Module 0x2::package
Functions for operating on Move packages from within Move:
-
Creating proof-of-publish objects from one-time witnesses
-
Administering package upgrades through upgrade policies.
use 0x1::ascii;
use 0x1::type_name;
use 0x2::object;
use 0x2::transfer;
use 0x2::tx_context;
use 0x2::types;
Resource Publisher
This type can only be created in the transaction that generates a module, by consuming its one-time witness, so it can be used to identify the address that published the package a type originated from.
struct Publisher has store, key
Fields
id: object::UID
package: ascii::String
module_name: ascii::String
Resource UpgradeCap
Capability controlling the ability to upgrade a package.
struct UpgradeCap has store, key
Fields
id: object::UID
package: object::ID
(Mutable) ID of the package that can be upgraded.
version: u64
(Mutable) The number of upgrades that have been applied successively to the original package. Initially 0.
policy: u8
What kind of upgrades are allowed.
Struct UpgradeTicket
Permission to perform a particular upgrade (for a fixed version of the package, bytecode to upgrade with and transitive dependencies to depend against).
An UpgradeCap
can only issue one ticket at a time, to prevent races
between concurrent updates or a change in its upgrade policy after
issuing a ticket, so the ticket is a "Hot Potato" to preserve forward
progress.
structUpgradeTicket
Fields
cap: object::ID
(Immutable) ID of the
UpgradeCap
this originated from.package: object::ID
(Immutable) ID of the package that can be upgraded.
policy: u8
(Immutable) The policy regarding what kind of upgrade this ticket permits.
digest: vector<u8>
(Immutable) SHA256 digest of the bytecode and transitive dependencies that will be used in the upgrade.
Struct UpgradeReceipt
Issued as a result of a successful upgrade, containing the
information to be used to update the UpgradeCap
. This is a "Hot
Potato" to ensure that it is used to update its UpgradeCap
before
the end of the transaction that performed the upgrade.
structUpgradeReceipt
Fields
cap: object::ID
(Immutable) ID of the
UpgradeCap
this originated from.package: object::ID
(Immutable) ID of the package after it was upgraded.
Constants
Add new functions or types, or change dependencies, existing functions can't change.
const ADDITIVE: u8 = 128;
Update any part of the package (function implementations, add new functions or types, change dependencies)
const COMPATIBLE: u8 = 0;
Only be able to change dependencies.
const DEP_ONLY: u8 = 192;
This UpgradeCap
has already authorized a pending upgrade.
const EAlreadyAuthorized: u64 = 2;
This UpgradeCap
has not authorized an upgrade.
const ENotAuthorized: u64 = 3;
Tried to create a Publisher
using a type that isn't a
one-time witness.
const ENotOneTimeWitness: u64 = 0;
Tried to set a less restrictive policy than currently in place.
const ETooPermissive: u64 = 1;
Trying to commit an upgrade to the wrong UpgradeCap
.
const EWrongUpgradeCap: u64 = 4;
Function claim
Claim a Publisher object. Requires a One-Time-Witness to prove ownership. Due to this constraint there can be only one Publisher object per module but multiple per package (!).
public fun claim<OTW: drop>(otw: OTW, ctx: &mut tx_context::TxContext): package::Publisher
Implementation
public fun claim<OTW: drop>(otw: OTW, ctx: &mut TxContext): Publisher {
assert!(types::is_one_time_witness(&otw), ENotOneTimeWitness);
let tyname = type_name::get_with_original_ids<OTW>();
Publisher {
id: object::new(ctx),
package: tyname.get_address(),
module_name: tyname.get_module(),
}
}
Function claim_and_keep
Claim a Publisher object and send it to transaction sender. Since this function can only be called in the module initializer, the sender is the publisher.
public fun claim_and_keep<OTW: drop>(otw: OTW, ctx: &mut tx_context::TxContext)
Implementation
public fun claim_and_keep<OTW: drop>(otw: OTW, ctx: &mut TxContext) {
iota::transfer::public_transfer(claim(otw, ctx), ctx.sender())
}
Function burn_publisher
Destroy a Publisher object effectively removing all privileges associated with it.
public fun burn_publisher(self: package::Publisher)
Implementation
public fun burn_publisher(self: Publisher) {
let Publisher { id, package: _, module_name: _ } = self;
id.delete();
}
Function from_package
Check whether type belongs to the same package as the publisher object.
public fun from_package<T>(self: &package::Publisher): bool
Implementation
public fun from_package<T>(self: &Publisher): bool {
type_name::get_with_original_ids<T>().get_address() == self.package
}
Function from_module
Check whether a type belongs to the same module as the publisher object.
public fun from_module<T>(self: &package::Publisher): bool
Implementation
public fun from_module<T>(self: &Publisher): bool {
let tyname = type_name::get_with_original_ids<T>();
(tyname.get_address() == self.package) && (tyname.get_module() == self.module_name)
}
Function published_module
Read the name of the module.
public fun published_module(self: &package::Publisher): &ascii::String
Implementation
public fun published_module(self: &Publisher): &String {
&self.module_name
}
Function published_package
Read the package address string.
public fun published_package(self: &package::Publisher): &ascii::String
Implementation
public fun published_package(self: &Publisher): &String {
&self.package
}
Function upgrade_package
The ID of the package that this cap authorizes upgrades for.
Can be 0x0
if the cap cannot currently authorize an upgrade
because there is already a pending upgrade in the transaction.
Otherwise guaranteed to be the latest version of any given
package.
public fun upgrade_package(cap: &package::UpgradeCap): object::ID
Implementation
public fun upgrade_package(cap: &UpgradeCap): ID {
cap.package
}
Function version
The most recent version of the package, increments by one for each successfully applied upgrade.
public fun version(cap: &package::UpgradeCap): u64
Implementation
public fun version(cap: &UpgradeCap): u64 {
cap.version
}
Function upgrade_policy
The most permissive kind of upgrade currently supported by this
cap
.
public fun upgrade_policy(cap: &package::UpgradeCap): u8
Implementation
public fun upgrade_policy(cap: &UpgradeCap): u8 {
cap.policy
}
Function ticket_package
The package that this ticket is authorized to upgrade
public fun ticket_package(ticket: &package::UpgradeTicket): object::ID
Implementation
public fun ticket_package(ticket: &UpgradeTicket): ID {
ticket.package
}
Function ticket_policy
The kind of upgrade that this ticket authorizes.
public fun ticket_policy(ticket: &package::UpgradeTicket): u8
Implementation
public fun ticket_policy(ticket: &UpgradeTicket): u8 {
ticket.policy
}
Function receipt_cap
ID of the UpgradeCap
that this receipt
should be used to
update.
public fun receipt_cap(receipt: &package::UpgradeReceipt): object::ID
Implementation
public fun receipt_cap(receipt: &UpgradeReceipt): ID {
receipt.cap
}
Function receipt_package
ID of the package that was upgraded to: the latest version of
the package, as of the upgrade represented by this receipt
.
public fun receipt_package(receipt: &package::UpgradeReceipt): object::ID
Implementation
public fun receipt_package(receipt: &UpgradeReceipt): ID {
receipt.package
}
Function ticket_digest
A hash of the package contents for the new version of the package. This ticket only authorizes an upgrade to a package that matches this digest. A package's contents are identified by two things:
- modules: [[u8]] a list of the package's module contents
- deps: [[u8; 32]] a list of 32 byte ObjectIDs of the package's transitive dependencies
A package's digest is calculated as:
sha3_256(sort(modules ++ deps))
public fun ticket_digest(ticket: &package::UpgradeTicket): &vector<u8>
Implementation
public fun ticket_digest(ticket: &UpgradeTicket): &vector<u8> {
&ticket.digest
}
Function compatible_policy
Expose the constants representing various upgrade policies
public fun compatible_policy(): u8
Implementation
public fun compatible_policy(): u8 { COMPATIBLE }
Function additive_policy
public fun additive_policy(): u8
Implementation
public fun additive_policy(): u8 { ADDITIVE }
Function dep_only_policy
public fun dep_only_policy(): u8
Implementation
public fun dep_only_policy(): u8 { DEP_ONLY }
Function only_additive_upgrades
Restrict upgrades through this upgrade cap
to just add code, or
change dependencies.
public entry fun only_additive_upgrades(cap: &mut package::UpgradeCap)
Implementation
public entry fun only_additive_upgrades(cap: &mut UpgradeCap) {
cap.restrict(ADDITIVE)
}
Function only_dep_upgrades
Restrict upgrades through this upgrade cap
to just change
dependencies.
public entry fun only_dep_upgrades(cap: &mut package::UpgradeCap)
Implementation
public entry fun only_dep_upgrades(cap: &mut UpgradeCap) {
cap.restrict(DEP_ONLY)
}
Function make_immutable
Discard the UpgradeCap
to make a package immutable.
public entry fun make_immutable(cap: package::UpgradeCap)
Implementation
public entry fun make_immutable(cap: UpgradeCap) {
let UpgradeCap { id, package: _, version: _, policy: _ } = cap;
id.delete();
}
Function authorize_upgrade
Issue a ticket authorizing an upgrade to a particular new bytecode
(identified by its digest). A ticket will only be issued if one has
not already been issued, and if the policy
requested is at least as
restrictive as the policy set out by the cap
.
The digest
supplied and the policy
will both be checked by
validators when running the upgrade. I.e. the bytecode supplied in
the upgrade must have a matching digest, and the changes relative to
the parent package must be compatible with the policy in the ticket
for the upgrade to succeed.
public fun authorize_upgrade(cap: &mut package::UpgradeCap, policy: u8, digest: vector<u8>): package::UpgradeTicket
Implementation
public fun authorize_upgrade(
cap: &mut UpgradeCap,
policy: u8,
digest: vector<u8>
): UpgradeTicket {
let id_zero = @0x0.to_id();
assert!(cap.package != id_zero, EAlreadyAuthorized);
assert!(policy >= cap.policy, ETooPermissive);
let package = cap.package;
cap.package = id_zero;
UpgradeTicket {
cap: object::id(cap),
package,
policy,
digest,
}
}
Function commit_upgrade
Consume an UpgradeReceipt
to update its UpgradeCap
, finalizing
the upgrade.
public fun commit_upgrade(cap: &mut package::UpgradeCap, receipt: package::UpgradeReceipt)
Implementation
public fun commit_upgrade(
cap: &mut UpgradeCap,
receipt: UpgradeReceipt,
) {
let UpgradeReceipt { cap: cap_id, package } = receipt;
assert!(object::id(cap) == cap_id, EWrongUpgradeCap);
assert!(cap.package.to_address() == @0x0, ENotAuthorized);
Function restrict
fun restrict(cap: &mut package::UpgradeCap, policy: u8)
Implementation
fun restrict(cap: &mut UpgradeCap, policy: u8) {
assert!(cap.policy <= policy, ETooPermissive);
cap.policy = policy;
}