diff --git a/crates/sui-framework/docs/sui-framework/config.md b/crates/sui-framework/docs/sui-framework/config.md index 16fedebe3194ad..4f06b6c9e4b6a9 100644 --- a/crates/sui-framework/docs/sui-framework/config.md +++ b/crates/sui-framework/docs/sui-framework/config.md @@ -11,6 +11,7 @@ title: Module `0x2::config` - [Function `new`](#0x2_config_new) - [Function `create`](#0x2_config_create) - [Function `add_for_current_epoch`](#0x2_config_add_for_current_epoch) +- [Function `remove_for_current_epoch`](#0x2_config_remove_for_current_epoch) - [Function `exists_with_type`](#0x2_config_exists_with_type) - [Function `exists_with_type_for_current_epoch`](#0x2_config_exists_with_type_for_current_epoch) - [Function `borrow_for_current_epoch_mut`](#0x2_config_borrow_for_current_epoch_mut) @@ -61,7 +62,7 @@ title: Module `0x2::config` -
struct Setting<Value: copy, drop, store> has store
+
struct Setting<Value: copy, drop, store> has drop, store
 
@@ -88,7 +89,7 @@ title: Module `0x2::config` -
struct SettingData<Value: copy, drop, store> has store
+
struct SettingData<Value: copy, drop, store> has drop, store
 
@@ -105,7 +106,7 @@ title: Module `0x2::config`
-newer_value: Value +newer_value: option::Option<Value>
@@ -207,7 +208,7 @@ title: Module `0x2::config` -
public(friend) fun add_for_current_epoch<WriteCap, Name: copy, drop, store, Value: copy, drop, store>(config: &mut config::Config<WriteCap>, _cap: &mut WriteCap, name: Name, value: Value, _ctx: &mut tx_context::TxContext): option::Option<Value>
+
public(friend) fun add_for_current_epoch<WriteCap, Name: copy, drop, store, Value: copy, drop, store>(config: &mut config::Config<WriteCap>, _cap: &mut WriteCap, name: Name, value: Value, ctx: &mut tx_context::TxContext): option::Option<Value>
 
@@ -225,14 +226,14 @@ title: Module `0x2::config` _cap: &mut WriteCap, name: Name, value: Value, - _ctx: &mut TxContext, + ctx: &mut TxContext, ): Option<Value> { - let epoch = _ctx.epoch(); + let epoch = ctx.epoch(); if (!field::exists_(&config.id, name)) { let sobj = Setting { data: option::some(SettingData { newer_value_epoch: epoch, - newer_value: value, + newer_value: option::some(value), older_value_opt: option::none(), }), }; @@ -245,19 +246,88 @@ title: Module `0x2::config` newer_value, older_value_opt, } = sobj.data.extract(); - assert!(epoch > newer_value_epoch, EAlreadySetForEpoch); + let (older_value_opt, removed_value) = + if (epoch > newer_value_epoch) { + // if the `newer_value` is for a previous epoch, move it to `older_value_opt` + (move newer_value, move older_value_opt) + } else { + // the current epoch cannot be less than the `newer_value_epoch` + assert!(epoch == newer_value_epoch); + // if the `newer_value` is for the current epoch, then the option must be `none` + assert!(newer_value.is_none(), EAlreadySetForEpoch); + (move older_value_opt, option::none()) + }; sobj.data.fill(SettingData { newer_value_epoch: epoch, - newer_value: value, - older_value_opt: option::some(newer_value), + newer_value: option::some(value), + older_value_opt, }); - older_value_opt + removed_value } }
+ + + + +## Function `remove_for_current_epoch` + + + +
public(friend) fun remove_for_current_epoch<WriteCap, Name: copy, drop, store, Value: copy, drop, store>(config: &mut config::Config<WriteCap>, _cap: &mut WriteCap, name: Name, ctx: &mut tx_context::TxContext): option::Option<Value>
+
+ + + +
+Implementation + + +
public(package) fun remove_for_current_epoch<
+    WriteCap,
+    Name: copy + drop + store,
+    Value: copy + drop + store,
+>(
+    config: &mut Config<WriteCap>,
+    _cap: &mut WriteCap,
+    name: Name,
+    ctx: &mut TxContext,
+): Option<Value> {
+    let epoch = ctx.epoch();
+    if (!field::exists_(&config.id, name)) return option::none();
+    let sobj: &mut Setting<Value> = field::borrow_mut(&mut config.id, name);
+    let SettingData {
+        newer_value_epoch,
+        newer_value,
+        older_value_opt,
+    } = sobj.data.extract();
+    let (older_value_opt, removed_value) =
+        if (epoch > newer_value_epoch) {
+            // if the `newer_value` is for a previous epoch, move it to `older_value_opt`
+            (move newer_value, option::none())
+        } else {
+            // the current epoch cannot be less than the `newer_value_epoch`
+            assert!(epoch == newer_value_epoch);
+            (move older_value_opt, move newer_value)
+        };
+    let older_value_opt_is_none = older_value_opt.is_none();
+    sobj.data.fill(SettingData {
+        newer_value_epoch: epoch,
+        newer_value: option::none(),
+        older_value_opt,
+    });
+    if (older_value_opt_is_none) {
+        field::remove<_, Setting<Value>>(&mut config.id, name);
+    };
+    removed_value
+}
+
+ + +
@@ -318,7 +388,8 @@ title: Module `0x2::config` field::exists_with_type<_, Setting<Value>>(&config.id, name) && { let epoch = ctx.epoch(); let sobj: &Setting<Value> = field::borrow(&config.id, name); - epoch == sobj.data.borrow().newer_value_epoch + epoch == sobj.data.borrow().newer_value_epoch && + sobj.data.borrow().newer_value.is_some() } }
@@ -356,7 +427,8 @@ title: Module `0x2::config` let sobj: &mut Setting<Value> = field::borrow_mut(&mut config.id, name); let data = sobj.data.borrow_mut(); assert!(data.newer_value_epoch == epoch, ENotSetForEpoch); - &mut data.newer_value + assert!(data.newer_value.is_some(), ENotSetForEpoch); + data.newer_value.borrow_mut() }
@@ -388,7 +460,9 @@ title: Module `0x2::config` name: Name, ): &Value { let sobj: &Setting<Value> = field::borrow(&config.id, name); - &sobj.data.borrow().newer_value + let data = sobj.data.borrow(); + assert!(data.newer_value.is_some(), ENotSetForEpoch); + data.newer_value.borrow() } diff --git a/crates/sui-framework/docs/sui-framework/deny_list.md b/crates/sui-framework/docs/sui-framework/deny_list.md index 95f690ab849f91..22e9510d415252 100644 --- a/crates/sui-framework/docs/sui-framework/deny_list.md +++ b/crates/sui-framework/docs/sui-framework/deny_list.md @@ -393,13 +393,11 @@ meaningless to add them to the deny list. ) { let per_type_config = deny_list.per_type_config_entry!(per_type_index, per_type_key, ctx); let setting_name = AddressKey(addr); - let next_epoch_entry = per_type_config.entry!<_, AddressKey, bool>( + per_type_config.remove_for_current_epoch<_, AddressKey, bool>( &mut ConfigWriteCap(), setting_name, - |_deny_list, _cap, _ctx| false, ctx, ); - *next_epoch_entry = false; } diff --git a/crates/sui-framework/packages/sui-framework/sources/config.move b/crates/sui-framework/packages/sui-framework/sources/config.move index 2b7fe323655770..d59101940098e1 100644 --- a/crates/sui-framework/packages/sui-framework/sources/config.move +++ b/crates/sui-framework/packages/sui-framework/sources/config.move @@ -24,13 +24,13 @@ module sui::config { id: UID, } - public struct Setting has store { + public struct Setting has store, drop { data: Option>, } - public struct SettingData has store { + public struct SettingData has store, drop { newer_value_epoch: u64, - newer_value: Value, + newer_value: Option, older_value_opt: Option, } @@ -43,6 +43,7 @@ module sui::config { transfer::share_object(new(cap, ctx)) } + #[allow(unused_mut_parameter)] public(package) fun add_for_current_epoch< WriteCap, Name: copy + drop + store, @@ -52,14 +53,14 @@ module sui::config { _cap: &mut WriteCap, name: Name, value: Value, - _ctx: &mut TxContext, + ctx: &mut TxContext, ): Option { - let epoch = _ctx.epoch(); + let epoch = ctx.epoch(); if (!field::exists_(&config.id, name)) { let sobj = Setting { data: option::some(SettingData { newer_value_epoch: epoch, - newer_value: value, + newer_value: option::some(value), older_value_opt: option::none(), }), }; @@ -72,16 +73,66 @@ module sui::config { newer_value, older_value_opt, } = sobj.data.extract(); - assert!(epoch > newer_value_epoch, EAlreadySetForEpoch); + let (older_value_opt, removed_value) = + if (epoch > newer_value_epoch) { + // if the `newer_value` is for a previous epoch, move it to `older_value_opt` + (move newer_value, move older_value_opt) + } else { + // the current epoch cannot be less than the `newer_value_epoch` + assert!(epoch == newer_value_epoch); + // if the `newer_value` is for the current epoch, then the option must be `none` + assert!(newer_value.is_none(), EAlreadySetForEpoch); + (move older_value_opt, option::none()) + }; sobj.data.fill(SettingData { newer_value_epoch: epoch, - newer_value: value, - older_value_opt: option::some(newer_value), + newer_value: option::some(value), + older_value_opt, }); - older_value_opt + removed_value } } + #[allow(unused_mut_parameter)] + public(package) fun remove_for_current_epoch< + WriteCap, + Name: copy + drop + store, + Value: copy + drop + store, + >( + config: &mut Config, + _cap: &mut WriteCap, + name: Name, + ctx: &mut TxContext, + ): Option { + let epoch = ctx.epoch(); + if (!field::exists_(&config.id, name)) return option::none(); + let sobj: &mut Setting = field::borrow_mut(&mut config.id, name); + let SettingData { + newer_value_epoch, + newer_value, + older_value_opt, + } = sobj.data.extract(); + let (older_value_opt, removed_value) = + if (epoch > newer_value_epoch) { + // if the `newer_value` is for a previous epoch, move it to `older_value_opt` + (move newer_value, option::none()) + } else { + // the current epoch cannot be less than the `newer_value_epoch` + assert!(epoch == newer_value_epoch); + (move older_value_opt, move newer_value) + }; + let older_value_opt_is_none = older_value_opt.is_none(); + sobj.data.fill(SettingData { + newer_value_epoch: epoch, + newer_value: option::none(), + older_value_opt, + }); + if (older_value_opt_is_none) { + field::remove<_, Setting>(&mut config.id, name); + }; + removed_value + } + public(package) fun exists_with_type< WriteCap, Name: copy + drop + store, @@ -106,7 +157,8 @@ module sui::config { field::exists_with_type<_, Setting>(&config.id, name) && { let epoch = ctx.epoch(); let sobj: &Setting = field::borrow(&config.id, name); - epoch == sobj.data.borrow().newer_value_epoch + epoch == sobj.data.borrow().newer_value_epoch && + sobj.data.borrow().newer_value.is_some() } } @@ -125,7 +177,8 @@ module sui::config { let sobj: &mut Setting = field::borrow_mut(&mut config.id, name); let data = sobj.data.borrow_mut(); assert!(data.newer_value_epoch == epoch, ENotSetForEpoch); - &mut data.newer_value + assert!(data.newer_value.is_some(), ENotSetForEpoch); + data.newer_value.borrow_mut() } public(package) fun borrow_most_recent< @@ -137,7 +190,9 @@ module sui::config { name: Name, ): &Value { let sobj: &Setting = field::borrow(&config.id, name); - &sobj.data.borrow().newer_value + let data = sobj.data.borrow(); + assert!(data.newer_value.is_some(), ENotSetForEpoch); + data.newer_value.borrow() } public(package) macro fun entry< diff --git a/crates/sui-framework/packages/sui-framework/sources/deny_list.move b/crates/sui-framework/packages/sui-framework/sources/deny_list.move index 04fd6d6c0cd04d..c15b45532aa900 100644 --- a/crates/sui-framework/packages/sui-framework/sources/deny_list.move +++ b/crates/sui-framework/packages/sui-framework/sources/deny_list.move @@ -98,13 +98,11 @@ module sui::deny_list { ) { let per_type_config = deny_list.per_type_config_entry!(per_type_index, per_type_key, ctx); let setting_name = AddressKey(addr); - let next_epoch_entry = per_type_config.entry!<_, AddressKey, bool>( + per_type_config.remove_for_current_epoch<_, AddressKey, bool>( &mut ConfigWriteCap(), setting_name, - |_deny_list, _cap, _ctx| false, ctx, ); - *next_epoch_entry = false; } public(package) fun v2_most_recent_contains( diff --git a/crates/sui-framework/packages/sui-framework/tests/config_tests.move b/crates/sui-framework/packages/sui-framework/tests/config_tests.move index 3a443ea0eaff8f..cd6dc188e89296 100644 --- a/crates/sui-framework/packages/sui-framework/tests/config_tests.move +++ b/crates/sui-framework/packages/sui-framework/tests/config_tests.move @@ -6,6 +6,7 @@ module sui::config_tests { use sui::config::{Self, Config}; use sui::test_scenario as ts; + use std::unit_test::assert_eq; const SENDER: address = @42; @@ -97,12 +98,16 @@ module sui::config_tests { // check that read_setting is not updated until next epoch ts.next_tx(SENDER); - assert!(config::read_setting<_, u8>(id, n1, ts.ctx()).destroy_some() == 224u8); - assert!(config::read_setting<_, u8>(id, n2, ts.ctx()).is_none()); + { + assert!(config::read_setting<_, u8>(id, n1, ts.ctx()).destroy_some() == 224u8); + assert!(config::read_setting<_, u8>(id, n2, ts.ctx()).is_none()); + }; ts.next_epoch(SENDER); - assert!(config::read_setting<_, u8>(id, n1, ts.ctx()).destroy_some() == 0u8); - assert!(config::read_setting<_, u8>(id, n2, ts.ctx()).destroy_some() == 2u8); + { + assert!(config::read_setting<_, u8>(id, n1, ts.ctx()).destroy_some() == 0u8); + assert!(config::read_setting<_, u8>(id, n2, ts.ctx()).destroy_some() == 2u8); + }; ts.next_tx(SENDER); { @@ -201,6 +206,240 @@ module sui::config_tests { assert!(config::read_setting<_, u8>(id, w, ts.ctx()).is_none()); }; + // remove the setting, but still readable this epoch + ts.next_tx(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + // still some + assert!(config::read_setting<_, u8>(id, n, ts.ctx()).is_some()); + // still none + assert!(config::read_setting<_, bool>(id, n, ts.ctx()).is_none()); + assert!(config::read_setting<_, u64>(id, n, ts.ctx()).is_none()); + assert!(config::read_setting<_, u8>(id, w, ts.ctx()).is_none()); + ts::return_shared(config); + }; + + // should now be none + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + assert!(config::read_setting<_, u8>(id, n, ts.ctx()).is_none()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 0, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 0, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + // now none + assert!(config::read_setting<_, u8>(id, n, ts.ctx()).is_none()); + // still none + assert!(config::read_setting<_, bool>(id, n, ts.ctx()).is_none()); + assert!(config::read_setting<_, u64>(id, n, ts.ctx()).is_none()); + assert!(config::read_setting<_, u8>(id, w, ts.ctx()).is_none()); + ts::return_shared(config); + }; + + // still none + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + assert!(config::read_setting<_, u8>(id, n, ts.ctx()).is_none()); + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 0, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 0, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 0, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + // now none + assert!(config::read_setting<_, u8>(id, n, ts.ctx()).is_none()); + // still none + assert!(config::read_setting<_, bool>(id, n, ts.ctx()).is_none()); + assert!(config::read_setting<_, u64>(id, n, ts.ctx()).is_none()); + assert!(config::read_setting<_, u8>(id, w, ts.ctx()).is_none()); + ts::return_shared(config); + }; + ts.end(); } + + #[test] + fun test_remove_doesnt_fail_on_duplicate() { + let mut ts = ts::begin(SENDER); + config::create(&mut WriteCap(), ts.ctx()); + ts.next_tx(SENDER); + let id = ts::most_recent_id_shared>().destroy_some(); + let n = b"hello"; + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + assert!(config::read_setting<_, u8>(id, n, ts.ctx()).is_none()); + ts::return_shared(config); + }; + + + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 0, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 0, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + assert!(config::read_setting<_, u8>(id, n, ts.ctx()).is_none()); + ts::return_shared(config); + }; + + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 0, ts.ctx()); + assert!(config::read_setting<_, u8>(id, n, ts.ctx()).is_none()); + ts::return_shared(config); + }; + + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 0, ts.ctx()); + assert!(config::read_setting<_, u8>(id, n, ts.ctx()).is_some()); + ts::return_shared(config); + }; + + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + assert!(config::read_setting<_, u8>(id, n, ts.ctx()).is_some()); + ts::return_shared(config); + }; + + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + assert!(config::read_setting<_, u8>(id, n, ts.ctx()).is_none()); + ts::return_shared(config); + }; + + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + assert!(config::read_setting<_, u8>(id, n, ts.ctx()).is_none()); + ts::return_shared(config); + }; + + ts.end(); + } + + #[test, expected_failure(abort_code = sui::dynamic_field::EFieldTypeMismatch)] + fun test_remove_fail_on_type_mismatch() { + let mut ts = ts::begin(SENDER); + config::create(&mut WriteCap(), ts.ctx()); + ts.next_tx(SENDER); + let id = ts::most_recent_id_shared>().destroy_some(); + let n = b"hello"; + ts.next_epoch(SENDER); + let mut config: Config = ts.take_shared_by_id(id); + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 0, ts.ctx()); + config.remove_for_current_epoch<_, _, bool>(&mut WriteCap(), n, ts.ctx()); + abort 0 + } + + #[test, expected_failure(abort_code = sui::dynamic_field::EFieldTypeMismatch)] + fun test_add_fail_on_type_mismatch() { + let mut ts = ts::begin(SENDER); + config::create(&mut WriteCap(), ts.ctx()); + ts.next_tx(SENDER); + let id = ts::most_recent_id_shared>().destroy_some(); + let n = b"hello"; + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 0, ts.ctx()); + ts.next_epoch(SENDER); + ts::return_shared(config); + }; + + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + config.remove_for_current_epoch<_, _, bool>(&mut WriteCap(), n, ts.ctx()); + abort 0 + } + } + + #[test] + fun test_removed_value() { + let mut ts = ts::begin(SENDER); + config::create(&mut WriteCap(), ts.ctx()); + ts.next_tx(SENDER); + let id = ts::most_recent_id_shared>().destroy_some(); + let n = b"hello"; + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + let removed_value = + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 0, ts.ctx()); + assert_eq!(removed_value, option::none()); + ts::return_shared(config); + }; + + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + let removed_value = + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 1, ts.ctx()); + assert_eq!(removed_value, option::none()); + ts::return_shared(config); + }; + + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + let removed_value = + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 2, ts.ctx()); + assert_eq!(removed_value, option::some(0)); + ts::return_shared(config); + }; + + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + let removed_value = + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + assert_eq!(removed_value, option::none()); + let removed_value = + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 3, ts.ctx()); + assert_eq!(removed_value, option::none()); + ts::return_shared(config); + }; + + + ts.next_epoch(SENDER); + { + let mut config: Config = ts.take_shared_by_id(id); + let removed_value = + config.add_for_current_epoch<_, _, u8>(&mut WriteCap(), n, 4, ts.ctx()); + assert_eq!(removed_value, option::some(2)); + let removed_value = + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + assert_eq!(removed_value, option::some(4)); + let removed_value = + config.remove_for_current_epoch<_, _, u8>(&mut WriteCap(), n, ts.ctx()); + assert_eq!(removed_value, option::none()); + ts::return_shared(config); + }; + + ts.end(); + } + + } diff --git a/crates/sui-framework/published_api.txt b/crates/sui-framework/published_api.txt index 4584a322f6d9e3..88cb0775f68ae8 100644 --- a/crates/sui-framework/published_api.txt +++ b/crates/sui-framework/published_api.txt @@ -1873,6 +1873,9 @@ create add_for_current_epoch public(package) fun 0x2::config +remove_for_current_epoch + public(package) fun + 0x2::config exists_with_type public(package) fun 0x2::config diff --git a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap index cb2e10a055228e..ff86636d63032c 100644 --- a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap +++ b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap @@ -240,13 +240,13 @@ validators: next_epoch_worker_address: ~ extra_fields: id: - id: "0x9782ad80b3af27622c103346d99fb630190cbea59ee12e398d965ac725c98201" + id: "0xedf032c6b47c9a27d46d9533a39b62ceef1f056f808eacec5e0ed545f7c1fdad" size: 0 voting_power: 10000 - operation_cap_id: "0xa82682c7e8cc6469e97584f0884fa620694f7c69ae379b4426724330e2459b67" + operation_cap_id: "0xcca7bcfb0c37af4c4e0dd305ed4babeb6743111e9765a5cfe5c4f369037c27a6" gas_price: 1000 staking_pool: - id: "0xecc45b11f965b0c6507287e8dfe6a155e60ad66ff9f8cb8018d2d5f14ac241e7" + id: "0xfbd6c23d91df3dfb53fa57e0ddb3317070ffa7afcf35e00717f4b4a9809e9802" activation_epoch: 0 deactivation_epoch: ~ sui_balance: 20000000000000000 @@ -254,14 +254,14 @@ validators: value: 0 pool_token_balance: 20000000000000000 exchange_rates: - id: "0xbc3c30211aef5b13284224b7e485f73584b6998c26b1a60ade850193fd141f35" + id: "0x5d656b3d0f8fd6497142742bf16262eaf906124cd4edb9c94f15b323440eb7b7" size: 1 pending_stake: 0 pending_total_sui_withdraw: 0 pending_pool_token_withdraw: 0 extra_fields: id: - id: "0xda1c598ab339f29abf16db225fd9fa9cb2a5dd403c086a094049b499e3f05df9" + id: "0xeb2ece185bb3a9a468781b683e9be127d94cb2c65afa85d9b32fb8c5c586e4c4" size: 0 commission_rate: 200 next_epoch_stake: 20000000000000000 @@ -269,27 +269,27 @@ validators: next_epoch_commission_rate: 200 extra_fields: id: - id: "0x031729e8a97dd92a5738c189ec493ed2527ae0900ba7aa148a0134bbee60fe58" + id: "0x8b97b2bf431a598dbe6184c0c4e765ed770638146698438b9bbc3c94b53eac88" size: 0 pending_active_validators: contents: - id: "0x0b6928d3aff001e2929522eca3ff33957ab0ce8274bd7eaf61d546e3784dba0c" + id: "0x1139e5d1b39405f92ec995d36c752669f438c89b807c58acb5afb8c4b6c513a9" size: 0 pending_removals: [] staking_pool_mappings: - id: "0x50676c9b2378c44854ca4a9154bd54c2c1f2433aa3338f6d72dd3d3dc9e48155" + id: "0x41f4be360bce58528aea2734ca2ab27fa0847da68fab36a7b577eecc5642ff21" size: 1 inactive_validators: - id: "0x43094c8ee5757e694ff7df3272975c35962043420fa3f9c8b063a7701a7ab4c5" + id: "0xa680d0a281b63d7eabc20288244a31964f6df47416b8fb61a8c162ee03d1f7dc" size: 0 validator_candidates: - id: "0xa756364517d279ec613a2b65b292743b9223375216caf1c6c9e871b986294f7d" + id: "0x76ebe1f42a643b10a2c465539388e2632b3df613753e247482c5e47a4775fb97" size: 0 at_risk_validators: contents: [] extra_fields: id: - id: "0x829d9485dd0ad080f11b947ebd386ccf11edb0950fe4dfc78fdfd806b66583f4" + id: "0xcd6597578e8ca2343e45cd43800e04ce3682383ed7d4215f7180bf1b83768a23" size: 0 storage_fund: total_object_storage_rebates: @@ -306,7 +306,7 @@ parameters: validator_low_stake_grace_period: 7 extra_fields: id: - id: "0xfbb65ad85adf44c3798617b7a563d2771bb599f15e0ef8ce05e75a846da0cf4b" + id: "0x75257db99109e5749fdb019af4936c931d2b67c5d51731a1f09d234f531661ae" size: 0 reference_gas_price: 1000 validator_report_records: @@ -320,7 +320,7 @@ stake_subsidy: stake_subsidy_decrease_rate: 1000 extra_fields: id: - id: "0xf5253da519723dc32193015c61fcfce270ed0b1dde8c0961ae0f10473f821ddf" + id: "0x2a0623ca8b6471e329c0eb64b647614d5c57fca78a207b0d018397ac86de83fe" size: 0 safe_mode: false safe_mode_storage_rewards: @@ -332,6 +332,6 @@ safe_mode_non_refundable_storage_fee: 0 epoch_start_timestamp_ms: 10 extra_fields: id: - id: "0x8bb8345d87e584c4527d48e96586bd8ca9f5c5c096be00792338e2f4e4b068c9" + id: "0x186e5c10432adb4544ce3342f9222bb0027056f1172b4d8cebf7bd68d64eaa96" size: 0 diff --git a/crates/sui-types/src/config.rs b/crates/sui-types/src/config.rs index f7b820635a5267..9a87ff0316daf3 100644 --- a/crates/sui-types/src/config.rs +++ b/crates/sui-types/src/config.rs @@ -38,7 +38,7 @@ pub struct Setting { #[derive(Debug, Serialize, Deserialize)] pub struct SettingData { pub newer_value_epoch: u64, - pub newer_value: V, + pub newer_value: Option, pub older_value_opt: Option, } @@ -105,7 +105,7 @@ impl SettingData { None => true, }; if use_newer_value { - Some(&self.newer_value) + self.newer_value.as_ref() } else { self.older_value_opt.as_ref() } diff --git a/sui-execution/latest/sui-move-natives/src/config.rs b/sui-execution/latest/sui-move-natives/src/config.rs index d51374a182d8e9..e576f9d99ed9a3 100644 --- a/sui-execution/latest/sui-move-natives/src/config.rs +++ b/sui-execution/latest/sui-move-natives/src/config.rs @@ -149,11 +149,15 @@ fn consistent_value_before_current_epoch( }; let [newer_value_epoch, newer_value, older_value_opt]: [Value; 3] = unpack_struct(data)?; let newer_value_epoch: u64 = newer_value_epoch.value_as()?; - if current_epoch > newer_value_epoch { - option_some(value_ty, newer_value) + debug_assert!( + unpack_option(newer_value.copy_value()?, value_ty)?.is_some() + || unpack_option(older_value_opt.copy_value()?, value_ty)?.is_some() + ); + Ok(if current_epoch > newer_value_epoch { + newer_value } else { - Ok(older_value_opt) - } + older_value_opt + }) } fn unpack_struct(s: Value) -> PartialVMResult<[Value; N]> { @@ -183,10 +187,3 @@ fn option_none(type_param: &Type) -> PartialVMResult { type_param, )?]))) } - -fn option_some(type_param: &Type, value: Value) -> PartialVMResult { - Ok(Value::struct_(Struct::pack(vec![Vector::pack( - type_param, - vec![value], - )?]))) -}