From 7336840e36b9cdc2aebf59467d3b05ac125ebf3a Mon Sep 17 00:00:00 2001 From: Damir Shamanaev Date: Tue, 24 Sep 2024 01:53:14 +0300 Subject: [PATCH] [framework] Formatting: utils, object, tx_context, types, random 5/N (#19498) ## Description Continues the formatting. ## Test plan Tests must pass, framework must be compatible. --- ## Release notes Check each box that your changes affect. If none of the boxes relate to your changes, release notes aren't required. For each box you select, include information after the relevant heading that describes the impact of your changes that a user might notice and any actions they must take to implement updates. - [ ] Protocol: - [ ] Nodes (Validators and Full nodes): - [ ] Indexer: - [ ] JSON-RPC: - [ ] GraphQL: - [ ] CLI: - [ ] Rust SDK: - [ ] REST API: --- .../docs/sui-framework/authenticator_state.md | 22 +- .../docs/sui-framework/borrow.md | 13 +- .../sui-framework/docs/sui-framework/clock.md | 6 +- .../docs/sui-framework/display.md | 25 +- .../sui-framework/docs/sui-framework/hex.md | 6 +- .../sui-framework/docs/sui-framework/math.md | 2 +- .../docs/sui-framework/object.md | 10 +- .../docs/sui-framework/package.md | 11 +- .../sui-framework/docs/sui-framework/pay.md | 17 +- .../docs/sui-framework/random.md | 14 +- .../docs/sui-framework/tx_context.md | 2 +- .../sui-framework/docs/sui-framework/url.md | 2 +- .../docs/sui-framework/versioned.md | 9 +- .../sui-framework/sources/address.move | 162 ++--- .../sources/authenticator_state.move | 660 +++++++++--------- .../packages/sui-framework/sources/bcs.move | 466 ++++++------- .../sui-framework/sources/borrow.move | 170 ++--- .../packages/sui-framework/sources/clock.move | 143 ++-- .../sui-framework/sources/display.move | 340 ++++----- .../packages/sui-framework/sources/event.move | 34 +- .../packages/sui-framework/sources/hex.move | 152 ++-- .../packages/sui-framework/sources/math.move | 71 +- .../sui-framework/sources/object.move | 355 +++++----- .../sui-framework/sources/package.move | 620 ++++++++-------- .../packages/sui-framework/sources/pay.move | 138 ++-- .../sui-framework/sources/prover.move | 3 +- .../sui-framework/sources/random.move | 633 +++++++++-------- .../sui-framework/sources/tx_context.move | 275 ++++---- .../packages/sui-framework/sources/types.move | 12 +- .../packages/sui-framework/sources/url.move | 50 +- .../sui-framework/sources/versioned.move | 143 ++-- .../sui-framework/tests/display_tests.move | 39 ++ .../sui-framework/tests/hex_tests.move | 62 ++ 33 files changed, 2329 insertions(+), 2338 deletions(-) create mode 100644 crates/sui-framework/packages/sui-framework/tests/display_tests.move create mode 100644 crates/sui-framework/packages/sui-framework/tests/hex_tests.move diff --git a/crates/sui-framework/docs/sui-framework/authenticator_state.md b/crates/sui-framework/docs/sui-framework/authenticator_state.md index 93d44e078b5d6..fe4f48e3a07de 100644 --- a/crates/sui-framework/docs/sui-framework/authenticator_state.md +++ b/crates/sui-framework/docs/sui-framework/authenticator_state.md @@ -308,9 +308,9 @@ Sender is not @0x0 the system address.
fun jwk_equal(a: &JWK, b: &JWK): bool {
     (&a.kty == &b.kty) &&
-       (&a.e == &b.e) &&
-       (&a.n == &b.n) &&
-       (&a.alg == &b.alg)
+           (&a.e == &b.e) &&
+           (&a.n == &b.n) &&
+           (&a.alg == &b.alg)
 }
 
@@ -484,9 +484,7 @@ Can only be called by genesis or change_epoch transactions. Implementation -
fun load_inner_mut(
-    self: &mut AuthenticatorState,
-): &mut AuthenticatorStateInner {
+
fun load_inner_mut(self: &mut AuthenticatorState): &mut AuthenticatorStateInner {
     let version = self.version;
 
     // replace this with a lazy update function when we add a new version of the inner object.
@@ -518,9 +516,7 @@ Can only be called by genesis or change_epoch transactions.
 Implementation
 
 
-
fun load_inner(
-    self: &AuthenticatorState,
-): &AuthenticatorStateInner {
+
fun load_inner(self: &AuthenticatorState): &AuthenticatorStateInner {
     let version = self.version;
 
     // replace this with a lazy update function when we add a new version of the inner object.
@@ -709,7 +705,8 @@ indicate that the JWK has been validated in the current epoch and should not be
     self: &mut AuthenticatorState,
     // any jwk below this epoch is not retained
     min_epoch: u64,
-    ctx: &TxContext) {
+    ctx: &TxContext,
+) {
     // This will only be called by sui_system::advance_epoch
     assert!(ctx.sender() == @0x0, ENotSystemAddress);
 
@@ -793,10 +790,7 @@ JWK state from the chain.
 Implementation
 
 
-
fun get_active_jwks(
-    self: &AuthenticatorState,
-    ctx: &TxContext,
-): vector<ActiveJwk> {
+
fun get_active_jwks(self: &AuthenticatorState, ctx: &TxContext): vector<ActiveJwk> {
     assert!(ctx.sender() == @0x0, ENotSystemAddress);
     self.load_inner().active_jwks
 }
diff --git a/crates/sui-framework/docs/sui-framework/borrow.md b/crates/sui-framework/docs/sui-framework/borrow.md
index 0fe949d035fb0..c9af348f4c10c 100644
--- a/crates/sui-framework/docs/sui-framework/borrow.md
+++ b/crates/sui-framework/docs/sui-framework/borrow.md
@@ -137,7 +137,7 @@ Create a new Referent s
 
public fun new<T: key + store>(value: T, ctx: &mut TxContext): Referent<T> {
     Referent {
         id: tx_context::fresh_object_address(ctx),
-        value: option::some(value)
+        value: option::some(value),
     }
 }
 
@@ -167,10 +167,13 @@ hot potato. let value = self.value.extract(); let id = object::id(&value); - (value, Borrow { - ref: self.id, - obj: id - }) + ( + value, + Borrow { + ref: self.id, + obj: id, + }, + ) }
diff --git a/crates/sui-framework/docs/sui-framework/clock.md b/crates/sui-framework/docs/sui-framework/clock.md index 4093c882c71ad..3919d8837f026 100644 --- a/crates/sui-framework/docs/sui-framework/clock.md +++ b/crates/sui-framework/docs/sui-framework/clock.md @@ -154,11 +154,7 @@ called exactly once, during genesis. Implementation -
fun consensus_commit_prologue(
-    clock: &mut Clock,
-    timestamp_ms: u64,
-    ctx: &TxContext,
-) {
+
fun consensus_commit_prologue(clock: &mut Clock, timestamp_ms: u64, ctx: &TxContext) {
     // Validator will make a special system call with sender set as 0x0.
     assert!(ctx.sender() == @0x0, ENotSystemAddress);
 
diff --git a/crates/sui-framework/docs/sui-framework/display.md b/crates/sui-framework/docs/sui-framework/display.md
index 3d085df973e54..e56a69e0d080f 100644
--- a/crates/sui-framework/docs/sui-framework/display.md
+++ b/crates/sui-framework/docs/sui-framework/display.md
@@ -247,7 +247,10 @@ Create a new Display object with a set of fields.
 
 
 
public fun new_with_fields<T: key>(
-    pub: &Publisher, fields: vector<String>, values: vector<String>, ctx: &mut TxContext
+    pub: &Publisher,
+    fields: vector<String>,
+    values: vector<String>,
+    ctx: &mut TxContext,
 ): Display<T> {
     let len = fields.length();
     assert!(len == values.length(), EVecLengthMismatch);
@@ -283,7 +286,7 @@ Create a new empty Display object and keep it.
 Implementation
 
 
-
entry public fun create_and_keep<T: key>(pub: &Publisher, ctx: &mut TxContext) {
+
public entry fun create_and_keep<T: key>(pub: &Publisher, ctx: &mut TxContext) {
     transfer::public_transfer(new<T>(pub, ctx), ctx.sender())
 }
 
@@ -308,9 +311,7 @@ Manually bump the version and emit an event with the updated version's contents. Implementation -
entry public fun update_version<T: key>(
-    display: &mut Display<T>
-) {
+
public entry fun update_version<T: key>(display: &mut Display<T>) {
     display.version = display.version + 1;
     event::emit(VersionUpdated<T> {
         version: display.version,
@@ -340,7 +341,7 @@ Sets a custom name field with the value.
 Implementation
 
 
-
entry public fun add<T: key>(self: &mut Display<T>, name: String, value: String) {
+
public entry fun add<T: key>(self: &mut Display<T>, name: String, value: String) {
     self.add_internal(name, value)
 }
 
@@ -365,8 +366,10 @@ Sets multiple fields with values. Implementation -
entry public fun add_multiple<T: key>(
-    self: &mut Display<T>, fields: vector<String>, values: vector<String>
+
public entry fun add_multiple<T: key>(
+    self: &mut Display<T>,
+    fields: vector<String>,
+    values: vector<String>,
 ) {
     let len = fields.length();
     assert!(len == values.length(), EVecLengthMismatch);
@@ -400,7 +403,7 @@ TODO (long run): version changes;
 Implementation
 
 
-
entry public fun edit<T: key>(self: &mut Display<T>, name: String, value: String) {
+
public entry fun edit<T: key>(self: &mut Display<T>, name: String, value: String) {
     let (_, _) = self.fields.remove(&name);
     self.add_internal(name, value)
 }
@@ -426,7 +429,7 @@ Remove the key from the Display.
 Implementation
 
 
-
entry public fun remove<T: key>(self: &mut Display<T>, name: String) {
+
public entry fun remove<T: key>(self: &mut Display<T>, name: String) {
     self.fields.remove(&name);
 }
 
@@ -530,7 +533,7 @@ Internal function to create a new let uid = object::new(ctx); event::emit(DisplayCreated<T> { - id: uid.to_inner() + id: uid.to_inner(), }); Display { diff --git a/crates/sui-framework/docs/sui-framework/hex.md b/crates/sui-framework/docs/sui-framework/hex.md index 5a835de9a6314..c7844eb46f877 100644 --- a/crates/sui-framework/docs/sui-framework/hex.md +++ b/crates/sui-framework/docs/sui-framework/hex.md @@ -133,11 +133,11 @@ Aborts if the hex string contains non-valid hex characters (valid characters are
fun decode_byte(hex: u8): u8 {
-    if (/* 0 .. 9 */ 48 <= hex && hex < 58) {
+    if (48 <= hex && hex < 58) {
         hex - 48
-    } else if (/* A .. F */ 65 <= hex && hex < 71) {
+    } else if (65 <= hex && hex < 71) {
         10 + hex - 65
-    } else if (/* a .. f */ 97 <= hex && hex < 103) {
+    } else if (97 <= hex && hex < 103) {
         10 + hex - 97
     } else {
         abort ENotValidHexCharacter
diff --git a/crates/sui-framework/docs/sui-framework/math.md b/crates/sui-framework/docs/sui-framework/math.md
index d138083a64689..be044025e9ba1 100644
--- a/crates/sui-framework/docs/sui-framework/math.md
+++ b/crates/sui-framework/docs/sui-framework/math.md
@@ -162,7 +162,7 @@ DEPRECATED, use std::u128::sqrt instead
 
 
 
public fun sqrt_u128(x: u128): u128 {
-   x.sqrt()
+    x.sqrt()
 }
 
diff --git a/crates/sui-framework/docs/sui-framework/object.md b/crates/sui-framework/docs/sui-framework/object.md index 8e7a390ad700e..020d715c11e82 100644 --- a/crates/sui-framework/docs/sui-framework/object.md +++ b/crates/sui-framework/docs/sui-framework/object.md @@ -330,7 +330,7 @@ This should only be called once from clock(): UID { UID { - id: ID { bytes: SUI_CLOCK_OBJECT_ID } + id: ID { bytes: SUI_CLOCK_OBJECT_ID }, } }
@@ -358,7 +358,7 @@ This should only be called once from authenticator_state(): UID { UID { - id: ID { bytes: SUI_AUTHENTICATOR_STATE_ID } + id: ID { bytes: SUI_AUTHENTICATOR_STATE_ID }, } }
@@ -386,7 +386,7 @@ This should only be called once from randomness_state(): UID { UID { - id: ID { bytes: SUI_RANDOM_ID } + id: ID { bytes: SUI_RANDOM_ID }, } }
@@ -414,7 +414,7 @@ This should only be called once from sui_deny_list_object_id(): UID { UID { - id: ID { bytes: SUI_DENY_LIST_OBJECT_ID } + id: ID { bytes: SUI_DENY_LIST_OBJECT_ID }, } }
@@ -442,7 +442,7 @@ This should only be called once from bridge.
fun bridge(): UID {
     UID {
-        id: ID { bytes: SUI_BRIDGE_ID }
+        id: ID { bytes: SUI_BRIDGE_ID },
     }
 }
 
diff --git a/crates/sui-framework/docs/sui-framework/package.md b/crates/sui-framework/docs/sui-framework/package.md index a2c043014e433..b718af007cc98 100644 --- a/crates/sui-framework/docs/sui-framework/package.md +++ b/crates/sui-framework/docs/sui-framework/package.md @@ -899,11 +899,7 @@ for the upgrade to succeed. Implementation -
public fun authorize_upgrade(
-    cap: &mut UpgradeCap,
-    policy: u8,
-    digest: vector<u8>
-): UpgradeTicket {
+
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);
@@ -941,10 +937,7 @@ the upgrade.
 Implementation
 
 
-
public fun commit_upgrade(
-    cap: &mut UpgradeCap,
-    receipt: UpgradeReceipt,
-) {
+
public fun commit_upgrade(cap: &mut UpgradeCap, receipt: UpgradeReceipt) {
     let UpgradeReceipt { cap: cap_id, package } = receipt;
 
     assert!(object::id(cap) == cap_id, EWrongUpgradeCap);
diff --git a/crates/sui-framework/docs/sui-framework/pay.md b/crates/sui-framework/docs/sui-framework/pay.md
index 7abd57b9fe2ed..84b2a29a92726 100644
--- a/crates/sui-framework/docs/sui-framework/pay.md
+++ b/crates/sui-framework/docs/sui-framework/pay.md
@@ -80,9 +80,7 @@ and the remaining balance is left is self.
 Implementation
 
 
-
public entry fun split<T>(
-    coin: &mut Coin<T>, split_amount: u64, ctx: &mut TxContext
-) {
+
public entry fun split<T>(coin: &mut Coin<T>, split_amount: u64, ctx: &mut TxContext) {
     keep(coin.split(split_amount, ctx), ctx)
 }
 
@@ -108,9 +106,7 @@ in split_amounts. Remaining balance is left in self. Implementation -
public entry fun split_vec<T>(
-    self: &mut Coin<T>, split_amounts: vector<u64>, ctx: &mut TxContext
-) {
+
public entry fun split_vec<T>(self: &mut Coin<T>, split_amounts: vector<u64>, ctx: &mut TxContext) {
     let (mut i, len) = (0, split_amounts.length());
     while (i < len) {
         split(self, split_amounts[i], ctx);
@@ -141,7 +137,10 @@ Aborts with EVALUE if amount is greater than or equal
 
 
 
public entry fun split_and_transfer<T>(
-    c: &mut Coin<T>, amount: u64, recipient: address, ctx: &mut TxContext
+    c: &mut Coin<T>,
+    amount: u64,
+    recipient: address,
+    ctx: &mut TxContext,
 ) {
     transfer::public_transfer(c.split(amount, ctx), recipient)
 }
@@ -168,9 +167,7 @@ not evenly divisible by n, the remainder is left in selfImplementation
 
 
-
public entry fun divide_and_keep<T>(
-    self: &mut Coin<T>, n: u64, ctx: &mut TxContext
-) {
+
public entry fun divide_and_keep<T>(self: &mut Coin<T>, n: u64, ctx: &mut TxContext) {
     let mut vec: vector<Coin<T>> = self.divide_into_n(n, ctx);
     let (mut i, len) = (0, vec.length());
     while (i < len) {
diff --git a/crates/sui-framework/docs/sui-framework/random.md b/crates/sui-framework/docs/sui-framework/random.md
index 27837f0a1cf5c..a685e78d198b9 100644
--- a/crates/sui-framework/docs/sui-framework/random.md
+++ b/crates/sui-framework/docs/sui-framework/random.md
@@ -300,9 +300,7 @@ Can only be called by genesis or change_epoch transactions.
 Implementation
 
 
-
fun load_inner_mut(
-    self: &mut Random,
-): &mut RandomInner {
+
fun load_inner_mut(self: &mut Random): &mut RandomInner {
     let version = versioned::version(&self.inner);
 
     // Replace this with a lazy update function when we add a new version of the inner object.
@@ -332,9 +330,7 @@ Can only be called by genesis or change_epoch transactions.
 Implementation
 
 
-
fun load_inner(
-    self: &Random,
-): &RandomInner {
+
fun load_inner(self: &Random): &RandomInner {
     let version = versioned::version(&self.inner);
 
     // Replace this with a lazy update function when we add a new version of the inner object.
@@ -387,8 +383,8 @@ transaction.
         // randomness ever being generated in that epoch.
         assert!(
             (epoch > inner.epoch && new_round == 0) ||
-                (new_round == inner.randomness_round + 1),
-            EInvalidRandomnessUpdate
+                    (new_round == inner.randomness_round + 1),
+            EInvalidRandomnessUpdate,
         );
     };
 
@@ -422,7 +418,7 @@ Create a generator. Can be used to derive up to MAX_U16 * 32 random bytes.
     let inner = load_inner(r);
     let seed = hmac_sha3_256(
         &inner.random_bytes,
-        &ctx.fresh_object_address().to_bytes()
+        &ctx.fresh_object_address().to_bytes(),
     );
     RandomGenerator { seed, counter: 0, buffer: vector[] }
 }
diff --git a/crates/sui-framework/docs/sui-framework/tx_context.md b/crates/sui-framework/docs/sui-framework/tx_context.md
index 97e1840b5aed6..380f047c58eeb 100644
--- a/crates/sui-framework/docs/sui-framework/tx_context.md
+++ b/crates/sui-framework/docs/sui-framework/tx_context.md
@@ -167,7 +167,7 @@ Return the epoch start time as a unix timestamp in milliseconds.
 
 
 
public fun epoch_timestamp_ms(self: &TxContext): u64 {
-   self.epoch_timestamp_ms
+    self.epoch_timestamp_ms
 }
 
diff --git a/crates/sui-framework/docs/sui-framework/url.md b/crates/sui-framework/docs/sui-framework/url.md index e0e2204219292..6129f0f7d229c 100644 --- a/crates/sui-framework/docs/sui-framework/url.md +++ b/crates/sui-framework/docs/sui-framework/url.md @@ -113,7 +113,7 @@ Get inner URL Implementation -
public fun inner_url(self: &Url): String{
+
public fun inner_url(self: &Url): String {
     self.url
 }
 
diff --git a/crates/sui-framework/docs/sui-framework/versioned.md b/crates/sui-framework/docs/sui-framework/versioned.md index afc62e3e59a44..6a67a4a33f744 100644 --- a/crates/sui-framework/docs/sui-framework/versioned.md +++ b/crates/sui-framework/docs/sui-framework/versioned.md @@ -241,7 +241,7 @@ and must be used when we upgrade. VersionChangeCap { versioned_id: object::id(self), old_version: self.version, - } + }, ) }
@@ -267,7 +267,12 @@ by calling remove_value_for_upgrade. Implementation -
public fun upgrade<T: store>(self: &mut Versioned, new_version: u64, new_value: T, cap: VersionChangeCap) {
+
public fun upgrade<T: store>(
+    self: &mut Versioned,
+    new_version: u64,
+    new_value: T,
+    cap: VersionChangeCap,
+) {
     let VersionChangeCap { versioned_id, old_version } = cap;
     assert!(versioned_id == object::id(self), EInvalidUpgrade);
     assert!(old_version < new_version, EInvalidUpgrade);
diff --git a/crates/sui-framework/packages/sui-framework/sources/address.move b/crates/sui-framework/packages/sui-framework/sources/address.move
index 129908910df05..51d65d7b98b5a 100644
--- a/crates/sui-framework/packages/sui-framework/sources/address.move
+++ b/crates/sui-framework/packages/sui-framework/sources/address.move
@@ -2,85 +2,85 @@
 // SPDX-License-Identifier: Apache-2.0
 
 #[defines_primitive(address)]
-module sui::address {
-    use sui::hex;
-    use std::ascii;
-    use std::bcs;
-    use std::string;
-
-    /// Allows calling `.to_id()` on an address to get its `ID`.
-    public use fun sui::object::id_from_address as address.to_id;
-
-    /// The length of an address, in bytes
-    const LENGTH: u64 = 32;
-
-    // The largest integer that can be represented with 32 bytes: 2^(8*32) - 1
-    const MAX: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
-
-    #[allow(unused_const)]
-    /// Error from `from_bytes` when it is supplied too many or too few bytes.
-    const EAddressParseError: u64 = 0;
-
-    /// Convert `a` into a u256 by interpreting `a` as the bytes of a big-endian integer
-    /// (e.g., `to_u256(0x1) == 1`)
-    public native fun to_u256(a: address): u256;
-
-    /// Convert `n` into an address by encoding it as a big-endian integer (e.g., `from_u256(1) = @0x1`)
-    /// Aborts if `n` > `MAX_ADDRESS`
-    public native fun from_u256(n: u256): address;
-
-    /// Convert `bytes` into an address.
-    /// Aborts with `EAddressParseError` if the length of `bytes` is not 32
-    public native fun from_bytes(bytes: vector): address;
-
-    /// Convert `a` into BCS-encoded bytes.
-    public fun to_bytes(a: address): vector {
-        bcs::to_bytes(&a)
-    }
-
-    /// Convert `a` to a hex-encoded ASCII string
-    public fun to_ascii_string(a: address): ascii::String {
-        hex::encode(to_bytes(a)).to_ascii_string()
-    }
-
-    /// Convert `a` to a hex-encoded string
-    public fun to_string(a: address): string::String {
-        to_ascii_string(a).to_string()
-    }
-
-    /// Converts an ASCII string to an address, taking the numerical value for each character. The
-    /// string must be Base16 encoded, and thus exactly 64 characters long.
-    /// For example, the string "00000000000000000000000000000000000000000000000000000000DEADB33F"
-    /// will be converted to the address @0xDEADB33F.
-    /// Aborts with `EAddressParseError` if the length of `s` is not 64,
-    /// or if an invalid character is encountered.
-    public fun from_ascii_bytes(bytes: &vector): address {
-        assert!(bytes.length() == 64, EAddressParseError);
-        let mut hex_bytes = vector[];
-        let mut i = 0;
-        while (i < 64) {
-            let hi = hex_char_value(bytes[i]);
-            let lo = hex_char_value(bytes[i+1]);
-            hex_bytes.push_back((hi << 4) | lo);
-            i = i + 2;
-        };
-        from_bytes(hex_bytes)
-    }
-
-    fun hex_char_value(c: u8): u8 {
-        if (c >= 48 && c <= 57) c - 48 // 0-9
-        else if (c >= 65 && c <= 70) c - 55 // A-F
-        else if (c >= 97 && c <= 102) c - 87 // a-f
-        else abort EAddressParseError
-    }
-
-    /// Length of a Sui address in bytes
-    public fun length(): u64 {
-        LENGTH
-    }
-
-    /// Largest possible address
-    public fun max(): u256 {
-        MAX
-    }
+module sui::address;
+
+use std::ascii;
+use std::bcs;
+use std::string;
+use sui::hex;
+
+/// Allows calling `.to_id()` on an address to get its `ID`.
+public use fun sui::object::id_from_address as address.to_id;
+
+/// The length of an address, in bytes
+const LENGTH: u64 = 32;
+
+// The largest integer that can be represented with 32 bytes: 2^(8*32) - 1
+const MAX: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
+
+#[allow(unused_const)]
+/// Error from `from_bytes` when it is supplied too many or too few bytes.
+const EAddressParseError: u64 = 0;
+
+/// Convert `a` into a u256 by interpreting `a` as the bytes of a big-endian integer
+/// (e.g., `to_u256(0x1) == 1`)
+public native fun to_u256(a: address): u256;
+
+/// Convert `n` into an address by encoding it as a big-endian integer (e.g., `from_u256(1) = @0x1`)
+/// Aborts if `n` > `MAX_ADDRESS`
+public native fun from_u256(n: u256): address;
+
+/// Convert `bytes` into an address.
+/// Aborts with `EAddressParseError` if the length of `bytes` is not 32
+public native fun from_bytes(bytes: vector): address;
+
+/// Convert `a` into BCS-encoded bytes.
+public fun to_bytes(a: address): vector {
+    bcs::to_bytes(&a)
+}
+
+/// Convert `a` to a hex-encoded ASCII string
+public fun to_ascii_string(a: address): ascii::String {
+    hex::encode(to_bytes(a)).to_ascii_string()
+}
+
+/// Convert `a` to a hex-encoded string
+public fun to_string(a: address): string::String {
+    to_ascii_string(a).to_string()
+}
+
+/// Converts an ASCII string to an address, taking the numerical value for each character. The
+/// string must be Base16 encoded, and thus exactly 64 characters long.
+/// For example, the string "00000000000000000000000000000000000000000000000000000000DEADB33F"
+/// will be converted to the address @0xDEADB33F.
+/// Aborts with `EAddressParseError` if the length of `s` is not 64,
+/// or if an invalid character is encountered.
+public fun from_ascii_bytes(bytes: &vector): address {
+    assert!(bytes.length() == 64, EAddressParseError);
+    let mut hex_bytes = vector[];
+    let mut i = 0;
+    while (i < 64) {
+        let hi = hex_char_value(bytes[i]);
+        let lo = hex_char_value(bytes[i+1]);
+        hex_bytes.push_back((hi << 4) | lo);
+        i = i + 2;
+    };
+    from_bytes(hex_bytes)
+}
+
+fun hex_char_value(c: u8): u8 {
+    if (c >= 48 && c <= 57) c - 48 // 0-9
+    else if (c >= 65 && c <= 70) c - 55 // A-F
+    else if (c >= 97 && c <= 102) c - 87 // a-f
+    else abort EAddressParseError
+}
+
+/// Length of a Sui address in bytes
+public fun length(): u64 {
+    LENGTH
+}
+
+/// Largest possible address
+public fun max(): u256 {
+    MAX
 }
diff --git a/crates/sui-framework/packages/sui-framework/sources/authenticator_state.move b/crates/sui-framework/packages/sui-framework/sources/authenticator_state.move
index beca79feea46c..fb39f865ac071 100644
--- a/crates/sui-framework/packages/sui-framework/sources/authenticator_state.move
+++ b/crates/sui-framework/packages/sui-framework/sources/authenticator_state.move
@@ -7,389 +7,377 @@
 //
 // This module is not currently accessible from user contracts, and is used only to record the JWK
 // state to the chain for auditability + restore from snapshot purposes.
-module sui::authenticator_state {
-    use std::string;
-    use sui::dynamic_field;
-    use std::string::{String, utf8};
-
-    /// Sender is not @0x0 the system address.
-    const ENotSystemAddress: u64 = 0;
-    const EWrongInnerVersion: u64 = 1;
-    const EJwksNotSorted: u64 = 2;
-
-    const CurrentVersion: u64 = 1;
-
-    /// Singleton shared object which stores the global authenticator state.
-    /// The actual state is stored in a dynamic field of type AuthenticatorStateInner to support
-    /// future versions of the authenticator state.
-    public struct AuthenticatorState has key {
-        id: UID,
-        version: u64,
-    }
+module sui::authenticator_state;
 
-    public struct AuthenticatorStateInner has store {
-        version: u64,
+use std::string::{Self, String, utf8};
+use sui::dynamic_field;
 
-        /// List of currently active JWKs.
-        active_jwks: vector,
-    }
+/// Sender is not @0x0 the system address.
+const ENotSystemAddress: u64 = 0;
+const EWrongInnerVersion: u64 = 1;
+const EJwksNotSorted: u64 = 2;
 
-    #[allow(unused_field)]
-    /// Must match the JWK struct in fastcrypto-zkp
-    public struct JWK has store, drop, copy {
-        kty: String,
-        e: String,
-        n: String,
-        alg: String,
-    }
+const CurrentVersion: u64 = 1;
 
-    #[allow(unused_field)]
-    /// Must match the JwkId struct in fastcrypto-zkp
-    public struct JwkId has store, drop, copy {
-        iss: String,
-        kid: String,
-    }
+/// Singleton shared object which stores the global authenticator state.
+/// The actual state is stored in a dynamic field of type AuthenticatorStateInner to support
+/// future versions of the authenticator state.
+public struct AuthenticatorState has key {
+    id: UID,
+    version: u64,
+}
 
-    #[allow(unused_field)]
-    public struct ActiveJwk has store, drop, copy {
-        jwk_id: JwkId,
-        jwk: JWK,
-        epoch: u64,
-    }
+public struct AuthenticatorStateInner has store {
+    version: u64,
+    /// List of currently active JWKs.
+    active_jwks: vector,
+}
 
-    #[test_only]
-    public fun create_active_jwk(iss: String, kid: String, kty: String, epoch: u64): ActiveJwk {
-        ActiveJwk {
-            jwk_id: JwkId {
-                iss: iss,
-                kid: kid,
-            },
-            jwk: JWK {
-                kty: kty,
-                e: utf8(b"AQAB"),
-                n: utf8(b"test"),
-                alg: utf8(b"RS256"),
-            },
-            epoch,
-        }
-    }
+#[allow(unused_field)]
+/// Must match the JWK struct in fastcrypto-zkp
+public struct JWK has store, drop, copy {
+    kty: String,
+    e: String,
+    n: String,
+    alg: String,
+}
 
-    fun active_jwk_equal(a: &ActiveJwk, b: &ActiveJwk): bool {
-        // note: epoch is ignored
-        jwk_equal(&a.jwk, &b.jwk) && jwk_id_equal(&a.jwk_id, &b.jwk_id)
+#[allow(unused_field)]
+/// Must match the JwkId struct in fastcrypto-zkp
+public struct JwkId has store, drop, copy {
+    iss: String,
+    kid: String,
+}
+
+#[allow(unused_field)]
+public struct ActiveJwk has store, drop, copy {
+    jwk_id: JwkId,
+    jwk: JWK,
+    epoch: u64,
+}
+
+#[test_only]
+public fun create_active_jwk(iss: String, kid: String, kty: String, epoch: u64): ActiveJwk {
+    ActiveJwk {
+        jwk_id: JwkId {
+            iss: iss,
+            kid: kid,
+        },
+        jwk: JWK {
+            kty: kty,
+            e: utf8(b"AQAB"),
+            n: utf8(b"test"),
+            alg: utf8(b"RS256"),
+        },
+        epoch,
     }
+}
+
+fun active_jwk_equal(a: &ActiveJwk, b: &ActiveJwk): bool {
+    // note: epoch is ignored
+    jwk_equal(&a.jwk, &b.jwk) && jwk_id_equal(&a.jwk_id, &b.jwk_id)
+}
 
-    fun jwk_equal(a: &JWK, b: &JWK): bool {
-        (&a.kty == &b.kty) &&
+fun jwk_equal(a: &JWK, b: &JWK): bool {
+    (&a.kty == &b.kty) &&
            (&a.e == &b.e) &&
            (&a.n == &b.n) &&
            (&a.alg == &b.alg)
-    }
+}
 
-    fun jwk_id_equal(a: &JwkId, b: &JwkId): bool {
-        (&a.iss == &b.iss) && (&a.kid == &b.kid)
-    }
+fun jwk_id_equal(a: &JwkId, b: &JwkId): bool {
+    (&a.iss == &b.iss) && (&a.kid == &b.kid)
+}
 
-    // Compare the underlying byte arrays lexicographically. Since the strings may be utf8 this
-    // ordering is not necessarily the same as the string ordering, but we just need some
-    // canonical that is cheap to compute.
-    fun string_bytes_lt(a: &String, b: &String): bool {
-        let a_bytes = a.as_bytes();
-        let b_bytes = b.as_bytes();
-
-        if (a_bytes.length() < b_bytes.length()) {
-            true
-        } else if (a_bytes.length() > b_bytes.length()) {
-            false
-        } else {
-            let mut i = 0;
-            while (i < a_bytes.length()) {
-                let a_byte = a_bytes[i];
-                let b_byte = b_bytes[i];
-                if (a_byte < b_byte) {
-                    return true
-                } else if (a_byte > b_byte) {
-                    return false
-                };
-                i = i + 1;
+// Compare the underlying byte arrays lexicographically. Since the strings may be utf8 this
+// ordering is not necessarily the same as the string ordering, but we just need some
+// canonical that is cheap to compute.
+fun string_bytes_lt(a: &String, b: &String): bool {
+    let a_bytes = a.as_bytes();
+    let b_bytes = b.as_bytes();
+
+    if (a_bytes.length() < b_bytes.length()) {
+        true
+    } else if (a_bytes.length() > b_bytes.length()) {
+        false
+    } else {
+        let mut i = 0;
+        while (i < a_bytes.length()) {
+            let a_byte = a_bytes[i];
+            let b_byte = b_bytes[i];
+            if (a_byte < b_byte) {
+                return true
+            } else if (a_byte > b_byte) {
+                return false
             };
-            // all bytes are equal
-            false
-        }
-    }
-
-    fun jwk_lt(a: &ActiveJwk, b: &ActiveJwk): bool {
-        // note: epoch is ignored
-        if (&a.jwk_id.iss != &b.jwk_id.iss) {
-            return string_bytes_lt(&a.jwk_id.iss, &b.jwk_id.iss)
-        };
-        if (&a.jwk_id.kid != &b.jwk_id.kid) {
-            return string_bytes_lt(&a.jwk_id.kid, &b.jwk_id.kid)
-        };
-        if (&a.jwk.kty != &b.jwk.kty) {
-            return string_bytes_lt(&a.jwk.kty, &b.jwk.kty)
-        };
-        if (&a.jwk.e != &b.jwk.e) {
-            return string_bytes_lt(&a.jwk.e, &b.jwk.e)
-        };
-        if (&a.jwk.n != &b.jwk.n) {
-            return string_bytes_lt(&a.jwk.n, &b.jwk.n)
+            i = i + 1;
         };
-        string_bytes_lt(&a.jwk.alg, &b.jwk.alg)
+        // all bytes are equal
+        false
     }
+}
 
-    #[allow(unused_function)]
-    /// Create and share the AuthenticatorState object. This function is call exactly once, when
-    /// the authenticator state object is first created.
-    /// Can only be called by genesis or change_epoch transactions.
-    fun create(ctx: &TxContext) {
-        assert!(ctx.sender() == @0x0, ENotSystemAddress);
+fun jwk_lt(a: &ActiveJwk, b: &ActiveJwk): bool {
+    // note: epoch is ignored
+    if (&a.jwk_id.iss != &b.jwk_id.iss) {
+        return string_bytes_lt(&a.jwk_id.iss, &b.jwk_id.iss)
+    };
+    if (&a.jwk_id.kid != &b.jwk_id.kid) {
+        return string_bytes_lt(&a.jwk_id.kid, &b.jwk_id.kid)
+    };
+    if (&a.jwk.kty != &b.jwk.kty) {
+        return string_bytes_lt(&a.jwk.kty, &b.jwk.kty)
+    };
+    if (&a.jwk.e != &b.jwk.e) {
+        return string_bytes_lt(&a.jwk.e, &b.jwk.e)
+    };
+    if (&a.jwk.n != &b.jwk.n) {
+        return string_bytes_lt(&a.jwk.n, &b.jwk.n)
+    };
+    string_bytes_lt(&a.jwk.alg, &b.jwk.alg)
+}
 
-        let version = CurrentVersion;
+#[allow(unused_function)]
+/// Create and share the AuthenticatorState object. This function is call exactly once, when
+/// the authenticator state object is first created.
+/// Can only be called by genesis or change_epoch transactions.
+fun create(ctx: &TxContext) {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
 
-        let inner = AuthenticatorStateInner {
-            version,
-            active_jwks: vector[],
-        };
+    let version = CurrentVersion;
 
-        let mut self = AuthenticatorState {
-            id: object::authenticator_state(),
-            version,
-        };
+    let inner = AuthenticatorStateInner {
+        version,
+        active_jwks: vector[],
+    };
 
-        dynamic_field::add(&mut self.id, version, inner);
-        transfer::share_object(self);
-    }
+    let mut self = AuthenticatorState {
+        id: object::authenticator_state(),
+        version,
+    };
 
-    fun load_inner_mut(
-        self: &mut AuthenticatorState,
-    ): &mut AuthenticatorStateInner {
-        let version = self.version;
+    dynamic_field::add(&mut self.id, version, inner);
+    transfer::share_object(self);
+}
 
-        // replace this with a lazy update function when we add a new version of the inner object.
-        assert!(version == CurrentVersion, EWrongInnerVersion);
+fun load_inner_mut(self: &mut AuthenticatorState): &mut AuthenticatorStateInner {
+    let version = self.version;
 
-        let inner: &mut AuthenticatorStateInner = dynamic_field::borrow_mut(&mut self.id, self.version);
+    // replace this with a lazy update function when we add a new version of the inner object.
+    assert!(version == CurrentVersion, EWrongInnerVersion);
 
-        assert!(inner.version == version, EWrongInnerVersion);
-        inner
-    }
+    let inner: &mut AuthenticatorStateInner = dynamic_field::borrow_mut(&mut self.id, self.version);
 
-    fun load_inner(
-        self: &AuthenticatorState,
-    ): &AuthenticatorStateInner {
-        let version = self.version;
+    assert!(inner.version == version, EWrongInnerVersion);
+    inner
+}
 
-        // replace this with a lazy update function when we add a new version of the inner object.
-        assert!(version == CurrentVersion, EWrongInnerVersion);
+fun load_inner(self: &AuthenticatorState): &AuthenticatorStateInner {
+    let version = self.version;
 
-        let inner: &AuthenticatorStateInner = dynamic_field::borrow(&self.id, self.version);
+    // replace this with a lazy update function when we add a new version of the inner object.
+    assert!(version == CurrentVersion, EWrongInnerVersion);
 
-        assert!(inner.version == version, EWrongInnerVersion);
-        inner
-    }
+    let inner: &AuthenticatorStateInner = dynamic_field::borrow(&self.id, self.version);
 
-    fun check_sorted(new_active_jwks: &vector) {
-        let mut i = 0;
-        while (i < new_active_jwks.length() - 1) {
-            let a = &new_active_jwks[i];
-            let b = &new_active_jwks[i + 1];
-            assert!(jwk_lt(a, b), EJwksNotSorted);
-            i = i + 1;
-        };
-    }
+    assert!(inner.version == version, EWrongInnerVersion);
+    inner
+}
 
-    #[allow(unused_function)]
-    /// Record a new set of active_jwks. Called when executing the AuthenticatorStateUpdate system
-    /// transaction. The new input vector must be sorted and must not contain duplicates.
-    /// If a new JWK is already present, but with a previous epoch, then the epoch is updated to
-    /// indicate that the JWK has been validated in the current epoch and should not be expired.
-    fun update_authenticator_state(
-        self: &mut AuthenticatorState,
-        new_active_jwks: vector,
-        ctx: &TxContext,
-    ) {
-        // Validator will make a special system call with sender set as 0x0.
-        assert!(ctx.sender() == @0x0, ENotSystemAddress);
-
-        check_sorted(&new_active_jwks);
-        let new_active_jwks = deduplicate(new_active_jwks);
-
-        let inner = self.load_inner_mut();
-
-        let mut res = vector[];
-        let mut i = 0;
-        let mut j = 0;
-        let active_jwks_len = inner.active_jwks.length();
-        let new_active_jwks_len = new_active_jwks.length();
-
-        while (i < active_jwks_len && j < new_active_jwks_len) {
-            let old_jwk = &inner.active_jwks[i];
-            let new_jwk = &new_active_jwks[j];
-
-            // when they are equal, push only one, but use the max epoch of the two
-            if (active_jwk_equal(old_jwk, new_jwk)) {
-                let mut jwk = *old_jwk;
-                jwk.epoch = old_jwk.epoch.max(new_jwk.epoch);
-                res.push_back(jwk);
-                i = i + 1;
-                j = j + 1;
-            } else if (jwk_id_equal(&old_jwk.jwk_id, &new_jwk.jwk_id)) {
-                // if only jwk_id is equal, then the key has changed. Providers should not send
-                // JWKs like this, but if they do, we must ignore the new JWK to avoid having a
-                // liveness / forking issues
-                res.push_back(*old_jwk);
-                i = i + 1;
-                j = j + 1;
-            } else if (jwk_lt(old_jwk, new_jwk)) {
-                res.push_back(*old_jwk);
-                i = i + 1;
-            } else {
-                res.push_back(*new_jwk);
-                j = j + 1;
-            }
-        };
+fun check_sorted(new_active_jwks: &vector) {
+    let mut i = 0;
+    while (i < new_active_jwks.length() - 1) {
+        let a = &new_active_jwks[i];
+        let b = &new_active_jwks[i + 1];
+        assert!(jwk_lt(a, b), EJwksNotSorted);
+        i = i + 1;
+    };
+}
 
-        while (i < active_jwks_len) {
-            res.push_back(inner.active_jwks[i]);
+#[allow(unused_function)]
+/// Record a new set of active_jwks. Called when executing the AuthenticatorStateUpdate system
+/// transaction. The new input vector must be sorted and must not contain duplicates.
+/// If a new JWK is already present, but with a previous epoch, then the epoch is updated to
+/// indicate that the JWK has been validated in the current epoch and should not be expired.
+fun update_authenticator_state(
+    self: &mut AuthenticatorState,
+    new_active_jwks: vector,
+    ctx: &TxContext,
+) {
+    // Validator will make a special system call with sender set as 0x0.
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+    check_sorted(&new_active_jwks);
+    let new_active_jwks = deduplicate(new_active_jwks);
+
+    let inner = self.load_inner_mut();
+
+    let mut res = vector[];
+    let mut i = 0;
+    let mut j = 0;
+    let active_jwks_len = inner.active_jwks.length();
+    let new_active_jwks_len = new_active_jwks.length();
+
+    while (i < active_jwks_len && j < new_active_jwks_len) {
+        let old_jwk = &inner.active_jwks[i];
+        let new_jwk = &new_active_jwks[j];
+
+        // when they are equal, push only one, but use the max epoch of the two
+        if (active_jwk_equal(old_jwk, new_jwk)) {
+            let mut jwk = *old_jwk;
+            jwk.epoch = old_jwk.epoch.max(new_jwk.epoch);
+            res.push_back(jwk);
             i = i + 1;
-        };
-        while (j < new_active_jwks_len) {
-            res.push_back(new_active_jwks[j]);
             j = j + 1;
-        };
-
-        inner.active_jwks = res;
-    }
-
-    fun deduplicate(jwks: vector): vector {
-        let mut res = vector[];
-        let mut i = 0;
-        let mut prev: Option = option::none();
-        while (i < jwks.length()) {
-            let jwk = &jwks[i];
-            if (prev.is_none()) {
-                prev.fill(jwk.jwk_id);
-            } else if (jwk_id_equal(prev.borrow(), &jwk.jwk_id)) {
-                // skip duplicate jwks in input
-                i = i + 1;
-                continue
-            } else {
-                *prev.borrow_mut() = jwk.jwk_id;
-            };
-            res.push_back(*jwk);
+        } else if (jwk_id_equal(&old_jwk.jwk_id, &new_jwk.jwk_id)) {
+            // if only jwk_id is equal, then the key has changed. Providers should not send
+            // JWKs like this, but if they do, we must ignore the new JWK to avoid having a
+            // liveness / forking issues
+            res.push_back(*old_jwk);
             i = i + 1;
-        };
-        res
-    }
-
-    #[allow(unused_function)]
-    // Called directly by rust when constructing the ChangeEpoch transaction.
-    fun expire_jwks(
-        self: &mut AuthenticatorState,
-        // any jwk below this epoch is not retained
-        min_epoch: u64,
-        ctx: &TxContext) {
-        // This will only be called by sui_system::advance_epoch
-        assert!(ctx.sender() == @0x0, ENotSystemAddress);
-
-        let inner = load_inner_mut(self);
-
-        let len = inner.active_jwks.length();
-
-        // first we count how many jwks from each issuer are above the min_epoch
-        // and store the counts in a vector that parallels the (sorted) active_jwks vector
-        let mut issuer_max_epochs = vector[];
-        let mut i = 0;
-        let mut prev_issuer: Option = option::none();
+            j = j + 1;
+        } else if (jwk_lt(old_jwk, new_jwk)) {
+            res.push_back(*old_jwk);
+            i = i + 1;
+        } else {
+            res.push_back(*new_jwk);
+            j = j + 1;
+        }
+    };
+
+    while (i < active_jwks_len) {
+        res.push_back(inner.active_jwks[i]);
+        i = i + 1;
+    };
+    while (j < new_active_jwks_len) {
+        res.push_back(new_active_jwks[j]);
+        j = j + 1;
+    };
+
+    inner.active_jwks = res;
+}
 
-        while (i < len) {
-            let cur = &inner.active_jwks[i];
-            let cur_iss = &cur.jwk_id.iss;
-            if (prev_issuer.is_none()) {
-                prev_issuer.fill(*cur_iss);
-                issuer_max_epochs.push_back(cur.epoch);
-            } else {
-                if (cur_iss == prev_issuer.borrow()) {
-                    let back = issuer_max_epochs.length() - 1;
-                    let prev_max_epoch = &mut issuer_max_epochs[back];
-                    *prev_max_epoch = (*prev_max_epoch).max(cur.epoch);
-                } else {
-                    *prev_issuer.borrow_mut() = *cur_iss;
-                    issuer_max_epochs.push_back(cur.epoch);
-                }
-            };
+fun deduplicate(jwks: vector): vector {
+    let mut res = vector[];
+    let mut i = 0;
+    let mut prev: Option = option::none();
+    while (i < jwks.length()) {
+        let jwk = &jwks[i];
+        if (prev.is_none()) {
+            prev.fill(jwk.jwk_id);
+        } else if (jwk_id_equal(prev.borrow(), &jwk.jwk_id)) {
+            // skip duplicate jwks in input
             i = i + 1;
+            continue
+        } else {
+            *prev.borrow_mut() = jwk.jwk_id;
         };
+        res.push_back(*jwk);
+        i = i + 1;
+    };
+    res
+}
 
-        // Now, filter out any JWKs that are below the min_epoch, unless that issuer has no
-        // JWKs >= the min_epoch, in which case we keep all of them.
-        let mut new_active_jwks: vector = vector[];
-        let mut prev_issuer: Option = option::none();
-        let mut i = 0;
-        let mut j = 0;
-        while (i < len) {
-            let jwk = &inner.active_jwks[i];
-            let cur_iss = &jwk.jwk_id.iss;
-
-            if (prev_issuer.is_none()) {
-                prev_issuer.fill(*cur_iss);
-            } else if (cur_iss != prev_issuer.borrow()) {
+#[allow(unused_function)]
+// Called directly by rust when constructing the ChangeEpoch transaction.
+fun expire_jwks(
+    self: &mut AuthenticatorState,
+    // any jwk below this epoch is not retained
+    min_epoch: u64,
+    ctx: &TxContext,
+) {
+    // This will only be called by sui_system::advance_epoch
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+    let inner = load_inner_mut(self);
+
+    let len = inner.active_jwks.length();
+
+    // first we count how many jwks from each issuer are above the min_epoch
+    // and store the counts in a vector that parallels the (sorted) active_jwks vector
+    let mut issuer_max_epochs = vector[];
+    let mut i = 0;
+    let mut prev_issuer: Option = option::none();
+
+    while (i < len) {
+        let cur = &inner.active_jwks[i];
+        let cur_iss = &cur.jwk_id.iss;
+        if (prev_issuer.is_none()) {
+            prev_issuer.fill(*cur_iss);
+            issuer_max_epochs.push_back(cur.epoch);
+        } else {
+            if (cur_iss == prev_issuer.borrow()) {
+                let back = issuer_max_epochs.length() - 1;
+                let prev_max_epoch = &mut issuer_max_epochs[back];
+                *prev_max_epoch = (*prev_max_epoch).max(cur.epoch);
+            } else {
                 *prev_issuer.borrow_mut() = *cur_iss;
-                j = j + 1;
-            };
+                issuer_max_epochs.push_back(cur.epoch);
+            }
+        };
+        i = i + 1;
+    };
+
+    // Now, filter out any JWKs that are below the min_epoch, unless that issuer has no
+    // JWKs >= the min_epoch, in which case we keep all of them.
+    let mut new_active_jwks: vector = vector[];
+    let mut prev_issuer: Option = option::none();
+    let mut i = 0;
+    let mut j = 0;
+    while (i < len) {
+        let jwk = &inner.active_jwks[i];
+        let cur_iss = &jwk.jwk_id.iss;
+
+        if (prev_issuer.is_none()) {
+            prev_issuer.fill(*cur_iss);
+        } else if (cur_iss != prev_issuer.borrow()) {
+            *prev_issuer.borrow_mut() = *cur_iss;
+            j = j + 1;
+        };
 
-            let max_epoch_for_iss = &issuer_max_epochs[j];
+        let max_epoch_for_iss = &issuer_max_epochs[j];
 
-            // TODO: if the iss for this jwk has *no* jwks that meet the minimum epoch,
-            // then expire nothing.
-            if (*max_epoch_for_iss < min_epoch || jwk.epoch >= min_epoch) {
-                new_active_jwks.push_back(*jwk);
-            };
-            i = i + 1;
+        // TODO: if the iss for this jwk has *no* jwks that meet the minimum epoch,
+        // then expire nothing.
+        if (*max_epoch_for_iss < min_epoch || jwk.epoch >= min_epoch) {
+            new_active_jwks.push_back(*jwk);
         };
-        inner.active_jwks = new_active_jwks;
-    }
+        i = i + 1;
+    };
+    inner.active_jwks = new_active_jwks;
+}
 
-    #[allow(unused_function)]
-    /// Get the current active_jwks. Called when the node starts up in order to load the current
-    /// JWK state from the chain.
-    fun get_active_jwks(
-        self: &AuthenticatorState,
-        ctx: &TxContext,
-    ): vector {
-        assert!(ctx.sender() == @0x0, ENotSystemAddress);
-        self.load_inner().active_jwks
-    }
+#[allow(unused_function)]
+/// Get the current active_jwks. Called when the node starts up in order to load the current
+/// JWK state from the chain.
+fun get_active_jwks(self: &AuthenticatorState, ctx: &TxContext): vector {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+    self.load_inner().active_jwks
+}
 
-    #[test_only]
-    public fun create_for_testing(ctx: &TxContext) {
-        create(ctx);
-    }
+#[test_only]
+public fun create_for_testing(ctx: &TxContext) {
+    create(ctx);
+}
 
-    #[test_only]
-    public fun update_authenticator_state_for_testing(
-        self: &mut AuthenticatorState,
-        new_active_jwks: vector,
-        ctx: &TxContext,
-    ) {
-        self.update_authenticator_state(new_active_jwks, ctx);
-    }
+#[test_only]
+public fun update_authenticator_state_for_testing(
+    self: &mut AuthenticatorState,
+    new_active_jwks: vector,
+    ctx: &TxContext,
+) {
+    self.update_authenticator_state(new_active_jwks, ctx);
+}
 
-    #[test_only]
-    public fun expire_jwks_for_testing(
-        self: &mut AuthenticatorState,
-        min_epoch: u64,
-        ctx: &TxContext,
-    ) {
-        self.expire_jwks(min_epoch, ctx);
-    }
+#[test_only]
+public fun expire_jwks_for_testing(self: &mut AuthenticatorState, min_epoch: u64, ctx: &TxContext) {
+    self.expire_jwks(min_epoch, ctx);
+}
 
-    #[test_only]
-    public fun get_active_jwks_for_testing(
-        self: &AuthenticatorState,
-        ctx: &TxContext,
-    ): vector {
-        self.get_active_jwks(ctx)
-    }
+#[test_only]
+public fun get_active_jwks_for_testing(
+    self: &AuthenticatorState,
+    ctx: &TxContext,
+): vector {
+    self.get_active_jwks(ctx)
 }
diff --git a/crates/sui-framework/packages/sui-framework/sources/bcs.move b/crates/sui-framework/packages/sui-framework/sources/bcs.move
index 66ecb2b2e6b40..83f69cdc0c554 100644
--- a/crates/sui-framework/packages/sui-framework/sources/bcs.move
+++ b/crates/sui-framework/packages/sui-framework/sources/bcs.move
@@ -32,237 +32,237 @@
 ///     (u8_value, u64_value, leftovers)
 /// }
 /// ```
-module sui::bcs {
-    use sui::address;
-    use std::bcs;
-
-    /// For when bytes length is less than required for deserialization.
-    const EOutOfRange: u64 = 0;
-    /// For when the boolean value different than `0` or `1`.
-    const ENotBool: u64 = 1;
-    /// For when ULEB byte is out of range (or not found).
-    const ELenOutOfRange: u64 = 2;
-
-    /// A helper struct that saves resources on operations. For better
-    /// vector performance, it stores reversed bytes of the BCS and
-    /// enables use of `vector::pop_back`.
-    public struct BCS has store, copy, drop {
-        bytes: vector
-    }
-
-    /// Get BCS serialized bytes for any value.
-    /// Re-exports stdlib `bcs::to_bytes`.
-    public fun to_bytes(value: &T): vector {
-        bcs::to_bytes(value)
-    }
-
-    /// Creates a new instance of BCS wrapper that holds inversed
-    /// bytes for better performance.
-    public fun new(mut bytes: vector): BCS {
-        bytes.reverse();
-        BCS { bytes }
-    }
-
-    /// Unpack the `BCS` struct returning the leftover bytes.
-    /// Useful for passing the data further after partial deserialization.
-    public fun into_remainder_bytes(bcs: BCS): vector {
-        let BCS { mut bytes } = bcs;
-        bytes.reverse();
-        bytes
-    }
-
-    /// Read address from the bcs-serialized bytes.
-    public fun peel_address(bcs: &mut BCS): address {
-        assert!(bcs.bytes.length() >= address::length(), EOutOfRange);
-        let (mut addr_bytes, mut i) = (vector[], 0);
-        while (i < address::length()) {
-            addr_bytes.push_back(bcs.bytes.pop_back());
-            i = i + 1;
-        };
-        address::from_bytes(addr_bytes)
-    }
-
-    /// Read a `bool` value from bcs-serialized bytes.
-    public fun peel_bool(bcs: &mut BCS): bool {
-        let value = bcs.peel_u8();
-        if (value == 0) false
-        else if (value == 1) true
-        else abort ENotBool
-    }
-
-    /// Read `u8` value from bcs-serialized bytes.
-    public fun peel_u8(bcs: &mut BCS): u8 {
-        assert!(bcs.bytes.length() >= 1, EOutOfRange);
-        bcs.bytes.pop_back()
-    }
-
-    macro fun peel_num<$I, $T>($bcs: &mut BCS, $len: u64, $bits: $I): $T {
-        let bcs = $bcs;
-        assert!(bcs.bytes.length() >= $len, EOutOfRange);
-
-        let mut value: $T = 0;
-        let mut i: $I = 0;
-        let bits = $bits;
-        while (i < bits) {
-            let byte = bcs.bytes.pop_back() as $T;
-            value = value + (byte << (i as u8));
-            i = i + 8;
-        };
-
-        value
-    }
-
-    /// Read `u16` value from bcs-serialized bytes.
-    public fun peel_u16(bcs: &mut BCS): u16 {
-        bcs.peel_num!(2, 16u8)
-    }
-
-    /// Read `u32` value from bcs-serialized bytes.
-    public fun peel_u32(bcs: &mut BCS): u32 {
-        bcs.peel_num!(4, 32u8)
-    }
-
-    /// Read `u64` value from bcs-serialized bytes.
-    public fun peel_u64(bcs: &mut BCS): u64 {
-        bcs.peel_num!(8, 64u8)
-    }
-
-    /// Read `u128` value from bcs-serialized bytes.
-    public fun peel_u128(bcs: &mut BCS): u128 {
-        bcs.peel_num!(16, 128u8)
-    }
-
-    /// Read `u256` value from bcs-serialized bytes.
-    public fun peel_u256(bcs: &mut BCS): u256 {
-        bcs.peel_num!(32, 256u16)
-    }
-
-    // === Vector ===
-
-    /// Read ULEB bytes expecting a vector length. Result should
-    /// then be used to perform `peel_*` operation LEN times.
-    ///
-    /// In BCS `vector` length is implemented with ULEB128;
-    /// See more here: https://en.wikipedia.org/wiki/LEB128
-    public fun peel_vec_length(bcs: &mut BCS): u64 {
-        let (mut total, mut shift, mut len) = (0u64, 0, 0);
-        loop {
-            assert!(len <= 4, ELenOutOfRange);
-            let byte = bcs.bytes.pop_back() as u64;
-            len = len + 1;
-            total = total | ((byte & 0x7f) << shift);
-            if ((byte & 0x80) == 0) break;
-            shift = shift + 7;
-        };
-        total
-    }
-
-    /// Peel `vector<$T>` from serialized bytes, where `$peel: |&mut BCS| -> $T` gives the
-    /// functionality of peeling each value.
-    public macro fun peel_vec<$T>($bcs: &mut BCS, $peel: |&mut BCS| -> $T): vector<$T> {
-        let bcs = $bcs;
-        let len = bcs.peel_vec_length();
-        let mut i = 0;
-        let mut res = vector[];
-        while (i < len) {
-            res.push_back($peel(bcs));
-            i = i + 1;
-        };
-        res
-    }
-
-    /// Peel a vector of `address` from serialized bytes.
-    public fun peel_vec_address(bcs: &mut BCS): vector
{ - bcs.peel_vec!(|bcs| bcs.peel_address()) - } - - /// Peel a vector of `address` from serialized bytes. - public fun peel_vec_bool(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_bool()) - } - - /// Peel a vector of `u8` (eg string) from serialized bytes. - public fun peel_vec_u8(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_u8()) - } - - /// Peel a `vector>` (eg vec of string) from serialized bytes. - public fun peel_vec_vec_u8(bcs: &mut BCS): vector> { - bcs.peel_vec!(|bcs| bcs.peel_vec_u8()) - } - - /// Peel a vector of `u16` from serialized bytes. - public fun peel_vec_u16(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_u16()) - } - - /// Peel a vector of `u32` from serialized bytes. - public fun peel_vec_u32(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_u32()) - } - - /// Peel a vector of `u64` from serialized bytes. - public fun peel_vec_u64(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_u64()) - } - - /// Peel a vector of `u128` from serialized bytes. - public fun peel_vec_u128(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_u128()) - } - - /// Peel a vector of `u256` from serialized bytes. - public fun peel_vec_u256(bcs: &mut BCS): vector { - bcs.peel_vec!(|bcs| bcs.peel_u256()) - } - - // === Option === - - /// Peel `Option<$T>` from serialized bytes, where `$peel: |&mut BCS| -> $T` gives the - /// functionality of peeling the inner value. - public macro fun peel_option<$T>($bcs: &mut BCS, $peel: |&mut BCS| -> $T): Option<$T> { - let bcs = $bcs; - if (bcs.peel_bool())option::some($peel(bcs)) - else option::none() - } - - /// Peel `Option
` from serialized bytes. - public fun peel_option_address(bcs: &mut BCS): Option
{ - bcs.peel_option!(|bcs| bcs.peel_address()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_bool(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_bool()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u8(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_u8()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u16(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_u16()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u32(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_u32()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u64(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_u64()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u128(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_u128()) - } - - /// Peel `Option` from serialized bytes. - public fun peel_option_u256(bcs: &mut BCS): Option { - bcs.peel_option!(|bcs| bcs.peel_u256()) - } +module sui::bcs; + +use std::bcs; +use sui::address; + +/// For when bytes length is less than required for deserialization. +const EOutOfRange: u64 = 0; +/// For when the boolean value different than `0` or `1`. +const ENotBool: u64 = 1; +/// For when ULEB byte is out of range (or not found). +const ELenOutOfRange: u64 = 2; + +/// A helper struct that saves resources on operations. For better +/// vector performance, it stores reversed bytes of the BCS and +/// enables use of `vector::pop_back`. +public struct BCS has store, copy, drop { + bytes: vector, +} + +/// Get BCS serialized bytes for any value. +/// Re-exports stdlib `bcs::to_bytes`. +public fun to_bytes(value: &T): vector { + bcs::to_bytes(value) +} + +/// Creates a new instance of BCS wrapper that holds inversed +/// bytes for better performance. +public fun new(mut bytes: vector): BCS { + bytes.reverse(); + BCS { bytes } +} + +/// Unpack the `BCS` struct returning the leftover bytes. +/// Useful for passing the data further after partial deserialization. +public fun into_remainder_bytes(bcs: BCS): vector { + let BCS { mut bytes } = bcs; + bytes.reverse(); + bytes +} + +/// Read address from the bcs-serialized bytes. +public fun peel_address(bcs: &mut BCS): address { + assert!(bcs.bytes.length() >= address::length(), EOutOfRange); + let (mut addr_bytes, mut i) = (vector[], 0); + while (i < address::length()) { + addr_bytes.push_back(bcs.bytes.pop_back()); + i = i + 1; + }; + address::from_bytes(addr_bytes) +} + +/// Read a `bool` value from bcs-serialized bytes. +public fun peel_bool(bcs: &mut BCS): bool { + let value = bcs.peel_u8(); + if (value == 0) false + else if (value == 1) true + else abort ENotBool +} + +/// Read `u8` value from bcs-serialized bytes. +public fun peel_u8(bcs: &mut BCS): u8 { + assert!(bcs.bytes.length() >= 1, EOutOfRange); + bcs.bytes.pop_back() +} + +macro fun peel_num<$I, $T>($bcs: &mut BCS, $len: u64, $bits: $I): $T { + let bcs = $bcs; + assert!(bcs.bytes.length() >= $len, EOutOfRange); + + let mut value: $T = 0; + let mut i: $I = 0; + let bits = $bits; + while (i < bits) { + let byte = bcs.bytes.pop_back() as $T; + value = value + (byte << (i as u8)); + i = i + 8; + }; + + value +} + +/// Read `u16` value from bcs-serialized bytes. +public fun peel_u16(bcs: &mut BCS): u16 { + bcs.peel_num!(2, 16u8) +} + +/// Read `u32` value from bcs-serialized bytes. +public fun peel_u32(bcs: &mut BCS): u32 { + bcs.peel_num!(4, 32u8) +} + +/// Read `u64` value from bcs-serialized bytes. +public fun peel_u64(bcs: &mut BCS): u64 { + bcs.peel_num!(8, 64u8) +} + +/// Read `u128` value from bcs-serialized bytes. +public fun peel_u128(bcs: &mut BCS): u128 { + bcs.peel_num!(16, 128u8) +} + +/// Read `u256` value from bcs-serialized bytes. +public fun peel_u256(bcs: &mut BCS): u256 { + bcs.peel_num!(32, 256u16) +} + +// === Vector === + +/// Read ULEB bytes expecting a vector length. Result should +/// then be used to perform `peel_*` operation LEN times. +/// +/// In BCS `vector` length is implemented with ULEB128; +/// See more here: https://en.wikipedia.org/wiki/LEB128 +public fun peel_vec_length(bcs: &mut BCS): u64 { + let (mut total, mut shift, mut len) = (0u64, 0, 0); + loop { + assert!(len <= 4, ELenOutOfRange); + let byte = bcs.bytes.pop_back() as u64; + len = len + 1; + total = total | ((byte & 0x7f) << shift); + if ((byte & 0x80) == 0) break; + shift = shift + 7; + }; + total +} + +/// Peel `vector<$T>` from serialized bytes, where `$peel: |&mut BCS| -> $T` gives the +/// functionality of peeling each value. +public macro fun peel_vec<$T>($bcs: &mut BCS, $peel: |&mut BCS| -> $T): vector<$T> { + let bcs = $bcs; + let len = bcs.peel_vec_length(); + let mut i = 0; + let mut res = vector[]; + while (i < len) { + res.push_back($peel(bcs)); + i = i + 1; + }; + res +} + +/// Peel a vector of `address` from serialized bytes. +public fun peel_vec_address(bcs: &mut BCS): vector
{ + bcs.peel_vec!(|bcs| bcs.peel_address()) +} + +/// Peel a vector of `address` from serialized bytes. +public fun peel_vec_bool(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_bool()) +} + +/// Peel a vector of `u8` (eg string) from serialized bytes. +public fun peel_vec_u8(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_u8()) +} + +/// Peel a `vector>` (eg vec of string) from serialized bytes. +public fun peel_vec_vec_u8(bcs: &mut BCS): vector> { + bcs.peel_vec!(|bcs| bcs.peel_vec_u8()) +} + +/// Peel a vector of `u16` from serialized bytes. +public fun peel_vec_u16(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_u16()) +} + +/// Peel a vector of `u32` from serialized bytes. +public fun peel_vec_u32(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_u32()) +} + +/// Peel a vector of `u64` from serialized bytes. +public fun peel_vec_u64(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_u64()) +} + +/// Peel a vector of `u128` from serialized bytes. +public fun peel_vec_u128(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_u128()) +} + +/// Peel a vector of `u256` from serialized bytes. +public fun peel_vec_u256(bcs: &mut BCS): vector { + bcs.peel_vec!(|bcs| bcs.peel_u256()) +} + +// === Option === + +/// Peel `Option<$T>` from serialized bytes, where `$peel: |&mut BCS| -> $T` gives the +/// functionality of peeling the inner value. +public macro fun peel_option<$T>($bcs: &mut BCS, $peel: |&mut BCS| -> $T): Option<$T> { + let bcs = $bcs; + if (bcs.peel_bool()) option::some($peel(bcs)) + else option::none() +} + +/// Peel `Option
` from serialized bytes. +public fun peel_option_address(bcs: &mut BCS): Option
{ + bcs.peel_option!(|bcs| bcs.peel_address()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_bool(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_bool()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_u8(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_u8()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_u16(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_u16()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_u32(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_u32()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_u64(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_u64()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_u128(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_u128()) +} + +/// Peel `Option` from serialized bytes. +public fun peel_option_u256(bcs: &mut BCS): Option { + bcs.peel_option!(|bcs| bcs.peel_u256()) } diff --git a/crates/sui-framework/packages/sui-framework/sources/borrow.move b/crates/sui-framework/packages/sui-framework/sources/borrow.move index 55eb1e1ae5bd3..483a6aab4912a 100644 --- a/crates/sui-framework/packages/sui-framework/sources/borrow.move +++ b/crates/sui-framework/packages/sui-framework/sources/borrow.move @@ -6,113 +6,115 @@ /// With Programmable transactions, it is possible to borrow a value within /// a transaction, use it and put back in the end. Hot-potato `Borrow` makes /// sure the object is returned and was not swapped for another one. -module sui::borrow { +module sui::borrow; - /// The `Borrow` does not match the `Referent`. - const EWrongBorrow: u64 = 0; - /// An attempt to swap the `Referent.value` with another object of the same type. - const EWrongValue: u64 = 1; +/// The `Borrow` does not match the `Referent`. +const EWrongBorrow: u64 = 0; +/// An attempt to swap the `Referent.value` with another object of the same type. +const EWrongValue: u64 = 1; - /// An object wrapping a `T` and providing the borrow API. - public struct Referent has store { - id: address, - value: Option - } +/// An object wrapping a `T` and providing the borrow API. +public struct Referent has store { + id: address, + value: Option, +} - /// A hot potato making sure the object is put back once borrowed. - public struct Borrow { ref: address, obj: ID } +/// A hot potato making sure the object is put back once borrowed. +public struct Borrow { ref: address, obj: ID } - /// Create a new `Referent` struct - public fun new(value: T, ctx: &mut TxContext): Referent { - Referent { - id: tx_context::fresh_object_address(ctx), - value: option::some(value) - } +/// Create a new `Referent` struct +public fun new(value: T, ctx: &mut TxContext): Referent { + Referent { + id: tx_context::fresh_object_address(ctx), + value: option::some(value), } +} - /// Borrow the `T` from the `Referent` receiving the `T` and a `Borrow` - /// hot potato. - public fun borrow(self: &mut Referent): (T, Borrow) { - let value = self.value.extract(); - let id = object::id(&value); +/// Borrow the `T` from the `Referent` receiving the `T` and a `Borrow` +/// hot potato. +public fun borrow(self: &mut Referent): (T, Borrow) { + let value = self.value.extract(); + let id = object::id(&value); - (value, Borrow { + ( + value, + Borrow { ref: self.id, - obj: id - }) - } + obj: id, + }, + ) +} - /// Put an object and the `Borrow` hot potato back. - public fun put_back(self: &mut Referent, value: T, borrow: Borrow) { - let Borrow { ref, obj } = borrow; +/// Put an object and the `Borrow` hot potato back. +public fun put_back(self: &mut Referent, value: T, borrow: Borrow) { + let Borrow { ref, obj } = borrow; - assert!(object::id(&value) == obj, EWrongValue); - assert!(self.id == ref, EWrongBorrow); - self.value.fill(value); - } + assert!(object::id(&value) == obj, EWrongValue); + assert!(self.id == ref, EWrongBorrow); + self.value.fill(value); +} - /// Unpack the `Referent` struct and return the value. - public fun destroy(self: Referent): T { - let Referent { id: _, value } = self; - value.destroy_some() - } +/// Unpack the `Referent` struct and return the value. +public fun destroy(self: Referent): T { + let Referent { id: _, value } = self; + value.destroy_some() +} - #[test_only] - public struct Test has key, store { - id: object::UID - } +#[test_only] +public struct Test has key, store { + id: object::UID, +} - #[test] - fun test_borrow() { - let ctx = &mut sui::tx_context::dummy(); - let mut ref = new(Test { id: object::new(ctx) }, ctx); +#[test] +fun test_borrow() { + let ctx = &mut sui::tx_context::dummy(); + let mut ref = new(Test { id: object::new(ctx) }, ctx); - let (value, borrow) = borrow(&mut ref); - put_back(&mut ref, value, borrow); + let (value, borrow) = borrow(&mut ref); + put_back(&mut ref, value, borrow); - let Test { id } = destroy(ref); - id.delete(); - } + let Test { id } = destroy(ref); + id.delete(); +} - #[test] - #[expected_failure(abort_code = EWrongValue)] - /// The `value` is swapped with another instance of the type `T`. - fun test_object_swap() { - let ctx = &mut sui::tx_context::dummy(); - let mut ref_1 = new(Test { id: object::new(ctx) }, ctx); - let mut ref_2 = new(Test { id: object::new(ctx) }, ctx); +#[test] +#[expected_failure(abort_code = EWrongValue)] +/// The `value` is swapped with another instance of the type `T`. +fun test_object_swap() { + let ctx = &mut sui::tx_context::dummy(); + let mut ref_1 = new(Test { id: object::new(ctx) }, ctx); + let mut ref_2 = new(Test { id: object::new(ctx) }, ctx); - let (v_1, b_1) = borrow(&mut ref_1); - let (v_2, b_2) = borrow(&mut ref_2); + let (v_1, b_1) = borrow(&mut ref_1); + let (v_2, b_2) = borrow(&mut ref_2); - put_back(&mut ref_1, v_2, b_1); - put_back(&mut ref_2, v_1, b_2); + put_back(&mut ref_1, v_2, b_1); + put_back(&mut ref_2, v_1, b_2); - let Test { id } = destroy(ref_1); - id.delete(); + let Test { id } = destroy(ref_1); + id.delete(); - let Test { id } = destroy(ref_2); - id.delete(); - } + let Test { id } = destroy(ref_2); + id.delete(); +} - #[test] - #[expected_failure(abort_code = EWrongBorrow)] - /// The both `borrow` and `value` are swapped with another `Referent`. - fun test_borrow_fail() { - let ctx = &mut sui::tx_context::dummy(); - let mut ref_1 = new(Test { id: object::new(ctx) }, ctx); - let mut ref_2 = new(Test { id: object::new(ctx) }, ctx); +#[test] +#[expected_failure(abort_code = EWrongBorrow)] +/// The both `borrow` and `value` are swapped with another `Referent`. +fun test_borrow_fail() { + let ctx = &mut sui::tx_context::dummy(); + let mut ref_1 = new(Test { id: object::new(ctx) }, ctx); + let mut ref_2 = new(Test { id: object::new(ctx) }, ctx); - let (v_1, b_1) = borrow(&mut ref_1); - let (v_2, b_2) = borrow(&mut ref_2); + let (v_1, b_1) = borrow(&mut ref_1); + let (v_2, b_2) = borrow(&mut ref_2); - put_back(&mut ref_1, v_2, b_2); - put_back(&mut ref_2, v_1, b_1); + put_back(&mut ref_1, v_2, b_2); + put_back(&mut ref_2, v_1, b_1); - let Test { id } = destroy(ref_1); - id.delete(); + let Test { id } = destroy(ref_1); + id.delete(); - let Test { id } = destroy(ref_2); - id.delete(); - } + let Test { id } = destroy(ref_2); + id.delete(); } diff --git a/crates/sui-framework/packages/sui-framework/sources/clock.move b/crates/sui-framework/packages/sui-framework/sources/clock.move index 9cfa08c9c6872..11b72322248a1 100644 --- a/crates/sui-framework/packages/sui-framework/sources/clock.move +++ b/crates/sui-framework/packages/sui-framework/sources/clock.move @@ -3,91 +3,86 @@ /// APIs for accessing time from move calls, via the `Clock`: a unique /// shared object that is created at 0x6 during genesis. -module sui::clock { +module sui::clock; - /// Sender is not @0x0 the system address. - const ENotSystemAddress: u64 = 0; +/// Sender is not @0x0 the system address. +const ENotSystemAddress: u64 = 0; - /// Singleton shared object that exposes time to Move calls. This - /// object is found at address 0x6, and can only be read (accessed - /// via an immutable reference) by entry functions. - /// - /// Entry Functions that attempt to accept `Clock` by mutable - /// reference or value will fail to verify, and honest validators - /// will not sign or execute transactions that use `Clock` as an - /// input parameter, unless it is passed by immutable reference. - public struct Clock has key { - id: UID, - /// The clock's timestamp, which is set automatically by a - /// system transaction every time consensus commits a - /// schedule, or by `sui::clock::increment_for_testing` during - /// testing. - timestamp_ms: u64, - } +/// Singleton shared object that exposes time to Move calls. This +/// object is found at address 0x6, and can only be read (accessed +/// via an immutable reference) by entry functions. +/// +/// Entry Functions that attempt to accept `Clock` by mutable +/// reference or value will fail to verify, and honest validators +/// will not sign or execute transactions that use `Clock` as an +/// input parameter, unless it is passed by immutable reference. +public struct Clock has key { + id: UID, + /// The clock's timestamp, which is set automatically by a + /// system transaction every time consensus commits a + /// schedule, or by `sui::clock::increment_for_testing` during + /// testing. + timestamp_ms: u64, +} - /// The `clock`'s current timestamp as a running total of - /// milliseconds since an arbitrary point in the past. - public fun timestamp_ms(clock: &Clock): u64 { - clock.timestamp_ms - } +/// The `clock`'s current timestamp as a running total of +/// milliseconds since an arbitrary point in the past. +public fun timestamp_ms(clock: &Clock): u64 { + clock.timestamp_ms +} - #[allow(unused_function)] - /// Create and share the singleton Clock -- this function is - /// called exactly once, during genesis. - fun create(ctx: &TxContext) { - assert!(ctx.sender() == @0x0, ENotSystemAddress); +#[allow(unused_function)] +/// Create and share the singleton Clock -- this function is +/// called exactly once, during genesis. +fun create(ctx: &TxContext) { + assert!(ctx.sender() == @0x0, ENotSystemAddress); - transfer::share_object(Clock { - id: object::clock(), - // Initialised to zero, but set to a real timestamp by a - // system transaction before it can be witnessed by a move - // call. - timestamp_ms: 0, - }) - } + transfer::share_object(Clock { + id: object::clock(), + // Initialised to zero, but set to a real timestamp by a + // system transaction before it can be witnessed by a move + // call. + timestamp_ms: 0, + }) +} - #[allow(unused_function)] - fun consensus_commit_prologue( - clock: &mut Clock, - timestamp_ms: u64, - ctx: &TxContext, - ) { - // Validator will make a special system call with sender set as 0x0. - assert!(ctx.sender() == @0x0, ENotSystemAddress); +#[allow(unused_function)] +fun consensus_commit_prologue(clock: &mut Clock, timestamp_ms: u64, ctx: &TxContext) { + // Validator will make a special system call with sender set as 0x0. + assert!(ctx.sender() == @0x0, ENotSystemAddress); - clock.timestamp_ms = timestamp_ms - } + clock.timestamp_ms = timestamp_ms +} - #[test_only] - /// Expose the functionality of `create()` (usually only done during - /// genesis) for tests that want to create a Clock. - public fun create_for_testing(ctx: &mut TxContext): Clock { - Clock { - id: object::new(ctx), - timestamp_ms: 0, - } +#[test_only] +/// Expose the functionality of `create()` (usually only done during +/// genesis) for tests that want to create a Clock. +public fun create_for_testing(ctx: &mut TxContext): Clock { + Clock { + id: object::new(ctx), + timestamp_ms: 0, } +} - #[test_only] - /// For transactional tests (if a Clock is used as a shared object). - public fun share_for_testing(clock: Clock) { - transfer::share_object(clock) - } +#[test_only] +/// For transactional tests (if a Clock is used as a shared object). +public fun share_for_testing(clock: Clock) { + transfer::share_object(clock) +} - #[test_only] - public fun increment_for_testing(clock: &mut Clock, tick: u64) { - clock.timestamp_ms = clock.timestamp_ms + tick; - } +#[test_only] +public fun increment_for_testing(clock: &mut Clock, tick: u64) { + clock.timestamp_ms = clock.timestamp_ms + tick; +} - #[test_only] - public fun set_for_testing(clock: &mut Clock, timestamp_ms: u64) { - assert!(timestamp_ms >= clock.timestamp_ms); - clock.timestamp_ms = timestamp_ms; - } +#[test_only] +public fun set_for_testing(clock: &mut Clock, timestamp_ms: u64) { + assert!(timestamp_ms >= clock.timestamp_ms); + clock.timestamp_ms = timestamp_ms; +} - #[test_only] - public fun destroy_for_testing(clock: Clock) { - let Clock { id, timestamp_ms: _ } = clock; - id.delete(); - } +#[test_only] +public fun destroy_for_testing(clock: Clock) { + let Clock { id, timestamp_ms: _ } = clock; + id.delete(); } diff --git a/crates/sui-framework/packages/sui-framework/sources/display.move b/crates/sui-framework/packages/sui-framework/sources/display.move index ef590aba27b40..b09e4802600d6 100644 --- a/crates/sui-framework/packages/sui-framework/sources/display.move +++ b/crates/sui-framework/packages/sui-framework/sources/display.move @@ -10,218 +10,184 @@ /// substitution and filling-in the pieces using the data from the object T. /// /// More entry functions might be added in the future depending on the use cases. -module sui::display { - use sui::package::Publisher; - use sui::vec_map::{Self, VecMap}; - use sui::event; - use std::string::String; - - /// For when T does not belong to the package `Publisher`. - const ENotOwner: u64 = 0; - - /// For when vectors passed into one of the multiple insert functions - /// don't match in their lengths. - const EVecLengthMismatch: u64 = 1; - - /// The Display object. Defines the way a T instance should be - /// displayed. Display object can only be created and modified with - /// a PublisherCap, making sure that the rules are set by the owner - /// of the type. - /// - /// Each of the display properties should support patterns outside - /// of the system, making it simpler to customize Display based - /// on the property values of an Object. - /// ``` - /// // Example of a display object - /// Display<0x...::capy::Capy> { - /// fields: - /// - /// - /// - /// - /// } - /// ``` - /// - /// Uses only String type due to external-facing nature of the object, - /// the property names have a priority over their types. - public struct Display has key, store { - id: UID, - /// Contains fields for display. Currently supported - /// fields are: name, link, image and description. - fields: VecMap, - /// Version that can only be updated manually by the Publisher. - version: u16 - } - - /// Event: emitted when a new Display object has been created for type T. - /// Type signature of the event corresponds to the type while id serves for - /// the discovery. - /// - /// Since Sui RPC supports querying events by type, finding a Display for the T - /// would be as simple as looking for the first event with `Display`. - public struct DisplayCreated has copy, drop { - id: ID - } - - /// Version of Display got updated - - public struct VersionUpdated has copy, drop { - id: ID, - version: u16, - fields: VecMap, - } +module sui::display; - // === Initializer Methods === +use std::string::String; +use sui::event; +use sui::package::Publisher; +use sui::vec_map::{Self, VecMap}; - /// Create an empty Display object. It can either be shared empty or filled - /// with data right away via cheaper `set_owned` method. - public fun new(pub: &Publisher, ctx: &mut TxContext): Display { - assert!(is_authorized(pub), ENotOwner); - create_internal(ctx) - } - - /// Create a new Display object with a set of fields. - public fun new_with_fields( - pub: &Publisher, fields: vector, values: vector, ctx: &mut TxContext - ): Display { - let len = fields.length(); - assert!(len == values.length(), EVecLengthMismatch); - - let mut i = 0; - let mut display = new(pub, ctx); - while (i < len) { - display.add_internal(fields[i], values[i]); - i = i + 1; - }; - - display - } +/// For when T does not belong to the package `Publisher`. +const ENotOwner: u64 = 0; - // === Entry functions: Create === +/// For when vectors passed into one of the multiple insert functions +/// don't match in their lengths. +const EVecLengthMismatch: u64 = 1; - #[allow(lint(self_transfer))] - /// Create a new empty Display object and keep it. - entry public fun create_and_keep(pub: &Publisher, ctx: &mut TxContext) { - transfer::public_transfer(new(pub, ctx), ctx.sender()) - } +/// The Display object. Defines the way a T instance should be +/// displayed. Display object can only be created and modified with +/// a PublisherCap, making sure that the rules are set by the owner +/// of the type. +/// +/// Each of the display properties should support patterns outside +/// of the system, making it simpler to customize Display based +/// on the property values of an Object. +/// ``` +/// // Example of a display object +/// Display<0x...::capy::Capy> { +/// fields: +/// +/// +/// +/// +/// } +/// ``` +/// +/// Uses only String type due to external-facing nature of the object, +/// the property names have a priority over their types. +public struct Display has key, store { + id: UID, + /// Contains fields for display. Currently supported + /// fields are: name, link, image and description. + fields: VecMap, + /// Version that can only be updated manually by the Publisher. + version: u16, +} - /// Manually bump the version and emit an event with the updated version's contents. - entry public fun update_version( - display: &mut Display - ) { - display.version = display.version + 1; - event::emit(VersionUpdated { - version: display.version, - fields: *&display.fields, - id: display.id.to_inner(), - }) - } +/// Event: emitted when a new Display object has been created for type T. +/// Type signature of the event corresponds to the type while id serves for +/// the discovery. +/// +/// Since Sui RPC supports querying events by type, finding a Display for the T +/// would be as simple as looking for the first event with `Display`. +public struct DisplayCreated has copy, drop { + id: ID, +} - // === Entry functions: Add/Modify fields === +/// Version of Display got updated - +public struct VersionUpdated has copy, drop { + id: ID, + version: u16, + fields: VecMap, +} - /// Sets a custom `name` field with the `value`. - entry public fun add(self: &mut Display, name: String, value: String) { - self.add_internal(name, value) - } +// === Initializer Methods === - /// Sets multiple `fields` with `values`. - entry public fun add_multiple( - self: &mut Display, fields: vector, values: vector - ) { - let len = fields.length(); - assert!(len == values.length(), EVecLengthMismatch); - - let mut i = 0; - while (i < len) { - self.add_internal(fields[i], values[i]); - i = i + 1; - }; - } +/// Create an empty Display object. It can either be shared empty or filled +/// with data right away via cheaper `set_owned` method. +public fun new(pub: &Publisher, ctx: &mut TxContext): Display { + assert!(is_authorized(pub), ENotOwner); + create_internal(ctx) +} - /// Change the value of the field. - /// TODO (long run): version changes; - entry public fun edit(self: &mut Display, name: String, value: String) { - let (_, _) = self.fields.remove(&name); - self.add_internal(name, value) - } +/// Create a new Display object with a set of fields. +public fun new_with_fields( + pub: &Publisher, + fields: vector, + values: vector, + ctx: &mut TxContext, +): Display { + let len = fields.length(); + assert!(len == values.length(), EVecLengthMismatch); + + let mut i = 0; + let mut display = new(pub, ctx); + while (i < len) { + display.add_internal(fields[i], values[i]); + i = i + 1; + }; + + display +} - /// Remove the key from the Display. - entry public fun remove(self: &mut Display, name: String) { - self.fields.remove(&name); - } +// === Entry functions: Create === - // === Access fields === +#[allow(lint(self_transfer))] +/// Create a new empty Display object and keep it. +public entry fun create_and_keep(pub: &Publisher, ctx: &mut TxContext) { + transfer::public_transfer(new(pub, ctx), ctx.sender()) +} - /// Authorization check; can be performed externally to implement protection rules for Display. - public fun is_authorized(pub: &Publisher): bool { - pub.from_package() - } +/// Manually bump the version and emit an event with the updated version's contents. +public entry fun update_version(display: &mut Display) { + display.version = display.version + 1; + event::emit(VersionUpdated { + version: display.version, + fields: *&display.fields, + id: display.id.to_inner(), + }) +} - /// Read the `version` field. - public fun version(d: &Display): u16 { - d.version - } +// === Entry functions: Add/Modify fields === - /// Read the `fields` field. - public fun fields(d: &Display): &VecMap { - &d.fields - } +/// Sets a custom `name` field with the `value`. +public entry fun add(self: &mut Display, name: String, value: String) { + self.add_internal(name, value) +} - // === Private functions === +/// Sets multiple `fields` with `values`. +public entry fun add_multiple( + self: &mut Display, + fields: vector, + values: vector, +) { + let len = fields.length(); + assert!(len == values.length(), EVecLengthMismatch); + + let mut i = 0; + while (i < len) { + self.add_internal(fields[i], values[i]); + i = i + 1; + }; +} - /// Internal function to create a new `Display`. - fun create_internal(ctx: &mut TxContext): Display { - let uid = object::new(ctx); +/// Change the value of the field. +/// TODO (long run): version changes; +public entry fun edit(self: &mut Display, name: String, value: String) { + let (_, _) = self.fields.remove(&name); + self.add_internal(name, value) +} - event::emit(DisplayCreated { - id: uid.to_inner() - }); +/// Remove the key from the Display. +public entry fun remove(self: &mut Display, name: String) { + self.fields.remove(&name); +} - Display { - id: uid, - fields: vec_map::empty(), - version: 0, - } - } +// === Access fields === - /// Private method for inserting fields without security checks. - fun add_internal(display: &mut Display, name: String, value: String) { - display.fields.insert(name, value) - } +/// Authorization check; can be performed externally to implement protection rules for Display. +public fun is_authorized(pub: &Publisher): bool { + pub.from_package() } -#[test_only] -module sui::display_tests { - use sui::test_scenario as test; - use std::string::String; - use sui::package; - use sui::display; - - #[allow(unused_field)] - /// An example object. - /// Purely for visibility. - public struct Capy has key { - id: UID, - name: String - } +/// Read the `version` field. +public fun version(d: &Display): u16 { + d.version +} - /// Test witness type to create a Publisher object. - public struct CAPY has drop {} +/// Read the `fields` field. +public fun fields(d: &Display): &VecMap { + &d.fields +} - #[test] - fun capy_init() { - let mut test = test::begin(@0x2); - let pub = package::test_claim(CAPY {}, test.ctx()); +// === Private functions === - // create a new display object - let mut display = display::new(&pub, test.ctx()); +/// Internal function to create a new `Display`. +fun create_internal(ctx: &mut TxContext): Display { + let uid = object::new(ctx); - display.add(b"name".to_string(), b"Capy {name}".to_string()); - display.add(b"link".to_string(), b"https://capy.art/capy/{id}".to_string()); - display.add(b"image".to_string(), b"https://api.capy.art/capy/{id}/svg".to_string()); - display.add(b"description".to_string(), b"A Lovely Capy".to_string()); + event::emit(DisplayCreated { + id: uid.to_inner(), + }); - pub.burn_publisher(); - transfer::public_transfer(display, @0x2); - test.end(); + Display { + id: uid, + fields: vec_map::empty(), + version: 0, } } + +/// Private method for inserting fields without security checks. +fun add_internal(display: &mut Display, name: String, value: String) { + display.fields.insert(name, value) +} diff --git a/crates/sui-framework/packages/sui-framework/sources/event.move b/crates/sui-framework/packages/sui-framework/sources/event.move index f708ac46285c5..7aea21d5c2108 100644 --- a/crates/sui-framework/packages/sui-framework/sources/event.move +++ b/crates/sui-framework/packages/sui-framework/sources/event.move @@ -26,22 +26,22 @@ /// } /// } /// ``` -module sui::event { - /// Emit a custom Move event, sending the data offchain. - /// - /// Used for creating custom indexes and tracking onchain - /// activity in a way that suits a specific application the most. - /// - /// The type `T` is the main way to index the event, and can contain - /// phantom parameters, eg `emit(MyEvent)`. - public native fun emit(event: T); +module sui::event; - #[test_only] - /// Get the total number of events emitted during execution so far - public native fun num_events(): u32; +/// Emit a custom Move event, sending the data offchain. +/// +/// Used for creating custom indexes and tracking onchain +/// activity in a way that suits a specific application the most. +/// +/// The type `T` is the main way to index the event, and can contain +/// phantom parameters, eg `emit(MyEvent)`. +public native fun emit(event: T); + +#[test_only] +/// Get the total number of events emitted during execution so far +public native fun num_events(): u32; - #[test_only] - /// Get all events of type `T` emitted during execution. - /// Can only be used in testing, - public native fun events_by_type(): vector; -} +#[test_only] +/// Get all events of type `T` emitted during execution. +/// Can only be used in testing, +public native fun events_by_type(): vector; diff --git a/crates/sui-framework/packages/sui-framework/sources/hex.move b/crates/sui-framework/packages/sui-framework/sources/hex.move index 640e4338d9a62..5776d3e912076 100644 --- a/crates/sui-framework/packages/sui-framework/sources/hex.move +++ b/crates/sui-framework/packages/sui-framework/sources/hex.move @@ -2,104 +2,68 @@ // SPDX-License-Identifier: Apache-2.0 /// HEX (Base16) encoding utility. -module sui::hex { +module sui::hex; - const EInvalidHexLength: u64 = 0; - const ENotValidHexCharacter: u64 = 1; +const EInvalidHexLength: u64 = 0; +const ENotValidHexCharacter: u64 = 1; - /// Vector of Base16 values from `00` to `FF` - const HEX: vector> = vector[ - b"00",b"01",b"02",b"03",b"04",b"05",b"06",b"07",b"08",b"09",b"0a",b"0b",b"0c",b"0d",b"0e",b"0f",b"10",b"11",b"12",b"13",b"14",b"15",b"16",b"17",b"18",b"19",b"1a",b"1b",b"1c",b"1d",b"1e",b"1f",b"20",b"21",b"22",b"23",b"24",b"25",b"26",b"27",b"28",b"29",b"2a",b"2b",b"2c",b"2d",b"2e",b"2f",b"30",b"31",b"32",b"33",b"34",b"35",b"36",b"37",b"38",b"39",b"3a",b"3b",b"3c",b"3d",b"3e",b"3f",b"40",b"41",b"42",b"43",b"44",b"45",b"46",b"47",b"48",b"49",b"4a",b"4b",b"4c",b"4d",b"4e",b"4f",b"50",b"51",b"52",b"53",b"54",b"55",b"56",b"57",b"58",b"59",b"5a",b"5b",b"5c",b"5d",b"5e",b"5f",b"60",b"61",b"62",b"63",b"64",b"65",b"66",b"67",b"68",b"69",b"6a",b"6b",b"6c",b"6d",b"6e",b"6f",b"70",b"71",b"72",b"73",b"74",b"75",b"76",b"77",b"78",b"79",b"7a",b"7b",b"7c",b"7d",b"7e",b"7f",b"80",b"81",b"82",b"83",b"84",b"85",b"86",b"87",b"88",b"89",b"8a",b"8b",b"8c",b"8d",b"8e",b"8f",b"90",b"91",b"92",b"93",b"94",b"95",b"96",b"97",b"98",b"99",b"9a",b"9b",b"9c",b"9d",b"9e",b"9f",b"a0",b"a1",b"a2",b"a3",b"a4",b"a5",b"a6",b"a7",b"a8",b"a9",b"aa",b"ab",b"ac",b"ad",b"ae",b"af",b"b0",b"b1",b"b2",b"b3",b"b4",b"b5",b"b6",b"b7",b"b8",b"b9",b"ba",b"bb",b"bc",b"bd",b"be",b"bf",b"c0",b"c1",b"c2",b"c3",b"c4",b"c5",b"c6",b"c7",b"c8",b"c9",b"ca",b"cb",b"cc",b"cd",b"ce",b"cf",b"d0",b"d1",b"d2",b"d3",b"d4",b"d5",b"d6",b"d7",b"d8",b"d9",b"da",b"db",b"dc",b"dd",b"de",b"df",b"e0",b"e1",b"e2",b"e3",b"e4",b"e5",b"e6",b"e7",b"e8",b"e9",b"ea",b"eb",b"ec",b"ed",b"ee",b"ef",b"f0",b"f1",b"f2",b"f3",b"f4",b"f5",b"f6",b"f7",b"f8",b"f9",b"fa",b"fb",b"fc",b"fd",b"fe",b"ff" - ]; +// prettier-ignore +/// Vector of Base16 values from `00` to `FF` +const HEX: vector> = vector[ + b"00", b"01", b"02", b"03", b"04", b"05", b"06", b"07", b"08", b"09", b"0a", b"0b", b"0c", b"0d", b"0e", b"0f", + b"10", b"11", b"12", b"13", b"14", b"15", b"16", b"17", b"18", b"19", b"1a", b"1b", b"1c", b"1d", b"1e", b"1f", + b"20", b"21", b"22", b"23", b"24", b"25", b"26", b"27", b"28", b"29", b"2a", b"2b", b"2c", b"2d", b"2e", b"2f", + b"30", b"31", b"32", b"33", b"34", b"35", b"36", b"37", b"38", b"39", b"3a", b"3b", b"3c", b"3d", b"3e", b"3f", + b"40", b"41", b"42", b"43", b"44", b"45", b"46", b"47", b"48", b"49", b"4a", b"4b", b"4c", b"4d", b"4e", b"4f", + b"50", b"51", b"52", b"53", b"54", b"55", b"56", b"57", b"58", b"59", b"5a", b"5b", b"5c", b"5d", b"5e", b"5f", + b"60", b"61", b"62", b"63", b"64", b"65", b"66", b"67", b"68", b"69", b"6a", b"6b", b"6c", b"6d", b"6e", b"6f", + b"70", b"71", b"72", b"73", b"74", b"75", b"76", b"77", b"78", b"79", b"7a", b"7b", b"7c", b"7d", b"7e", b"7f", + b"80", b"81", b"82", b"83", b"84", b"85", b"86", b"87", b"88", b"89", b"8a", b"8b", b"8c", b"8d", b"8e", b"8f", + b"90", b"91", b"92", b"93", b"94", b"95", b"96", b"97", b"98", b"99", b"9a", b"9b", b"9c", b"9d", b"9e", b"9f", + b"a0", b"a1", b"a2", b"a3", b"a4", b"a5", b"a6", b"a7", b"a8", b"a9", b"aa", b"ab", b"ac", b"ad", b"ae", b"af", + b"b0", b"b1", b"b2", b"b3", b"b4", b"b5", b"b6", b"b7", b"b8", b"b9", b"ba", b"bb", b"bc", b"bd", b"be", b"bf", + b"c0", b"c1", b"c2", b"c3", b"c4", b"c5", b"c6", b"c7", b"c8", b"c9", b"ca", b"cb", b"cc", b"cd", b"ce", b"cf", + b"d0", b"d1", b"d2", b"d3", b"d4", b"d5", b"d6", b"d7", b"d8", b"d9", b"da", b"db", b"dc", b"dd", b"de", b"df", + b"e0", b"e1", b"e2", b"e3", b"e4", b"e5", b"e6", b"e7", b"e8", b"e9", b"ea", b"eb", b"ec", b"ed", b"ee", b"ef", + b"f0", b"f1", b"f2", b"f3", b"f4", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb", b"fc", b"fd", b"fe", b"ff", +]; - /// Encode `bytes` in lowercase hex - public fun encode(bytes: vector): vector { - let (mut i, mut r, l) = (0, vector[], bytes.length()); - let hex_vector = HEX; - while (i < l) { - r.append(hex_vector[bytes[i] as u64]); - i = i + 1; - }; - r - } - - /// Decode hex into `bytes` - /// Takes a hex string (no 0x prefix) (e.g. b"0f3a") - /// Returns vector of `bytes` that represents the hex string (e.g. x"0f3a") - /// Hex string can be case insensitive (e.g. b"0F3A" and b"0f3a" both return x"0f3a") - /// Aborts if the hex string does not have an even number of characters (as each hex character is 2 characters long) - /// Aborts if the hex string contains non-valid hex characters (valid characters are 0 - 9, a - f, A - F) - public fun decode(hex: vector): vector { - let (mut i, mut r, l) = (0, vector[], hex.length()); - assert!(l % 2 == 0, EInvalidHexLength); - while (i < l) { - let decimal = decode_byte(hex[i]) * 16 + decode_byte(hex[i + 1]); - r.push_back(decimal); - i = i + 2; - }; - r - } - - fun decode_byte(hex: u8): u8 { - if (/* 0 .. 9 */ 48 <= hex && hex < 58) { - hex - 48 - } else if (/* A .. F */ 65 <= hex && hex < 71) { - 10 + hex - 65 - } else if (/* a .. f */ 97 <= hex && hex < 103) { - 10 + hex - 97 - } else { - abort ENotValidHexCharacter - } - } - - #[test] - fun test_hex_encode_string_literal() { - assert!(b"30" == encode(b"0")); - assert!(b"61" == encode(b"a")); - assert!(b"666666" == encode(b"fff")); - } - - #[test] - fun test_hex_encode_hex_literal() { - assert!(b"ff" == encode(x"ff")); - assert!(b"fe" == encode(x"fe")); - assert!(b"00" == encode(x"00")); - } - - #[test] - fun test_hex_decode_string_literal() { - assert!(x"ff" == decode(b"ff")); - assert!(x"fe" == decode(b"fe")); - assert!(x"00" == decode(b"00")); - } - - #[test] - fun test_hex_decode_string_literal__lowercase_and_uppercase() { - assert!(x"ff" == decode(b"Ff")); - assert!(x"ff" == decode(b"fF")); - assert!(x"ff" == decode(b"FF")); - } - - #[test] - fun test_hex_decode_string_literal__long_hex() { - assert!(x"036d2416252ae1db8aedad59e14b007bee6ab94a3e77a3549a81137871604456f3" == decode(b"036d2416252ae1Db8aedAd59e14b007bee6aB94a3e77a3549a81137871604456f3")); - } - - #[test] - #[expected_failure(abort_code = EInvalidHexLength)] - fun test_hex_decode__invalid_length() { - decode(b"0"); - } +/// Encode `bytes` in lowercase hex +public fun encode(bytes: vector): vector { + let (mut i, mut r, l) = (0, vector[], bytes.length()); + let hex_vector = HEX; + while (i < l) { + r.append(hex_vector[bytes[i] as u64]); + i = i + 1; + }; + r +} - #[test] - #[expected_failure(abort_code = ENotValidHexCharacter)] - fun test_hex_decode__hex_literal() { - decode(x"ffff"); - } +/// Decode hex into `bytes` +/// Takes a hex string (no 0x prefix) (e.g. b"0f3a") +/// Returns vector of `bytes` that represents the hex string (e.g. x"0f3a") +/// Hex string can be case insensitive (e.g. b"0F3A" and b"0f3a" both return x"0f3a") +/// Aborts if the hex string does not have an even number of characters (as each hex character is 2 characters long) +/// Aborts if the hex string contains non-valid hex characters (valid characters are 0 - 9, a - f, A - F) +public fun decode(hex: vector): vector { + let (mut i, mut r, l) = (0, vector[], hex.length()); + assert!(l % 2 == 0, EInvalidHexLength); + while (i < l) { + let decimal = decode_byte(hex[i]) * 16 + decode_byte(hex[i + 1]); + r.push_back(decimal); + i = i + 2; + }; + r +} - #[test] - #[expected_failure(abort_code = ENotValidHexCharacter)] - fun test_hex_decode__invalid_string_literal() { - decode(b"0g"); +fun decode_byte(hex: u8): u8 { + if (48 <= hex && hex < 58) { + hex - 48 + } else if (65 <= hex && hex < 71) { + 10 + hex - 65 + } else if (97 <= hex && hex < 103) { + 10 + hex - 97 + } else { + abort ENotValidHexCharacter } } diff --git a/crates/sui-framework/packages/sui-framework/sources/math.move b/crates/sui-framework/packages/sui-framework/sources/math.move index f98a7d7c5eb72..2ad382cc8304d 100644 --- a/crates/sui-framework/packages/sui-framework/sources/math.move +++ b/crates/sui-framework/packages/sui-framework/sources/math.move @@ -3,40 +3,39 @@ /// DEPRECATED, use the each integer type's individual module instead, e.g. `std::u64` #[deprecated(note = b"Use the each integer type's individual module instead, e.g. `std::u64`")] -module sui::math { - - /// DEPRECATED, use `std::u64::max` instead - public fun max(x: u64, y: u64): u64 { - x.max(y) - } - - /// DEPRECATED, use `std::u64::min` instead - public fun min(x: u64, y: u64): u64 { - x.min(y) - } - - /// DEPRECATED, use `std::u64::diff` instead - public fun diff(x: u64, y: u64): u64 { - x.diff(y) - } - - /// DEPRECATED, use `std::u64::pow` instead - public fun pow(base: u64, exponent: u8): u64 { - base.pow(exponent) - } - - /// DEPRECATED, use `std::u64::sqrt` instead - public fun sqrt(x: u64): u64 { - x.sqrt() - } - - /// DEPRECATED, use `std::u128::sqrt` instead - public fun sqrt_u128(x: u128): u128 { - x.sqrt() - } - - /// DEPRECATED, use `std::u64::divide_and_round_up` instead - public fun divide_and_round_up(x: u64, y: u64): u64 { - x.divide_and_round_up(y) - } +module sui::math; + +/// DEPRECATED, use `std::u64::max` instead +public fun max(x: u64, y: u64): u64 { + x.max(y) +} + +/// DEPRECATED, use `std::u64::min` instead +public fun min(x: u64, y: u64): u64 { + x.min(y) +} + +/// DEPRECATED, use `std::u64::diff` instead +public fun diff(x: u64, y: u64): u64 { + x.diff(y) +} + +/// DEPRECATED, use `std::u64::pow` instead +public fun pow(base: u64, exponent: u8): u64 { + base.pow(exponent) +} + +/// DEPRECATED, use `std::u64::sqrt` instead +public fun sqrt(x: u64): u64 { + x.sqrt() +} + +/// DEPRECATED, use `std::u128::sqrt` instead +public fun sqrt_u128(x: u128): u128 { + x.sqrt() +} + +/// DEPRECATED, use `std::u64::divide_and_round_up` instead +public fun divide_and_round_up(x: u64, y: u64): u64 { + x.divide_and_round_up(y) } diff --git a/crates/sui-framework/packages/sui-framework/sources/object.move b/crates/sui-framework/packages/sui-framework/sources/object.move index 5b1a388bb2450..8bc0c67c38fc8 100644 --- a/crates/sui-framework/packages/sui-framework/sources/object.move +++ b/crates/sui-framework/packages/sui-framework/sources/object.move @@ -2,233 +2,232 @@ // SPDX-License-Identifier: Apache-2.0 /// Sui object identifiers -module sui::object { - use std::bcs; - use sui::address; +module sui::object; - /// Allows calling `.to_address` on an `ID` to get an `address`. - public use fun id_to_address as ID.to_address; +use std::bcs; +use sui::address; - /// Allows calling `.to_bytes` on an `ID` to get a `vector`. - public use fun id_to_bytes as ID.to_bytes; +/// Allows calling `.to_address` on an `ID` to get an `address`. +public use fun id_to_address as ID.to_address; - /// Allows calling `.as_inner` on a `UID` to get an `&ID`. - public use fun uid_as_inner as UID.as_inner; +/// Allows calling `.to_bytes` on an `ID` to get a `vector`. +public use fun id_to_bytes as ID.to_bytes; - /// Allows calling `.to_inner` on a `UID` to get an `ID`. - public use fun uid_to_inner as UID.to_inner; +/// Allows calling `.as_inner` on a `UID` to get an `&ID`. +public use fun uid_as_inner as UID.as_inner; - /// Allows calling `.to_address` on a `UID` to get an `address`. - public use fun uid_to_address as UID.to_address; +/// Allows calling `.to_inner` on a `UID` to get an `ID`. +public use fun uid_to_inner as UID.to_inner; - /// Allows calling `.to_bytes` on a `UID` to get a `vector`. - public use fun uid_to_bytes as UID.to_bytes; +/// Allows calling `.to_address` on a `UID` to get an `address`. +public use fun uid_to_address as UID.to_address; - /// The hardcoded ID for the singleton Sui System State Object. - const SUI_SYSTEM_STATE_OBJECT_ID: address = @0x5; +/// Allows calling `.to_bytes` on a `UID` to get a `vector`. +public use fun uid_to_bytes as UID.to_bytes; - /// The hardcoded ID for the singleton Clock Object. - const SUI_CLOCK_OBJECT_ID: address = @0x6; +/// The hardcoded ID for the singleton Sui System State Object. +const SUI_SYSTEM_STATE_OBJECT_ID: address = @0x5; - /// The hardcoded ID for the singleton AuthenticatorState Object. - const SUI_AUTHENTICATOR_STATE_ID: address = @0x7; +/// The hardcoded ID for the singleton Clock Object. +const SUI_CLOCK_OBJECT_ID: address = @0x6; - /// The hardcoded ID for the singleton Random Object. - const SUI_RANDOM_ID: address = @0x8; +/// The hardcoded ID for the singleton AuthenticatorState Object. +const SUI_AUTHENTICATOR_STATE_ID: address = @0x7; - /// The hardcoded ID for the singleton DenyList. - const SUI_DENY_LIST_OBJECT_ID: address = @0x403; +/// The hardcoded ID for the singleton Random Object. +const SUI_RANDOM_ID: address = @0x8; - /// The hardcoded ID for the Bridge Object. - const SUI_BRIDGE_ID: address = @0x9; +/// The hardcoded ID for the singleton DenyList. +const SUI_DENY_LIST_OBJECT_ID: address = @0x403; - /// Sender is not @0x0 the system address. - const ENotSystemAddress: u64 = 0; +/// The hardcoded ID for the Bridge Object. +const SUI_BRIDGE_ID: address = @0x9; - /// An object ID. This is used to reference Sui Objects. - /// This is *not* guaranteed to be globally unique--anyone can create an `ID` from a `UID` or - /// from an object, and ID's can be freely copied and dropped. - /// Here, the values are not globally unique because there can be multiple values of type `ID` - /// with the same underlying bytes. For example, `object::id(&obj)` can be called as many times - /// as you want for a given `obj`, and each `ID` value will be identical. - public struct ID has copy, drop, store { - // We use `address` instead of `vector` here because `address` has a more - // compact serialization. `address` is serialized as a BCS fixed-length sequence, - // which saves us the length prefix we would pay for if this were `vector`. - // See https://github.com/diem/bcs#fixed-and-variable-length-sequences. - bytes: address - } +/// Sender is not @0x0 the system address. +const ENotSystemAddress: u64 = 0; - /// Globally unique IDs that define an object's ID in storage. Any Sui Object, that is a struct - /// with the `key` ability, must have `id: UID` as its first field. - /// These are globally unique in the sense that no two values of type `UID` are ever equal, in - /// other words for any two values `id1: UID` and `id2: UID`, `id1` != `id2`. - /// This is a privileged type that can only be derived from a `TxContext`. - /// `UID` doesn't have the `drop` ability, so deleting a `UID` requires a call to `delete`. - public struct UID has store { - id: ID, - } +/// An object ID. This is used to reference Sui Objects. +/// This is *not* guaranteed to be globally unique--anyone can create an `ID` from a `UID` or +/// from an object, and ID's can be freely copied and dropped. +/// Here, the values are not globally unique because there can be multiple values of type `ID` +/// with the same underlying bytes. For example, `object::id(&obj)` can be called as many times +/// as you want for a given `obj`, and each `ID` value will be identical. +public struct ID has copy, drop, store { + // We use `address` instead of `vector` here because `address` has a more + // compact serialization. `address` is serialized as a BCS fixed-length sequence, + // which saves us the length prefix we would pay for if this were `vector`. + // See https://github.com/diem/bcs#fixed-and-variable-length-sequences. + bytes: address, +} - // === id === +/// Globally unique IDs that define an object's ID in storage. Any Sui Object, that is a struct +/// with the `key` ability, must have `id: UID` as its first field. +/// These are globally unique in the sense that no two values of type `UID` are ever equal, in +/// other words for any two values `id1: UID` and `id2: UID`, `id1` != `id2`. +/// This is a privileged type that can only be derived from a `TxContext`. +/// `UID` doesn't have the `drop` ability, so deleting a `UID` requires a call to `delete`. +public struct UID has store { + id: ID, +} - /// Get the raw bytes of a `ID` - public fun id_to_bytes(id: &ID): vector { - bcs::to_bytes(&id.bytes) - } +// === id === - /// Get the inner bytes of `id` as an address. - public fun id_to_address(id: &ID): address { - id.bytes - } +/// Get the raw bytes of a `ID` +public fun id_to_bytes(id: &ID): vector { + bcs::to_bytes(&id.bytes) +} - /// Make an `ID` from raw bytes. - public fun id_from_bytes(bytes: vector): ID { - address::from_bytes(bytes).to_id() - } +/// Get the inner bytes of `id` as an address. +public fun id_to_address(id: &ID): address { + id.bytes +} - /// Make an `ID` from an address. - public fun id_from_address(bytes: address): ID { - ID { bytes } - } +/// Make an `ID` from raw bytes. +public fun id_from_bytes(bytes: vector): ID { + address::from_bytes(bytes).to_id() +} - // === uid === +/// Make an `ID` from an address. +public fun id_from_address(bytes: address): ID { + ID { bytes } +} - #[allow(unused_function)] - /// Create the `UID` for the singleton `SuiSystemState` object. - /// This should only be called once from `sui_system`. - fun sui_system_state(ctx: &TxContext): UID { - assert!(ctx.sender() == @0x0, ENotSystemAddress); - UID { - id: ID { bytes: SUI_SYSTEM_STATE_OBJECT_ID }, - } - } +// === uid === - /// Create the `UID` for the singleton `Clock` object. - /// This should only be called once from `clock`. - public(package) fun clock(): UID { - UID { - id: ID { bytes: SUI_CLOCK_OBJECT_ID } - } +#[allow(unused_function)] +/// Create the `UID` for the singleton `SuiSystemState` object. +/// This should only be called once from `sui_system`. +fun sui_system_state(ctx: &TxContext): UID { + assert!(ctx.sender() == @0x0, ENotSystemAddress); + UID { + id: ID { bytes: SUI_SYSTEM_STATE_OBJECT_ID }, } +} - /// Create the `UID` for the singleton `AuthenticatorState` object. - /// This should only be called once from `authenticator_state`. - public(package) fun authenticator_state(): UID { - UID { - id: ID { bytes: SUI_AUTHENTICATOR_STATE_ID } - } +/// Create the `UID` for the singleton `Clock` object. +/// This should only be called once from `clock`. +public(package) fun clock(): UID { + UID { + id: ID { bytes: SUI_CLOCK_OBJECT_ID }, } +} - /// Create the `UID` for the singleton `Random` object. - /// This should only be called once from `random`. - public(package) fun randomness_state(): UID { - UID { - id: ID { bytes: SUI_RANDOM_ID } - } +/// Create the `UID` for the singleton `AuthenticatorState` object. +/// This should only be called once from `authenticator_state`. +public(package) fun authenticator_state(): UID { + UID { + id: ID { bytes: SUI_AUTHENTICATOR_STATE_ID }, } +} - /// Create the `UID` for the singleton `DenyList` object. - /// This should only be called once from `deny_list`. - public(package) fun sui_deny_list_object_id(): UID { - UID { - id: ID { bytes: SUI_DENY_LIST_OBJECT_ID } - } +/// Create the `UID` for the singleton `Random` object. +/// This should only be called once from `random`. +public(package) fun randomness_state(): UID { + UID { + id: ID { bytes: SUI_RANDOM_ID }, } +} - #[allow(unused_function)] - /// Create the `UID` for the singleton `Bridge` object. - /// This should only be called once from `bridge`. - fun bridge(): UID { - UID { - id: ID { bytes: SUI_BRIDGE_ID } - } +/// Create the `UID` for the singleton `DenyList` object. +/// This should only be called once from `deny_list`. +public(package) fun sui_deny_list_object_id(): UID { + UID { + id: ID { bytes: SUI_DENY_LIST_OBJECT_ID }, } +} - /// Get the inner `ID` of `uid` - public fun uid_as_inner(uid: &UID): &ID { - &uid.id +#[allow(unused_function)] +/// Create the `UID` for the singleton `Bridge` object. +/// This should only be called once from `bridge`. +fun bridge(): UID { + UID { + id: ID { bytes: SUI_BRIDGE_ID }, } +} - /// Get the raw bytes of a `uid`'s inner `ID` - public fun uid_to_inner(uid: &UID): ID { - uid.id - } +/// Get the inner `ID` of `uid` +public fun uid_as_inner(uid: &UID): &ID { + &uid.id +} - /// Get the raw bytes of a `UID` - public fun uid_to_bytes(uid: &UID): vector { - bcs::to_bytes(&uid.id.bytes) - } +/// Get the raw bytes of a `uid`'s inner `ID` +public fun uid_to_inner(uid: &UID): ID { + uid.id +} - /// Get the inner bytes of `id` as an address. - public fun uid_to_address(uid: &UID): address { - uid.id.bytes - } +/// Get the raw bytes of a `UID` +public fun uid_to_bytes(uid: &UID): vector { + bcs::to_bytes(&uid.id.bytes) +} - // === any object === +/// Get the inner bytes of `id` as an address. +public fun uid_to_address(uid: &UID): address { + uid.id.bytes +} - /// Create a new object. Returns the `UID` that must be stored in a Sui object. - /// This is the only way to create `UID`s. - public fun new(ctx: &mut TxContext): UID { - UID { - id: ID { bytes: ctx.fresh_object_address() }, - } - } +// === any object === - /// Delete the object and it's `UID`. This is the only way to eliminate a `UID`. - // This exists to inform Sui of object deletions. When an object - // gets unpacked, the programmer will have to do something with its - // `UID`. The implementation of this function emits a deleted - // system event so Sui knows to process the object deletion - public fun delete(id: UID) { - let UID { id: ID { bytes } } = id; - delete_impl(bytes) +/// Create a new object. Returns the `UID` that must be stored in a Sui object. +/// This is the only way to create `UID`s. +public fun new(ctx: &mut TxContext): UID { + UID { + id: ID { bytes: ctx.fresh_object_address() }, } +} - /// Get the underlying `ID` of `obj` - public fun id(obj: &T): ID { - borrow_uid(obj).id - } +/// Delete the object and it's `UID`. This is the only way to eliminate a `UID`. +// This exists to inform Sui of object deletions. When an object +// gets unpacked, the programmer will have to do something with its +// `UID`. The implementation of this function emits a deleted +// system event so Sui knows to process the object deletion +public fun delete(id: UID) { + let UID { id: ID { bytes } } = id; + delete_impl(bytes) +} - /// Borrow the underlying `ID` of `obj` - public fun borrow_id(obj: &T): &ID { - &borrow_uid(obj).id - } +/// Get the underlying `ID` of `obj` +public fun id(obj: &T): ID { + borrow_uid(obj).id +} - /// Get the raw bytes for the underlying `ID` of `obj` - public fun id_bytes(obj: &T): vector { - bcs::to_bytes(&borrow_uid(obj).id) - } +/// Borrow the underlying `ID` of `obj` +public fun borrow_id(obj: &T): &ID { + &borrow_uid(obj).id +} - /// Get the inner bytes for the underlying `ID` of `obj` - public fun id_address(obj: &T): address { - borrow_uid(obj).id.bytes - } +/// Get the raw bytes for the underlying `ID` of `obj` +public fun id_bytes(obj: &T): vector { + bcs::to_bytes(&borrow_uid(obj).id) +} - /// Get the `UID` for `obj`. - /// Safe because Sui has an extra bytecode verifier pass that forces every struct with - /// the `key` ability to have a distinguished `UID` field. - /// Cannot be made public as the access to `UID` for a given object must be privileged, and - /// restrictable in the object's module. - native fun borrow_uid(obj: &T): &UID; - - /// Generate a new UID specifically used for creating a UID from a hash - public(package) fun new_uid_from_hash(bytes: address): UID { - record_new_uid(bytes); - UID { id: ID { bytes } } - } +/// Get the inner bytes for the underlying `ID` of `obj` +public fun id_address(obj: &T): address { + borrow_uid(obj).id.bytes +} - // === internal functions === +/// Get the `UID` for `obj`. +/// Safe because Sui has an extra bytecode verifier pass that forces every struct with +/// the `key` ability to have a distinguished `UID` field. +/// Cannot be made public as the access to `UID` for a given object must be privileged, and +/// restrictable in the object's module. +native fun borrow_uid(obj: &T): &UID; + +/// Generate a new UID specifically used for creating a UID from a hash +public(package) fun new_uid_from_hash(bytes: address): UID { + record_new_uid(bytes); + UID { id: ID { bytes } } +} - // helper for delete - native fun delete_impl(id: address); +// === internal functions === - // marks newly created UIDs from hash - native fun record_new_uid(id: address); +// helper for delete +native fun delete_impl(id: address); - #[test_only] - /// Return the most recent created object ID. - public fun last_created(ctx: &TxContext): ID { - ID { bytes: ctx.last_created_object_id() } - } +// marks newly created UIDs from hash +native fun record_new_uid(id: address); +#[test_only] +/// Return the most recent created object ID. +public fun last_created(ctx: &TxContext): ID { + ID { bytes: ctx.last_created_object_id() } } diff --git a/crates/sui-framework/packages/sui-framework/sources/package.move b/crates/sui-framework/packages/sui-framework/sources/package.move index 85917a647c9d4..4ef8990662b7c 100644 --- a/crates/sui-framework/packages/sui-framework/sources/package.move +++ b/crates/sui-framework/packages/sui-framework/sources/package.move @@ -4,355 +4,351 @@ /// Functions for operating on Move packages from within Move: /// - Creating proof-of-publish objects from one-time witnesses /// - Administering package upgrades through upgrade policies. -module sui::package { - use std::ascii::String; - use std::type_name; - use sui::types; - - /// Allows calling `.burn` to destroy a `Publisher`. - public use fun burn_publisher as Publisher.burn; - - /// Allows calling `.module_` to access the name of the module a - /// `Publisher` was derived from. - public use fun published_module as Publisher.module_; - - /// Allows calling `.package` to access the address of the package - /// a `Publisher` was derived from. - public use fun published_package as Publisher.package; - - /// Allows calling `.package` to access the package this cap - /// authorizes upgrades for. - public use fun upgrade_package as UpgradeCap.package; - - /// Allows calling `.policy` to access the most permissive kind of - /// upgrade this cap will authorize. - public use fun upgrade_policy as UpgradeCap.policy; - - /// Allows calling `.authorize` to initiate an upgrade. - public use fun authorize_upgrade as UpgradeCap.authorize; - - /// Allows calling `.commit` to finalize an upgrade. - public use fun commit_upgrade as UpgradeCap.commit; - - /// Allows calling `.package` to access the package this ticket - /// authorizes an upgrade for. - public use fun ticket_package as UpgradeTicket.package; - - /// Allows calling `.policy` to access the kind of upgrade this - /// ticket authorizes. - public use fun ticket_policy as UpgradeTicket.policy; - - /// Allows calling `.digest` to access the digest of the bytecode - /// used for this upgrade. - public use fun ticket_digest as UpgradeTicket.digest; - - /// Allows calling `.cap` to fetch the ID of the cap this receipt - /// should be applied to. - public use fun receipt_cap as UpgradeReceipt.cap; - - /// Allows calling `.package` to fetch the ID of the package after - /// upgrade. - public use fun receipt_package as UpgradeReceipt.package; - - /// 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; - /// This `UpgradeCap` has already authorized a pending upgrade. - const EAlreadyAuthorized: u64 = 2; - /// This `UpgradeCap` has not authorized an upgrade. - const ENotAuthorized: u64 = 3; - /// Trying to commit an upgrade to the wrong `UpgradeCap`. - const EWrongUpgradeCap: u64 = 4; - - /// Update any part of the package (function implementations, add new - /// functions or types, change dependencies) - const COMPATIBLE: u8 = 0; - /// Add new functions or types, or change dependencies, existing - /// functions can't change. - const ADDITIVE: u8 = 128; - /// Only be able to change dependencies. - const DEP_ONLY: u8 = 192; - - /// 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. - public struct Publisher has key, store { - id: UID, - package: String, - module_name: String, - } +module sui::package; + +use std::ascii::String; +use std::type_name; +use sui::types; + +/// Allows calling `.burn` to destroy a `Publisher`. +public use fun burn_publisher as Publisher.burn; + +/// Allows calling `.module_` to access the name of the module a +/// `Publisher` was derived from. +public use fun published_module as Publisher.module_; + +/// Allows calling `.package` to access the address of the package +/// a `Publisher` was derived from. +public use fun published_package as Publisher.package; + +/// Allows calling `.package` to access the package this cap +/// authorizes upgrades for. +public use fun upgrade_package as UpgradeCap.package; + +/// Allows calling `.policy` to access the most permissive kind of +/// upgrade this cap will authorize. +public use fun upgrade_policy as UpgradeCap.policy; + +/// Allows calling `.authorize` to initiate an upgrade. +public use fun authorize_upgrade as UpgradeCap.authorize; + +/// Allows calling `.commit` to finalize an upgrade. +public use fun commit_upgrade as UpgradeCap.commit; + +/// Allows calling `.package` to access the package this ticket +/// authorizes an upgrade for. +public use fun ticket_package as UpgradeTicket.package; + +/// Allows calling `.policy` to access the kind of upgrade this +/// ticket authorizes. +public use fun ticket_policy as UpgradeTicket.policy; + +/// Allows calling `.digest` to access the digest of the bytecode +/// used for this upgrade. +public use fun ticket_digest as UpgradeTicket.digest; + +/// Allows calling `.cap` to fetch the ID of the cap this receipt +/// should be applied to. +public use fun receipt_cap as UpgradeReceipt.cap; + +/// Allows calling `.package` to fetch the ID of the package after +/// upgrade. +public use fun receipt_package as UpgradeReceipt.package; + +/// 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; +/// This `UpgradeCap` has already authorized a pending upgrade. +const EAlreadyAuthorized: u64 = 2; +/// This `UpgradeCap` has not authorized an upgrade. +const ENotAuthorized: u64 = 3; +/// Trying to commit an upgrade to the wrong `UpgradeCap`. +const EWrongUpgradeCap: u64 = 4; + +/// Update any part of the package (function implementations, add new +/// functions or types, change dependencies) +const COMPATIBLE: u8 = 0; +/// Add new functions or types, or change dependencies, existing +/// functions can't change. +const ADDITIVE: u8 = 128; +/// Only be able to change dependencies. +const DEP_ONLY: u8 = 192; + +/// 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. +public struct Publisher has key, store { + id: UID, + package: String, + module_name: String, +} - /// Capability controlling the ability to upgrade a package. - public struct UpgradeCap has key, store { - id: UID, - /// (Mutable) ID of the package that can be upgraded. - package: ID, - /// (Mutable) The number of upgrades that have been applied - /// successively to the original package. Initially 0. - version: u64, - /// What kind of upgrades are allowed. - policy: u8, - } +/// Capability controlling the ability to upgrade a package. +public struct UpgradeCap has key, store { + id: UID, + /// (Mutable) ID of the package that can be upgraded. + package: ID, + /// (Mutable) The number of upgrades that have been applied + /// successively to the original package. Initially 0. + version: u64, + /// What kind of upgrades are allowed. + policy: u8, +} - /// 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. - public struct UpgradeTicket { - /// (Immutable) ID of the `UpgradeCap` this originated from. - cap: ID, - /// (Immutable) ID of the package that can be upgraded. - package: ID, - /// (Immutable) The policy regarding what kind of upgrade this ticket - /// permits. - policy: u8, - /// (Immutable) SHA256 digest of the bytecode and transitive - /// dependencies that will be used in the upgrade. - digest: vector, - } +/// 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. +public struct UpgradeTicket { + /// (Immutable) ID of the `UpgradeCap` this originated from. + cap: ID, + /// (Immutable) ID of the package that can be upgraded. + package: ID, + /// (Immutable) The policy regarding what kind of upgrade this ticket + /// permits. + policy: u8, + /// (Immutable) SHA256 digest of the bytecode and transitive + /// dependencies that will be used in the upgrade. + digest: vector, +} - /// 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. - public struct UpgradeReceipt { - /// (Immutable) ID of the `UpgradeCap` this originated from. - cap: ID, - /// (Immutable) ID of the package after it was upgraded. - package: ID, - } +/// 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. +public struct UpgradeReceipt { + /// (Immutable) ID of the `UpgradeCap` this originated from. + cap: ID, + /// (Immutable) ID of the package after it was upgraded. + package: ID, +} - /// 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: OTW, ctx: &mut TxContext): Publisher { - assert!(types::is_one_time_witness(&otw), ENotOneTimeWitness); +/// 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: OTW, ctx: &mut TxContext): Publisher { + assert!(types::is_one_time_witness(&otw), ENotOneTimeWitness); - let tyname = type_name::get_with_original_ids(); + let tyname = type_name::get_with_original_ids(); - Publisher { - id: object::new(ctx), - package: tyname.get_address(), - module_name: tyname.get_module(), - } + Publisher { + id: object::new(ctx), + package: tyname.get_address(), + module_name: tyname.get_module(), } +} - #[allow(lint(self_transfer))] - /// 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: OTW, ctx: &mut TxContext) { - sui::transfer::public_transfer(claim(otw, ctx), ctx.sender()) - } +#[allow(lint(self_transfer))] +/// 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: OTW, ctx: &mut TxContext) { + sui::transfer::public_transfer(claim(otw, ctx), ctx.sender()) +} - /// Destroy a Publisher object effectively removing all privileges - /// associated with it. - public fun burn_publisher(self: Publisher) { - let Publisher { id, package: _, module_name: _ } = self; - id.delete(); - } +/// Destroy a Publisher object effectively removing all privileges +/// associated with it. +public fun burn_publisher(self: Publisher) { + let Publisher { id, package: _, module_name: _ } = self; + id.delete(); +} - /// Check whether type belongs to the same package as the publisher object. - public fun from_package(self: &Publisher): bool { - type_name::get_with_original_ids().get_address() == self.package - } +/// Check whether type belongs to the same package as the publisher object. +public fun from_package(self: &Publisher): bool { + type_name::get_with_original_ids().get_address() == self.package +} - /// Check whether a type belongs to the same module as the publisher object. - public fun from_module(self: &Publisher): bool { - let tyname = type_name::get_with_original_ids(); +/// Check whether a type belongs to the same module as the publisher object. +public fun from_module(self: &Publisher): bool { + let tyname = type_name::get_with_original_ids(); - (tyname.get_address() == self.package) && (tyname.get_module() == self.module_name) - } + (tyname.get_address() == self.package) && (tyname.get_module() == self.module_name) +} - /// Read the name of the module. - public fun published_module(self: &Publisher): &String { - &self.module_name - } +/// Read the name of the module. +public fun published_module(self: &Publisher): &String { + &self.module_name +} - /// Read the package address string. - public fun published_package(self: &Publisher): &String { - &self.package - } +/// Read the package address string. +public fun published_package(self: &Publisher): &String { + &self.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: &UpgradeCap): ID { - cap.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: &UpgradeCap): ID { + cap.package +} - /// The most recent version of the package, increments by one for each - /// successfully applied upgrade. - public fun version(cap: &UpgradeCap): u64 { - cap.version - } +/// The most recent version of the package, increments by one for each +/// successfully applied upgrade. +public fun version(cap: &UpgradeCap): u64 { + cap.version +} - /// The most permissive kind of upgrade currently supported by this - /// `cap`. - public fun upgrade_policy(cap: &UpgradeCap): u8 { - cap.policy - } +/// The most permissive kind of upgrade currently supported by this +/// `cap`. +public fun upgrade_policy(cap: &UpgradeCap): u8 { + cap.policy +} - /// The package that this ticket is authorized to upgrade - public fun ticket_package(ticket: &UpgradeTicket): ID { - ticket.package - } +/// The package that this ticket is authorized to upgrade +public fun ticket_package(ticket: &UpgradeTicket): ID { + ticket.package +} - /// The kind of upgrade that this ticket authorizes. - public fun ticket_policy(ticket: &UpgradeTicket): u8 { - ticket.policy - } +/// The kind of upgrade that this ticket authorizes. +public fun ticket_policy(ticket: &UpgradeTicket): u8 { + ticket.policy +} - /// ID of the `UpgradeCap` that this `receipt` should be used to - /// update. - public fun receipt_cap(receipt: &UpgradeReceipt): ID { - receipt.cap - } +/// ID of the `UpgradeCap` that this `receipt` should be used to +/// update. +public fun receipt_cap(receipt: &UpgradeReceipt): ID { + receipt.cap +} - /// 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: &UpgradeReceipt): ID { - 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: &UpgradeReceipt): ID { + receipt.package +} - /// 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: &UpgradeTicket): &vector { - &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: &UpgradeTicket): &vector { + &ticket.digest +} - /// Expose the constants representing various upgrade policies - public fun compatible_policy(): u8 { COMPATIBLE } - public fun additive_policy(): u8 { ADDITIVE } - public fun dep_only_policy(): u8 { DEP_ONLY } +/// Expose the constants representing various upgrade policies +public fun compatible_policy(): u8 { COMPATIBLE } - /// Restrict upgrades through this upgrade `cap` to just add code, or - /// change dependencies. - public entry fun only_additive_upgrades(cap: &mut UpgradeCap) { - cap.restrict(ADDITIVE) - } +public fun additive_policy(): u8 { ADDITIVE } - /// Restrict upgrades through this upgrade `cap` to just change - /// dependencies. - public entry fun only_dep_upgrades(cap: &mut UpgradeCap) { - cap.restrict(DEP_ONLY) - } +public fun dep_only_policy(): u8 { DEP_ONLY } - /// Discard the `UpgradeCap` to make a package immutable. - public entry fun make_immutable(cap: UpgradeCap) { - let UpgradeCap { id, package: _, version: _, policy: _ } = cap; - id.delete(); - } +/// Restrict upgrades through this upgrade `cap` to just add code, or +/// change dependencies. +public entry fun only_additive_upgrades(cap: &mut UpgradeCap) { + cap.restrict(ADDITIVE) +} + +/// Restrict upgrades through this upgrade `cap` to just change +/// dependencies. +public entry fun only_dep_upgrades(cap: &mut UpgradeCap) { + cap.restrict(DEP_ONLY) +} - /// 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 UpgradeCap, - policy: u8, - digest: vector - ): 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, - } +/// Discard the `UpgradeCap` to make a package immutable. +public entry fun make_immutable(cap: UpgradeCap) { + let UpgradeCap { id, package: _, version: _, policy: _ } = cap; + id.delete(); +} + +/// 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 UpgradeCap, policy: u8, digest: vector): 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, } +} - /// Consume an `UpgradeReceipt` to update its `UpgradeCap`, finalizing - /// the upgrade. - public fun commit_upgrade( - cap: &mut UpgradeCap, - receipt: UpgradeReceipt, - ) { - let UpgradeReceipt { cap: cap_id, package } = receipt; +/// Consume an `UpgradeReceipt` to update its `UpgradeCap`, finalizing +/// the upgrade. +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); + assert!(object::id(cap) == cap_id, EWrongUpgradeCap); + assert!(cap.package.to_address() == @0x0, ENotAuthorized); - cap.package = package; - cap.version = cap.version + 1; - } + cap.package = package; + cap.version = cap.version + 1; +} - #[test_only] - /// Test-only function to claim a Publisher object bypassing OTW check. - public fun test_claim(_: OTW, ctx: &mut TxContext): Publisher { - let tyname = type_name::get_with_original_ids(); +#[test_only] +/// Test-only function to claim a Publisher object bypassing OTW check. +public fun test_claim(_: OTW, ctx: &mut TxContext): Publisher { + let tyname = type_name::get_with_original_ids(); - Publisher { - id: object::new(ctx), - package: tyname.get_address(), - module_name: tyname.get_module(), - } + Publisher { + id: object::new(ctx), + package: tyname.get_address(), + module_name: tyname.get_module(), } +} - #[test_only] - /// Test-only function to simulate publishing a package at address - /// `ID`, to create an `UpgradeCap`. - public fun test_publish(package: ID, ctx: &mut TxContext): UpgradeCap { - UpgradeCap { - id: object::new(ctx), - package, - version: 1, - policy: COMPATIBLE, - } +#[test_only] +/// Test-only function to simulate publishing a package at address +/// `ID`, to create an `UpgradeCap`. +public fun test_publish(package: ID, ctx: &mut TxContext): UpgradeCap { + UpgradeCap { + id: object::new(ctx), + package, + version: 1, + policy: COMPATIBLE, } +} - #[test_only] - /// Test-only function that takes the role of the actual `Upgrade` - /// command, converting the ticket for the pending upgrade to a - /// receipt for a completed upgrade. - public fun test_upgrade(ticket: UpgradeTicket): UpgradeReceipt { - let UpgradeTicket { cap, package, policy: _, digest: _ } = ticket; - - // Generate a fake package ID for the upgraded package by - // hashing the existing package and cap ID. - let mut data = cap.to_bytes(); - data.append(package.to_bytes()); - let package = object::id_from_bytes(sui::hash::blake2b256(&data)); - - UpgradeReceipt { - cap, package - } +#[test_only] +/// Test-only function that takes the role of the actual `Upgrade` +/// command, converting the ticket for the pending upgrade to a +/// receipt for a completed upgrade. +public fun test_upgrade(ticket: UpgradeTicket): UpgradeReceipt { + let UpgradeTicket { cap, package, policy: _, digest: _ } = ticket; + + // Generate a fake package ID for the upgraded package by + // hashing the existing package and cap ID. + let mut data = cap.to_bytes(); + data.append(package.to_bytes()); + let package = object::id_from_bytes(sui::hash::blake2b256(&data)); + + UpgradeReceipt { + cap, + package, } +} - fun restrict(cap: &mut UpgradeCap, policy: u8) { - assert!(cap.policy <= policy, ETooPermissive); - cap.policy = policy; - } +fun restrict(cap: &mut UpgradeCap, policy: u8) { + assert!(cap.policy <= policy, ETooPermissive); + cap.policy = policy; } diff --git a/crates/sui-framework/packages/sui-framework/sources/pay.move b/crates/sui-framework/packages/sui-framework/sources/pay.move index a13bab88c68c6..f161e935bcfb8 100644 --- a/crates/sui-framework/packages/sui-framework/sources/pay.move +++ b/crates/sui-framework/packages/sui-framework/sources/pay.move @@ -2,86 +2,82 @@ // SPDX-License-Identifier: Apache-2.0 /// This module provides handy functionality for wallets and `sui::Coin` management. -module sui::pay { - use sui::coin::Coin; +module sui::pay; - /// For when empty vector is supplied into join function. - const ENoCoins: u64 = 0; +use sui::coin::Coin; - #[allow(lint(self_transfer))] - /// Transfer `c` to the sender of the current transaction - public fun keep(c: Coin, ctx: &TxContext) { - transfer::public_transfer(c, ctx.sender()) - } +/// For when empty vector is supplied into join function. +const ENoCoins: u64 = 0; - /// Split coin `self` to two coins, one with balance `split_amount`, - /// and the remaining balance is left is `self`. - public entry fun split( - coin: &mut Coin, split_amount: u64, ctx: &mut TxContext - ) { - keep(coin.split(split_amount, ctx), ctx) - } +#[allow(lint(self_transfer))] +/// Transfer `c` to the sender of the current transaction +public fun keep(c: Coin, ctx: &TxContext) { + transfer::public_transfer(c, ctx.sender()) +} - /// Split coin `self` into multiple coins, each with balance specified - /// in `split_amounts`. Remaining balance is left in `self`. - public entry fun split_vec( - self: &mut Coin, split_amounts: vector, ctx: &mut TxContext - ) { - let (mut i, len) = (0, split_amounts.length()); - while (i < len) { - split(self, split_amounts[i], ctx); - i = i + 1; - }; - } +/// Split coin `self` to two coins, one with balance `split_amount`, +/// and the remaining balance is left is `self`. +public entry fun split(coin: &mut Coin, split_amount: u64, ctx: &mut TxContext) { + keep(coin.split(split_amount, ctx), ctx) +} - /// Send `amount` units of `c` to `recipient` - /// Aborts with `EVALUE` if `amount` is greater than or equal to `amount` - public entry fun split_and_transfer( - c: &mut Coin, amount: u64, recipient: address, ctx: &mut TxContext - ) { - transfer::public_transfer(c.split(amount, ctx), recipient) - } +/// Split coin `self` into multiple coins, each with balance specified +/// in `split_amounts`. Remaining balance is left in `self`. +public entry fun split_vec(self: &mut Coin, split_amounts: vector, ctx: &mut TxContext) { + let (mut i, len) = (0, split_amounts.length()); + while (i < len) { + split(self, split_amounts[i], ctx); + i = i + 1; + }; +} +/// Send `amount` units of `c` to `recipient` +/// Aborts with `EVALUE` if `amount` is greater than or equal to `amount` +public entry fun split_and_transfer( + c: &mut Coin, + amount: u64, + recipient: address, + ctx: &mut TxContext, +) { + transfer::public_transfer(c.split(amount, ctx), recipient) +} - #[allow(lint(self_transfer))] - /// Divide coin `self` into `n - 1` coins with equal balances. If the balance is - /// not evenly divisible by `n`, the remainder is left in `self`. - public entry fun divide_and_keep( - self: &mut Coin, n: u64, ctx: &mut TxContext - ) { - let mut vec: vector> = self.divide_into_n(n, ctx); - let (mut i, len) = (0, vec.length()); - while (i < len) { - transfer::public_transfer(vec.pop_back(), ctx.sender()); - i = i + 1; - }; - vec.destroy_empty(); - } +#[allow(lint(self_transfer))] +/// Divide coin `self` into `n - 1` coins with equal balances. If the balance is +/// not evenly divisible by `n`, the remainder is left in `self`. +public entry fun divide_and_keep(self: &mut Coin, n: u64, ctx: &mut TxContext) { + let mut vec: vector> = self.divide_into_n(n, ctx); + let (mut i, len) = (0, vec.length()); + while (i < len) { + transfer::public_transfer(vec.pop_back(), ctx.sender()); + i = i + 1; + }; + vec.destroy_empty(); +} - /// Join `coin` into `self`. Re-exports `coin::join` function. - /// Deprecated: you should call `coin.join(other)` directly. - public entry fun join(self: &mut Coin, coin: Coin) { - self.join(coin) - } +/// Join `coin` into `self`. Re-exports `coin::join` function. +/// Deprecated: you should call `coin.join(other)` directly. +public entry fun join(self: &mut Coin, coin: Coin) { + self.join(coin) +} - /// Join everything in `coins` with `self` - public entry fun join_vec(self: &mut Coin, mut coins: vector>) { - let (mut i, len) = (0, coins.length()); - while (i < len) { - let coin = coins.pop_back(); - self.join(coin); - i = i + 1 - }; - // safe because we've drained the vector - coins.destroy_empty() - } +/// Join everything in `coins` with `self` +public entry fun join_vec(self: &mut Coin, mut coins: vector>) { + let (mut i, len) = (0, coins.length()); + while (i < len) { + let coin = coins.pop_back(); + self.join(coin); + i = i + 1 + }; + // safe because we've drained the vector + coins.destroy_empty() +} - /// Join a vector of `Coin` into a single object and transfer it to `receiver`. - public entry fun join_vec_and_transfer(mut coins: vector>, receiver: address) { - assert!(coins.length() > 0, ENoCoins); +/// Join a vector of `Coin` into a single object and transfer it to `receiver`. +public entry fun join_vec_and_transfer(mut coins: vector>, receiver: address) { + assert!(coins.length() > 0, ENoCoins); - let mut self = coins.pop_back(); - join_vec(&mut self, coins); - transfer::public_transfer(self, receiver) - } + let mut self = coins.pop_back(); + join_vec(&mut self, coins); + transfer::public_transfer(self, receiver) } diff --git a/crates/sui-framework/packages/sui-framework/sources/prover.move b/crates/sui-framework/packages/sui-framework/sources/prover.move index e52feb4826479..6c06173ef87a9 100644 --- a/crates/sui-framework/packages/sui-framework/sources/prover.move +++ b/crates/sui-framework/packages/sui-framework/sources/prover.move @@ -1,5 +1,4 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -module sui::prover { -} +module sui::prover; diff --git a/crates/sui-framework/packages/sui-framework/sources/random.move b/crates/sui-framework/packages/sui-framework/sources/random.move index 8d7cdf10025d7..0e687c216d80e 100644 --- a/crates/sui-framework/packages/sui-framework/sources/random.move +++ b/crates/sui-framework/packages/sui-framework/sources/random.move @@ -2,325 +2,320 @@ // SPDX-License-Identifier: Apache-2.0 /// This module provides functionality for generating secure randomness. -module sui::random { - use std::bcs; - use sui::hmac::hmac_sha3_256; - use sui::versioned::{Self, Versioned}; - - // Sender is not @0x0 the system address. - const ENotSystemAddress: u64 = 0; - const EWrongInnerVersion: u64 = 1; - const EInvalidRandomnessUpdate: u64 = 2; - const EInvalidRange: u64 = 3; - const EInvalidLength: u64 = 4; - - const CURRENT_VERSION: u64 = 1; - const RAND_OUTPUT_LEN: u16 = 32; - const U16_MAX: u64 = 0xFFFF; - - /// Singleton shared object which stores the global randomness state. - /// The actual state is stored in a versioned inner field. - public struct Random has key { - id: UID, - // The inner object must never be accessed outside this module as it could be used for accessing global - // randomness via deserialization of RandomInner. - inner: Versioned, - } - - public struct RandomInner has store { - version: u64, - epoch: u64, - randomness_round: u64, - random_bytes: vector, - } - - #[allow(unused_function)] - /// Create and share the Random object. This function is called exactly once, when - /// the Random object is first created. - /// Can only be called by genesis or change_epoch transactions. - fun create(ctx: &mut TxContext) { - assert!(ctx.sender() == @0x0, ENotSystemAddress); - - let version = CURRENT_VERSION; - - let inner = RandomInner { - version, - epoch: ctx.epoch(), - randomness_round: 0, - random_bytes: vector[], - }; - - let self = Random { - id: object::randomness_state(), - inner: versioned::create(version, inner, ctx), - }; - transfer::share_object(self); - } - - #[test_only] - public fun create_for_testing(ctx: &mut TxContext) { - create(ctx); - } - - fun load_inner_mut( - self: &mut Random, - ): &mut RandomInner { - let version = versioned::version(&self.inner); - - // Replace this with a lazy update function when we add a new version of the inner object. - assert!(version == CURRENT_VERSION, EWrongInnerVersion); - let inner: &mut RandomInner = versioned::load_value_mut(&mut self.inner); - assert!(inner.version == version, EWrongInnerVersion); - inner - } - - fun load_inner( - self: &Random, - ): &RandomInner { - let version = versioned::version(&self.inner); - - // Replace this with a lazy update function when we add a new version of the inner object. - assert!(version == CURRENT_VERSION, EWrongInnerVersion); - let inner: &RandomInner = versioned::load_value(&self.inner); - assert!(inner.version == version, EWrongInnerVersion); - inner - } - - #[allow(unused_function)] - /// Record new randomness. Called when executing the RandomnessStateUpdate system - /// transaction. - fun update_randomness_state( - self: &mut Random, - new_round: u64, - new_bytes: vector, - ctx: &TxContext, - ) { - // Validator will make a special system call with sender set as 0x0. - assert!(ctx.sender() == @0x0, ENotSystemAddress); - - // Randomness should only be incremented. - let epoch = ctx.epoch(); - let inner = self.load_inner_mut(); - if (inner.randomness_round == 0 && inner.epoch == 0 && inner.random_bytes.is_empty()) { - // First update should be for round zero. - assert!(new_round == 0, EInvalidRandomnessUpdate); - } else { - // Subsequent updates should either increase epoch or increment randomness_round. - // Note that epoch may increase by more than 1 if an epoch is completed without - // randomness ever being generated in that epoch. - assert!( - (epoch > inner.epoch && new_round == 0) || +module sui::random; + +use std::bcs; +use sui::hmac::hmac_sha3_256; +use sui::versioned::{Self, Versioned}; + +// Sender is not @0x0 the system address. +const ENotSystemAddress: u64 = 0; +const EWrongInnerVersion: u64 = 1; +const EInvalidRandomnessUpdate: u64 = 2; +const EInvalidRange: u64 = 3; +const EInvalidLength: u64 = 4; + +const CURRENT_VERSION: u64 = 1; +const RAND_OUTPUT_LEN: u16 = 32; +const U16_MAX: u64 = 0xFFFF; + +/// Singleton shared object which stores the global randomness state. +/// The actual state is stored in a versioned inner field. +public struct Random has key { + id: UID, + // The inner object must never be accessed outside this module as it could be used for accessing global + // randomness via deserialization of RandomInner. + inner: Versioned, +} + +public struct RandomInner has store { + version: u64, + epoch: u64, + randomness_round: u64, + random_bytes: vector, +} + +#[allow(unused_function)] +/// Create and share the Random object. This function is called exactly once, when +/// the Random object is first created. +/// Can only be called by genesis or change_epoch transactions. +fun create(ctx: &mut TxContext) { + assert!(ctx.sender() == @0x0, ENotSystemAddress); + + let version = CURRENT_VERSION; + + let inner = RandomInner { + version, + epoch: ctx.epoch(), + randomness_round: 0, + random_bytes: vector[], + }; + + let self = Random { + id: object::randomness_state(), + inner: versioned::create(version, inner, ctx), + }; + transfer::share_object(self); +} + +#[test_only] +public fun create_for_testing(ctx: &mut TxContext) { + create(ctx); +} + +fun load_inner_mut(self: &mut Random): &mut RandomInner { + let version = versioned::version(&self.inner); + + // Replace this with a lazy update function when we add a new version of the inner object. + assert!(version == CURRENT_VERSION, EWrongInnerVersion); + let inner: &mut RandomInner = versioned::load_value_mut(&mut self.inner); + assert!(inner.version == version, EWrongInnerVersion); + inner +} + +fun load_inner(self: &Random): &RandomInner { + let version = versioned::version(&self.inner); + + // Replace this with a lazy update function when we add a new version of the inner object. + assert!(version == CURRENT_VERSION, EWrongInnerVersion); + let inner: &RandomInner = versioned::load_value(&self.inner); + assert!(inner.version == version, EWrongInnerVersion); + inner +} + +#[allow(unused_function)] +/// Record new randomness. Called when executing the RandomnessStateUpdate system +/// transaction. +fun update_randomness_state( + self: &mut Random, + new_round: u64, + new_bytes: vector, + ctx: &TxContext, +) { + // Validator will make a special system call with sender set as 0x0. + assert!(ctx.sender() == @0x0, ENotSystemAddress); + + // Randomness should only be incremented. + let epoch = ctx.epoch(); + let inner = self.load_inner_mut(); + if (inner.randomness_round == 0 && inner.epoch == 0 && inner.random_bytes.is_empty()) { + // First update should be for round zero. + assert!(new_round == 0, EInvalidRandomnessUpdate); + } else { + // Subsequent updates should either increase epoch or increment randomness_round. + // Note that epoch may increase by more than 1 if an epoch is completed without + // randomness ever being generated in that epoch. + assert!( + (epoch > inner.epoch && new_round == 0) || (new_round == inner.randomness_round + 1), - EInvalidRandomnessUpdate - ); - }; - - inner.epoch = ctx.epoch(); - inner.randomness_round = new_round; - inner.random_bytes = new_bytes; - } - - #[test_only] - public fun update_randomness_state_for_testing( - self: &mut Random, - new_round: u64, - new_bytes: vector, - ctx: &TxContext, - ) { - self.update_randomness_state(new_round, new_bytes, ctx); - } - - - /// Unique randomness generator, derived from the global randomness. - public struct RandomGenerator has drop { - seed: vector, - counter: u16, - buffer: vector, - } - - /// Create a generator. Can be used to derive up to MAX_U16 * 32 random bytes. - public fun new_generator(r: &Random, ctx: &mut TxContext): RandomGenerator { - let inner = load_inner(r); - let seed = hmac_sha3_256( - &inner.random_bytes, - &ctx.fresh_object_address().to_bytes() + EInvalidRandomnessUpdate, ); - RandomGenerator { seed, counter: 0, buffer: vector[] } - } - - // Get the next block of random bytes. - fun derive_next_block(g: &mut RandomGenerator): vector { - g.counter = g.counter + 1; - hmac_sha3_256(&g.seed, &bcs::to_bytes(&g.counter)) - } - - // Fill the generator's buffer with 32 random bytes. - fun fill_buffer(g: &mut RandomGenerator) { - let next_block = derive_next_block(g); - vector::append(&mut g.buffer, next_block); - } - - /// Generate n random bytes. - public fun generate_bytes(g: &mut RandomGenerator, num_of_bytes: u16): vector { - let mut result = vector[]; - // Append RAND_OUTPUT_LEN size buffers directly without going through the generator's buffer. - let mut num_of_blocks = num_of_bytes / RAND_OUTPUT_LEN; - while (num_of_blocks > 0) { - vector::append(&mut result, derive_next_block(g)); - num_of_blocks = num_of_blocks - 1; - }; - // Fill the generator's buffer if needed. - let num_of_bytes = num_of_bytes as u64; - if (vector::length(&g.buffer) < (num_of_bytes - vector::length(&result))) { - fill_buffer(g); - }; - // Take remaining bytes from the generator's buffer. - while (vector::length(&result) < num_of_bytes) { - vector::push_back(&mut result, vector::pop_back(&mut g.buffer)); - }; - result - } - - // Helper function that extracts the given number of bytes from the random generator and returns it as u256. - // Assumes that the caller has already checked that num_of_bytes is valid. - // TODO: Replace with a macro when we have support for it. - fun u256_from_bytes(g: &mut RandomGenerator, num_of_bytes: u8): u256 { - if (vector::length(&g.buffer) < num_of_bytes as u64) { - fill_buffer(g); - }; - let mut result: u256 = 0; - let mut i = 0; - while (i < num_of_bytes) { - let byte = vector::pop_back(&mut g.buffer); - result = (result << 8) + (byte as u256); - i = i + 1; - }; - result - } - - /// Generate a u256. - public fun generate_u256(g: &mut RandomGenerator): u256 { - u256_from_bytes(g, 32) - } - - /// Generate a u128. - public fun generate_u128(g: &mut RandomGenerator): u128 { - u256_from_bytes(g, 16) as u128 - } - - /// Generate a u64. - public fun generate_u64(g: &mut RandomGenerator): u64 { - u256_from_bytes(g, 8) as u64 - } - - /// Generate a u32. - public fun generate_u32(g: &mut RandomGenerator): u32 { - u256_from_bytes(g, 4) as u32 - } - - /// Generate a u16. - public fun generate_u16(g: &mut RandomGenerator): u16 { - u256_from_bytes(g, 2) as u16 - } - - /// Generate a u8. - public fun generate_u8(g: &mut RandomGenerator): u8 { - u256_from_bytes(g, 1) as u8 - } - - /// Generate a boolean. - public fun generate_bool(g: &mut RandomGenerator): bool { - (u256_from_bytes(g, 1) & 1) == 1 - } - - // Helper function to generate a random u128 in [min, max] using a random number with num_of_bytes bytes. - // Assumes that the caller verified the inputs, and uses num_of_bytes to control the bias (e.g., 8 bytes larger - // than the actual type used by the caller function to limit the bias by 2^{-64}). - // TODO: Replace with a macro when we have support for it. - fun u128_in_range(g: &mut RandomGenerator, min: u128, max: u128, num_of_bytes: u8): u128 { - assert!(min <= max, EInvalidRange); - if (min == max) { - return min - }; - // Pick a random number in [0, max - min] by generating a random number that is larger than max-min, and taking - // the modulo of the random number by the range size. Then add the min to the result to get a number in - // [min, max]. - let range_size = (max - min) as u256 + 1; - let rand = u256_from_bytes(g, num_of_bytes); - min + (rand % range_size as u128) - } - - /// Generate a random u128 in [min, max] (with a bias of 2^{-64}). - public fun generate_u128_in_range(g: &mut RandomGenerator, min: u128, max: u128): u128 { - u128_in_range(g, min, max, 24) - } - - //// Generate a random u64 in [min, max] (with a bias of 2^{-64}). - public fun generate_u64_in_range(g: &mut RandomGenerator, min: u64, max: u64): u64 { - u128_in_range(g, min as u128, max as u128, 16) as u64 - } - - /// Generate a random u32 in [min, max] (with a bias of 2^{-64}). - public fun generate_u32_in_range(g: &mut RandomGenerator, min: u32, max: u32): u32 { - u128_in_range(g, min as u128, max as u128, 12) as u32 - } - - /// Generate a random u16 in [min, max] (with a bias of 2^{-64}). - public fun generate_u16_in_range(g: &mut RandomGenerator, min: u16, max: u16): u16 { - u128_in_range(g, min as u128, max as u128, 10) as u16 - } - - /// Generate a random u8 in [min, max] (with a bias of 2^{-64}). - public fun generate_u8_in_range(g: &mut RandomGenerator, min: u8, max: u8): u8 { - u128_in_range(g, min as u128, max as u128, 9) as u8 - } - - /// Shuffle a vector using the random generator (Fisher–Yates/Knuth shuffle). - public fun shuffle(g: &mut RandomGenerator, v: &mut vector) { - let n = vector::length(v); - if (n == 0) { - return - }; - assert!(n <= U16_MAX, EInvalidLength); - let n = n as u16; - let mut i: u16 = 0; - let end = n - 1; - while (i < end) { - let j = generate_u16_in_range(g, i, end); - vector::swap(v, i as u64, j as u64); - i = i + 1; - }; - } - - #[test_only] - public fun generator_seed(r: &RandomGenerator): &vector { - &r.seed - } - - #[test_only] - public fun generator_counter(r: &RandomGenerator): u16 { - r.counter - } - - #[test_only] - public fun generator_buffer(r: &RandomGenerator): &vector { - &r.buffer - } - - #[test_only] - /// Random generator from a non-deterministic seed. - /// To be used when non-deterministic randomness is needed in tests (e.g., fuzzing). - public fun new_generator_for_testing(): RandomGenerator { - let seed = generate_rand_seed_for_testing(); - new_generator_from_seed_for_testing(seed) - } - - #[test_only] - /// Random generator from a given seed. - public fun new_generator_from_seed_for_testing(seed: vector): RandomGenerator { - RandomGenerator { seed, counter: 0, buffer: vector[] } - } - - #[test_only] - native fun generate_rand_seed_for_testing(): vector; + }; + + inner.epoch = ctx.epoch(); + inner.randomness_round = new_round; + inner.random_bytes = new_bytes; +} + +#[test_only] +public fun update_randomness_state_for_testing( + self: &mut Random, + new_round: u64, + new_bytes: vector, + ctx: &TxContext, +) { + self.update_randomness_state(new_round, new_bytes, ctx); +} + +/// Unique randomness generator, derived from the global randomness. +public struct RandomGenerator has drop { + seed: vector, + counter: u16, + buffer: vector, +} + +/// Create a generator. Can be used to derive up to MAX_U16 * 32 random bytes. +public fun new_generator(r: &Random, ctx: &mut TxContext): RandomGenerator { + let inner = load_inner(r); + let seed = hmac_sha3_256( + &inner.random_bytes, + &ctx.fresh_object_address().to_bytes(), + ); + RandomGenerator { seed, counter: 0, buffer: vector[] } +} + +// Get the next block of random bytes. +fun derive_next_block(g: &mut RandomGenerator): vector { + g.counter = g.counter + 1; + hmac_sha3_256(&g.seed, &bcs::to_bytes(&g.counter)) +} + +// Fill the generator's buffer with 32 random bytes. +fun fill_buffer(g: &mut RandomGenerator) { + let next_block = derive_next_block(g); + vector::append(&mut g.buffer, next_block); +} + +/// Generate n random bytes. +public fun generate_bytes(g: &mut RandomGenerator, num_of_bytes: u16): vector { + let mut result = vector[]; + // Append RAND_OUTPUT_LEN size buffers directly without going through the generator's buffer. + let mut num_of_blocks = num_of_bytes / RAND_OUTPUT_LEN; + while (num_of_blocks > 0) { + vector::append(&mut result, derive_next_block(g)); + num_of_blocks = num_of_blocks - 1; + }; + // Fill the generator's buffer if needed. + let num_of_bytes = num_of_bytes as u64; + if (vector::length(&g.buffer) < (num_of_bytes - vector::length(&result))) { + fill_buffer(g); + }; + // Take remaining bytes from the generator's buffer. + while (vector::length(&result) < num_of_bytes) { + vector::push_back(&mut result, vector::pop_back(&mut g.buffer)); + }; + result +} + +// Helper function that extracts the given number of bytes from the random generator and returns it as u256. +// Assumes that the caller has already checked that num_of_bytes is valid. +// TODO: Replace with a macro when we have support for it. +fun u256_from_bytes(g: &mut RandomGenerator, num_of_bytes: u8): u256 { + if (vector::length(&g.buffer) < num_of_bytes as u64) { + fill_buffer(g); + }; + let mut result: u256 = 0; + let mut i = 0; + while (i < num_of_bytes) { + let byte = vector::pop_back(&mut g.buffer); + result = (result << 8) + (byte as u256); + i = i + 1; + }; + result +} + +/// Generate a u256. +public fun generate_u256(g: &mut RandomGenerator): u256 { + u256_from_bytes(g, 32) +} + +/// Generate a u128. +public fun generate_u128(g: &mut RandomGenerator): u128 { + u256_from_bytes(g, 16) as u128 +} + +/// Generate a u64. +public fun generate_u64(g: &mut RandomGenerator): u64 { + u256_from_bytes(g, 8) as u64 +} + +/// Generate a u32. +public fun generate_u32(g: &mut RandomGenerator): u32 { + u256_from_bytes(g, 4) as u32 +} + +/// Generate a u16. +public fun generate_u16(g: &mut RandomGenerator): u16 { + u256_from_bytes(g, 2) as u16 +} + +/// Generate a u8. +public fun generate_u8(g: &mut RandomGenerator): u8 { + u256_from_bytes(g, 1) as u8 +} + +/// Generate a boolean. +public fun generate_bool(g: &mut RandomGenerator): bool { + (u256_from_bytes(g, 1) & 1) == 1 +} + +// Helper function to generate a random u128 in [min, max] using a random number with num_of_bytes bytes. +// Assumes that the caller verified the inputs, and uses num_of_bytes to control the bias (e.g., 8 bytes larger +// than the actual type used by the caller function to limit the bias by 2^{-64}). +// TODO: Replace with a macro when we have support for it. +fun u128_in_range(g: &mut RandomGenerator, min: u128, max: u128, num_of_bytes: u8): u128 { + assert!(min <= max, EInvalidRange); + if (min == max) { + return min + }; + // Pick a random number in [0, max - min] by generating a random number that is larger than max-min, and taking + // the modulo of the random number by the range size. Then add the min to the result to get a number in + // [min, max]. + let range_size = (max - min) as u256 + 1; + let rand = u256_from_bytes(g, num_of_bytes); + min + (rand % range_size as u128) +} + +/// Generate a random u128 in [min, max] (with a bias of 2^{-64}). +public fun generate_u128_in_range(g: &mut RandomGenerator, min: u128, max: u128): u128 { + u128_in_range(g, min, max, 24) +} + +//// Generate a random u64 in [min, max] (with a bias of 2^{-64}). +public fun generate_u64_in_range(g: &mut RandomGenerator, min: u64, max: u64): u64 { + u128_in_range(g, min as u128, max as u128, 16) as u64 +} + +/// Generate a random u32 in [min, max] (with a bias of 2^{-64}). +public fun generate_u32_in_range(g: &mut RandomGenerator, min: u32, max: u32): u32 { + u128_in_range(g, min as u128, max as u128, 12) as u32 } + +/// Generate a random u16 in [min, max] (with a bias of 2^{-64}). +public fun generate_u16_in_range(g: &mut RandomGenerator, min: u16, max: u16): u16 { + u128_in_range(g, min as u128, max as u128, 10) as u16 +} + +/// Generate a random u8 in [min, max] (with a bias of 2^{-64}). +public fun generate_u8_in_range(g: &mut RandomGenerator, min: u8, max: u8): u8 { + u128_in_range(g, min as u128, max as u128, 9) as u8 +} + +/// Shuffle a vector using the random generator (Fisher–Yates/Knuth shuffle). +public fun shuffle(g: &mut RandomGenerator, v: &mut vector) { + let n = vector::length(v); + if (n == 0) { + return + }; + assert!(n <= U16_MAX, EInvalidLength); + let n = n as u16; + let mut i: u16 = 0; + let end = n - 1; + while (i < end) { + let j = generate_u16_in_range(g, i, end); + vector::swap(v, i as u64, j as u64); + i = i + 1; + }; +} + +#[test_only] +public fun generator_seed(r: &RandomGenerator): &vector { + &r.seed +} + +#[test_only] +public fun generator_counter(r: &RandomGenerator): u16 { + r.counter +} + +#[test_only] +public fun generator_buffer(r: &RandomGenerator): &vector { + &r.buffer +} + +#[test_only] +/// Random generator from a non-deterministic seed. +/// To be used when non-deterministic randomness is needed in tests (e.g., fuzzing). +public fun new_generator_for_testing(): RandomGenerator { + let seed = generate_rand_seed_for_testing(); + new_generator_from_seed_for_testing(seed) +} + +#[test_only] +/// Random generator from a given seed. +public fun new_generator_from_seed_for_testing(seed: vector): RandomGenerator { + RandomGenerator { seed, counter: 0, buffer: vector[] } +} + +#[test_only] +native fun generate_rand_seed_for_testing(): vector; diff --git a/crates/sui-framework/packages/sui-framework/sources/tx_context.move b/crates/sui-framework/packages/sui-framework/sources/tx_context.move index 56111acecdc51..1fdef9ff83a81 100644 --- a/crates/sui-framework/packages/sui-framework/sources/tx_context.move +++ b/crates/sui-framework/packages/sui-framework/sources/tx_context.move @@ -1,142 +1,141 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -module sui::tx_context { - - #[test_only] - /// Number of bytes in an tx hash (which will be the transaction digest) - const TX_HASH_LENGTH: u64 = 32; - - #[test_only] - /// Expected an tx hash of length 32, but found a different length - const EBadTxHashLength: u64 = 0; - - #[test_only] - /// Attempt to get the most recent created object ID when none has been created. - const ENoIDsCreated: u64 = 1; - - /// Information about the transaction currently being executed. - /// This cannot be constructed by a transaction--it is a privileged object created by - /// the VM and passed in to the entrypoint of the transaction as `&mut TxContext`. - public struct TxContext has drop { - /// The address of the user that signed the current transaction - sender: address, - /// Hash of the current transaction - tx_hash: vector, - /// The current epoch number - epoch: u64, - /// Timestamp that the epoch started at - epoch_timestamp_ms: u64, - /// Counter recording the number of fresh id's created while executing - /// this transaction. Always 0 at the start of a transaction - ids_created: u64 - } - - /// Return the address of the user that signed the current - /// transaction - public fun sender(self: &TxContext): address { - self.sender - } - - /// Return the transaction digest (hash of transaction inputs). - /// Please do not use as a source of randomness. - public fun digest(self: &TxContext): &vector { - &self.tx_hash - } - - /// Return the current epoch - public fun epoch(self: &TxContext): u64 { - self.epoch - } - - /// Return the epoch start time as a unix timestamp in milliseconds. - public fun epoch_timestamp_ms(self: &TxContext): u64 { - self.epoch_timestamp_ms - } - - /// Create an `address` that has not been used. As it is an object address, it will never - /// occur as the address for a user. - /// In other words, the generated address is a globally unique object ID. - public fun fresh_object_address(ctx: &mut TxContext): address { - let ids_created = ctx.ids_created; - let id = derive_id(*&ctx.tx_hash, ids_created); - ctx.ids_created = ids_created + 1; - id - } - - #[allow(unused_function)] - /// Return the number of id's created by the current transaction. - /// Hidden for now, but may expose later - fun ids_created(self: &TxContext): u64 { - self.ids_created - } - - /// Native function for deriving an ID via hash(tx_hash || ids_created) - native fun derive_id(tx_hash: vector, ids_created: u64): address; - - // ==== test-only functions ==== - - #[test_only] - /// Create a `TxContext` for testing - public fun new( - sender: address, - tx_hash: vector, - epoch: u64, - epoch_timestamp_ms: u64, - ids_created: u64, - ): TxContext { - assert!(tx_hash.length() == TX_HASH_LENGTH, EBadTxHashLength); - TxContext { sender, tx_hash, epoch, epoch_timestamp_ms, ids_created } - } - - #[test_only] - /// Create a `TxContext` for testing, with a potentially non-zero epoch number. - public fun new_from_hint( - addr: address, - hint: u64, - epoch: u64, - epoch_timestamp_ms: u64, - ids_created: u64, - ): TxContext { - new(addr, dummy_tx_hash_with_hint(hint), epoch, epoch_timestamp_ms, ids_created) - } - - #[test_only] - /// Create a dummy `TxContext` for testing - public fun dummy(): TxContext { - let tx_hash = x"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"; - new(@0x0, tx_hash, 0, 0, 0) - } - - #[test_only] - /// Utility for creating 256 unique input hashes. - /// These hashes are guaranteed to be unique given a unique `hint: u64` - fun dummy_tx_hash_with_hint(hint: u64): vector { - let mut tx_hash = std::bcs::to_bytes(&hint); - while (tx_hash.length() < TX_HASH_LENGTH) tx_hash.push_back(0); - tx_hash - } - - #[test_only] - public fun get_ids_created(self: &TxContext): u64 { - ids_created(self) - } - - #[test_only] - /// Return the most recent created object ID. - public fun last_created_object_id(self: &TxContext): address { - let ids_created = self.ids_created; - assert!(ids_created > 0, ENoIDsCreated); - derive_id(*&self.tx_hash, ids_created - 1) - } - - #[test_only] - public fun increment_epoch_number(self: &mut TxContext) { - self.epoch = self.epoch + 1 - } - - #[test_only] - public fun increment_epoch_timestamp(self: &mut TxContext, delta_ms: u64) { - self.epoch_timestamp_ms = self.epoch_timestamp_ms + delta_ms - } +module sui::tx_context; + +#[test_only] +/// Number of bytes in an tx hash (which will be the transaction digest) +const TX_HASH_LENGTH: u64 = 32; + +#[test_only] +/// Expected an tx hash of length 32, but found a different length +const EBadTxHashLength: u64 = 0; + +#[test_only] +/// Attempt to get the most recent created object ID when none has been created. +const ENoIDsCreated: u64 = 1; + +/// Information about the transaction currently being executed. +/// This cannot be constructed by a transaction--it is a privileged object created by +/// the VM and passed in to the entrypoint of the transaction as `&mut TxContext`. +public struct TxContext has drop { + /// The address of the user that signed the current transaction + sender: address, + /// Hash of the current transaction + tx_hash: vector, + /// The current epoch number + epoch: u64, + /// Timestamp that the epoch started at + epoch_timestamp_ms: u64, + /// Counter recording the number of fresh id's created while executing + /// this transaction. Always 0 at the start of a transaction + ids_created: u64, +} + +/// Return the address of the user that signed the current +/// transaction +public fun sender(self: &TxContext): address { + self.sender +} + +/// Return the transaction digest (hash of transaction inputs). +/// Please do not use as a source of randomness. +public fun digest(self: &TxContext): &vector { + &self.tx_hash +} + +/// Return the current epoch +public fun epoch(self: &TxContext): u64 { + self.epoch +} + +/// Return the epoch start time as a unix timestamp in milliseconds. +public fun epoch_timestamp_ms(self: &TxContext): u64 { + self.epoch_timestamp_ms +} + +/// Create an `address` that has not been used. As it is an object address, it will never +/// occur as the address for a user. +/// In other words, the generated address is a globally unique object ID. +public fun fresh_object_address(ctx: &mut TxContext): address { + let ids_created = ctx.ids_created; + let id = derive_id(*&ctx.tx_hash, ids_created); + ctx.ids_created = ids_created + 1; + id +} + +#[allow(unused_function)] +/// Return the number of id's created by the current transaction. +/// Hidden for now, but may expose later +fun ids_created(self: &TxContext): u64 { + self.ids_created +} + +/// Native function for deriving an ID via hash(tx_hash || ids_created) +native fun derive_id(tx_hash: vector, ids_created: u64): address; + +// ==== test-only functions ==== + +#[test_only] +/// Create a `TxContext` for testing +public fun new( + sender: address, + tx_hash: vector, + epoch: u64, + epoch_timestamp_ms: u64, + ids_created: u64, +): TxContext { + assert!(tx_hash.length() == TX_HASH_LENGTH, EBadTxHashLength); + TxContext { sender, tx_hash, epoch, epoch_timestamp_ms, ids_created } +} + +#[test_only] +/// Create a `TxContext` for testing, with a potentially non-zero epoch number. +public fun new_from_hint( + addr: address, + hint: u64, + epoch: u64, + epoch_timestamp_ms: u64, + ids_created: u64, +): TxContext { + new(addr, dummy_tx_hash_with_hint(hint), epoch, epoch_timestamp_ms, ids_created) +} + +#[test_only] +/// Create a dummy `TxContext` for testing +public fun dummy(): TxContext { + let tx_hash = x"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"; + new(@0x0, tx_hash, 0, 0, 0) +} + +#[test_only] +/// Utility for creating 256 unique input hashes. +/// These hashes are guaranteed to be unique given a unique `hint: u64` +fun dummy_tx_hash_with_hint(hint: u64): vector { + let mut tx_hash = std::bcs::to_bytes(&hint); + while (tx_hash.length() < TX_HASH_LENGTH) tx_hash.push_back(0); + tx_hash +} + +#[test_only] +public fun get_ids_created(self: &TxContext): u64 { + ids_created(self) +} + +#[test_only] +/// Return the most recent created object ID. +public fun last_created_object_id(self: &TxContext): address { + let ids_created = self.ids_created; + assert!(ids_created > 0, ENoIDsCreated); + derive_id(*&self.tx_hash, ids_created - 1) +} + +#[test_only] +public fun increment_epoch_number(self: &mut TxContext) { + self.epoch = self.epoch + 1 +} + +#[test_only] +public fun increment_epoch_timestamp(self: &mut TxContext, delta_ms: u64) { + self.epoch_timestamp_ms = self.epoch_timestamp_ms + delta_ms } diff --git a/crates/sui-framework/packages/sui-framework/sources/types.move b/crates/sui-framework/packages/sui-framework/sources/types.move index 64a68a82434d3..adfb18a734ec2 100644 --- a/crates/sui-framework/packages/sui-framework/sources/types.move +++ b/crates/sui-framework/packages/sui-framework/sources/types.move @@ -2,10 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 /// Sui types helpers and utilities -module sui::types { - // === one-time witness === +module sui::types; - /// Tests if the argument type is a one-time witness, that is a type with only one instantiation - /// across the entire code base. - public native fun is_one_time_witness(_: &T): bool; -} +// === one-time witness === + +/// Tests if the argument type is a one-time witness, that is a type with only one instantiation +/// across the entire code base. +public native fun is_one_time_witness(_: &T): bool; diff --git a/crates/sui-framework/packages/sui-framework/sources/url.move b/crates/sui-framework/packages/sui-framework/sources/url.move index e4bfb272bf551..e2eac86c115b4 100644 --- a/crates/sui-framework/packages/sui-framework/sources/url.move +++ b/crates/sui-framework/packages/sui-framework/sources/url.move @@ -2,34 +2,34 @@ // SPDX-License-Identifier: Apache-2.0 /// URL: standard Uniform Resource Locator string -module sui::url { - use std::ascii::String; +module sui::url; - /// Standard Uniform Resource Locator (URL) string. - public struct Url has store, copy, drop { - // TODO: validate URL format - url: String, - } +use std::ascii::String; - /// Create a `Url`, with no validation - public fun new_unsafe(url: String): Url { - Url { url } - } +/// Standard Uniform Resource Locator (URL) string. +public struct Url has store, copy, drop { + // TODO: validate URL format + url: String, +} - /// Create a `Url` with no validation from bytes - /// Note: this will abort if `bytes` is not valid ASCII - public fun new_unsafe_from_bytes(bytes: vector): Url { - let url = bytes.to_ascii_string(); - Url { url } - } +/// Create a `Url`, with no validation +public fun new_unsafe(url: String): Url { + Url { url } +} - /// Get inner URL - public fun inner_url(self: &Url): String{ - self.url - } +/// Create a `Url` with no validation from bytes +/// Note: this will abort if `bytes` is not valid ASCII +public fun new_unsafe_from_bytes(bytes: vector): Url { + let url = bytes.to_ascii_string(); + Url { url } +} + +/// Get inner URL +public fun inner_url(self: &Url): String { + self.url +} - /// Update the inner URL - public fun update(self: &mut Url, url: String) { - self.url = url; - } +/// Update the inner URL +public fun update(self: &mut Url, url: String) { + self.url = url; } diff --git a/crates/sui-framework/packages/sui-framework/sources/versioned.move b/crates/sui-framework/packages/sui-framework/sources/versioned.move index ae916fcdef8b0..3746bbbd56286 100644 --- a/crates/sui-framework/packages/sui-framework/sources/versioned.move +++ b/crates/sui-framework/packages/sui-framework/sources/versioned.move @@ -1,83 +1,88 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -module sui::versioned { - use sui::dynamic_field; +module sui::versioned; - /// Failed to upgrade the inner object due to invalid capability or new version. - const EInvalidUpgrade: u64 = 0; +use sui::dynamic_field; - /// A wrapper type that supports versioning of the inner type. - /// The inner type is a dynamic field of the Versioned object, and is keyed using version. - /// User of this type could load the inner object using corresponding type based on the version. - /// You can also upgrade the inner object to a new type version. - /// If you want to support lazy upgrade of the inner type, one caveat is that all APIs would have - /// to use mutable reference even if it's a read-only API. - public struct Versioned has key, store { - id: UID, - version: u64, - } +/// Failed to upgrade the inner object due to invalid capability or new version. +const EInvalidUpgrade: u64 = 0; - /// Represents a hot potato object generated when we take out the dynamic field. - /// This is to make sure that we always put a new value back. - public struct VersionChangeCap { - versioned_id: ID, - old_version: u64, - } +/// A wrapper type that supports versioning of the inner type. +/// The inner type is a dynamic field of the Versioned object, and is keyed using version. +/// User of this type could load the inner object using corresponding type based on the version. +/// You can also upgrade the inner object to a new type version. +/// If you want to support lazy upgrade of the inner type, one caveat is that all APIs would have +/// to use mutable reference even if it's a read-only API. +public struct Versioned has key, store { + id: UID, + version: u64, +} - /// Create a new Versioned object that contains a initial value of type `T` with an initial version. - public fun create(init_version: u64, init_value: T, ctx: &mut TxContext): Versioned { - let mut self = Versioned { - id: object::new(ctx), - version: init_version, - }; - dynamic_field::add(&mut self.id, init_version, init_value); - self - } +/// Represents a hot potato object generated when we take out the dynamic field. +/// This is to make sure that we always put a new value back. +public struct VersionChangeCap { + versioned_id: ID, + old_version: u64, +} - /// Get the current version of the inner type. - public fun version(self: &Versioned): u64 { - self.version - } +/// Create a new Versioned object that contains a initial value of type `T` with an initial version. +public fun create(init_version: u64, init_value: T, ctx: &mut TxContext): Versioned { + let mut self = Versioned { + id: object::new(ctx), + version: init_version, + }; + dynamic_field::add(&mut self.id, init_version, init_value); + self +} - /// Load the inner value based on the current version. Caller specifies an expected type T. - /// If the type mismatch, the load will fail. - public fun load_value(self: &Versioned): &T { - dynamic_field::borrow(&self.id, self.version) - } +/// Get the current version of the inner type. +public fun version(self: &Versioned): u64 { + self.version +} - /// Similar to load_value, but return a mutable reference. - public fun load_value_mut(self: &mut Versioned): &mut T { - dynamic_field::borrow_mut(&mut self.id, self.version) - } +/// Load the inner value based on the current version. Caller specifies an expected type T. +/// If the type mismatch, the load will fail. +public fun load_value(self: &Versioned): &T { + dynamic_field::borrow(&self.id, self.version) +} - /// Take the inner object out for upgrade. To ensure we always upgrade properly, a capability object is returned - /// and must be used when we upgrade. - public fun remove_value_for_upgrade(self: &mut Versioned): (T, VersionChangeCap) { - ( - dynamic_field::remove(&mut self.id, self.version), - VersionChangeCap { - versioned_id: object::id(self), - old_version: self.version, - } - ) - } +/// Similar to load_value, but return a mutable reference. +public fun load_value_mut(self: &mut Versioned): &mut T { + dynamic_field::borrow_mut(&mut self.id, self.version) +} + +/// Take the inner object out for upgrade. To ensure we always upgrade properly, a capability object is returned +/// and must be used when we upgrade. +public fun remove_value_for_upgrade(self: &mut Versioned): (T, VersionChangeCap) { + ( + dynamic_field::remove(&mut self.id, self.version), + VersionChangeCap { + versioned_id: object::id(self), + old_version: self.version, + }, + ) +} - /// Upgrade the inner object with a new version and new value. Must use the capability returned - /// by calling remove_value_for_upgrade. - public fun upgrade(self: &mut Versioned, new_version: u64, new_value: T, cap: VersionChangeCap) { - let VersionChangeCap { versioned_id, old_version } = cap; - assert!(versioned_id == object::id(self), EInvalidUpgrade); - assert!(old_version < new_version, EInvalidUpgrade); - dynamic_field::add(&mut self.id, new_version, new_value); - self.version = new_version; - } +/// Upgrade the inner object with a new version and new value. Must use the capability returned +/// by calling remove_value_for_upgrade. +public fun upgrade( + self: &mut Versioned, + new_version: u64, + new_value: T, + cap: VersionChangeCap, +) { + let VersionChangeCap { versioned_id, old_version } = cap; + assert!(versioned_id == object::id(self), EInvalidUpgrade); + assert!(old_version < new_version, EInvalidUpgrade); + dynamic_field::add(&mut self.id, new_version, new_value); + self.version = new_version; +} - /// Destroy this Versioned container, and return the inner object. - public fun destroy(self: Versioned): T { - let Versioned { mut id, version } = self; - let ret = dynamic_field::remove(&mut id, version); - id.delete(); - ret - } +/// Destroy this Versioned container, and return the inner object. +public fun destroy(self: Versioned): T { + let Versioned { mut id, version } = self; + let ret = dynamic_field::remove(&mut id, version); + id.delete(); + ret } diff --git a/crates/sui-framework/packages/sui-framework/tests/display_tests.move b/crates/sui-framework/packages/sui-framework/tests/display_tests.move new file mode 100644 index 0000000000000..a704ce67e2c42 --- /dev/null +++ b/crates/sui-framework/packages/sui-framework/tests/display_tests.move @@ -0,0 +1,39 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module sui::display_tests { + use sui::test_scenario as test; + use std::string::String; + use sui::package; + use sui::display; + + #[allow(unused_field)] + /// An example object. + /// Purely for visibility. + public struct Capy has key { + id: UID, + name: String + } + + /// Test witness type to create a Publisher object. + public struct CAPY has drop {} + + #[test] + fun capy_init() { + let mut test = test::begin(@0x2); + let pub = package::test_claim(CAPY {}, test.ctx()); + + // create a new display object + let mut display = display::new(&pub, test.ctx()); + + display.add(b"name".to_string(), b"Capy {name}".to_string()); + display.add(b"link".to_string(), b"https://capy.art/capy/{id}".to_string()); + display.add(b"image".to_string(), b"https://api.capy.art/capy/{id}/svg".to_string()); + display.add(b"description".to_string(), b"A Lovely Capy".to_string()); + + pub.burn_publisher(); + transfer::public_transfer(display, @0x2); + test.end(); + } +} diff --git a/crates/sui-framework/packages/sui-framework/tests/hex_tests.move b/crates/sui-framework/packages/sui-framework/tests/hex_tests.move new file mode 100644 index 0000000000000..990bdb46d8b83 --- /dev/null +++ b/crates/sui-framework/packages/sui-framework/tests/hex_tests.move @@ -0,0 +1,62 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module sui::hex_tests { + use sui::hex; + + #[test] + fun test_hex_encode_string_literal() { + assert!(b"30" == hex::encode(b"0")); + assert!(b"61" == hex::encode(b"a")); + assert!(b"666666" == hex::encode(b"fff")); + } + + #[test] + fun test_hex_encode_hex_literal() { + assert!(b"ff" == hex::encode(x"ff")); + assert!(b"fe" == hex::encode(x"fe")); + assert!(b"00" == hex::encode(x"00")); + } + + #[test] + fun test_hex_decode_string_literal() { + assert!(x"ff" == hex::decode(b"ff")); + assert!(x"fe" == hex::decode(b"fe")); + assert!(x"00" == hex::decode(b"00")); + } + + #[test] + fun test_hex_decode_string_literal__lowercase_and_uppercase() { + assert!(x"ff" == hex::decode(b"Ff")); + assert!(x"ff" == hex::decode(b"fF")); + assert!(x"ff" == hex::decode(b"FF")); + } + + #[test] + fun test_hex_decode_string_literal__long_hex() { + assert!( + x"036d2416252ae1db8aedad59e14b007bee6ab94a3e77a3549a81137871604456f3" == hex::decode( + b"036d2416252ae1Db8aedAd59e14b007bee6aB94a3e77a3549a81137871604456f3" + ), + ); + } + + #[test] + #[expected_failure(abort_code = hex::EInvalidHexLength)] + fun test_hex_decode__invalid_length() { + hex::decode(b"0"); + } + + #[test] + #[expected_failure(abort_code = hex::ENotValidHexCharacter)] + fun test_hex_decode__hex_literal() { + hex::decode(x"ffff"); + } + + #[test] + #[expected_failure(abort_code = hex::ENotValidHexCharacter)] + fun test_hex_decode__invalid_string_literal() { + hex::decode(b"0g"); + } +}