From 9f49c9c3a0ec8b1c6b4188f5b8764d596aeee575 Mon Sep 17 00:00:00 2001 From: Igor Date: Wed, 22 May 2024 14:56:09 -0700 Subject: [PATCH] adding tests/feature flag --- .../src/delayed_field_extension.rs | 71 ++++++++++++++--- .../src/gas_schedule/aptos_framework.rs | 27 ++++--- aptos-move/aptos-gas-schedule/src/ver.rs | 10 ++- .../src/components/feature_flags.rs | 7 ++ .../tests/aggregator_v2.txt | 7 ++ .../e2e-move-tests/src/aggregator_v2.rs | 13 ++++ .../pack/sources/aggregator_v2_test.move | 76 ++++++++++++------- .../e2e-move-tests/src/tests/aggregator_v2.rs | 29 +++++++ .../aptos-framework/doc/aggregator_v2.md | 25 +++++- .../sources/aggregator_v2/aggregator_v2.move | 4 +- .../aggregator_v2/aggregator_v2.spec.move | 5 ++ .../framework/move-stdlib/doc/features.md | 14 +++- .../move-stdlib/sources/configs/features.move | 7 +- .../aggregator_natives/aggregator_v2.rs | 2 +- types/src/on_chain_config/aptos_features.rs | 2 + 15 files changed, 233 insertions(+), 66 deletions(-) create mode 100644 aptos-move/e2e-move-tests/proptest-regressions/tests/aggregator_v2.txt diff --git a/aptos-move/aptos-aggregator/src/delayed_field_extension.rs b/aptos-move/aptos-aggregator/src/delayed_field_extension.rs index 52a610b65814c..9a67226fc335b 100644 --- a/aptos-move/aptos-aggregator/src/delayed_field_extension.rs +++ b/aptos-move/aptos-aggregator/src/delayed_field_extension.rs @@ -321,7 +321,7 @@ impl DelayedFieldData { mod test { use super::*; use crate::FakeAggregatorView; - use claims::{assert_err, assert_ok, assert_ok_eq}; + use claims::{assert_err, assert_none, assert_ok_eq}; #[test] fn test_aggregator_not_in_storage() { @@ -355,28 +355,53 @@ mod test { get_agg(&data, &id), &DelayedChange::::Create(DelayedFieldValue::Aggregator(0)) ); - assert_ok!(data.try_add_delta(id, max_value, SignedU128::Positive(100), &resolver)); + assert_ok_eq!( + data.try_add_or_check_delta(id, max_value, SignedU128::Positive(100), &resolver, false), + true + ); + assert_eq!( + get_agg(&data, &id), + &DelayedChange::::Create(DelayedFieldValue::Aggregator(0)) + ); + + assert_ok_eq!( + data.try_add_delta(id, max_value, SignedU128::Positive(100), &resolver), + true + ); assert_eq!( get_agg(&data, &id), &DelayedChange::::Create(DelayedFieldValue::Aggregator(100)) ); - assert!(data - .try_add_delta(id, max_value, SignedU128::Negative(50), &resolver) - .unwrap()); + + assert_ok_eq!( + data.try_add_or_check_delta(id, max_value, SignedU128::Positive(120), &resolver, false), + false + ); + assert_eq!( + get_agg(&data, &id), + &DelayedChange::::Create(DelayedFieldValue::Aggregator(100)) + ); + + assert_ok_eq!( + data.try_add_delta(id, max_value, SignedU128::Negative(50), &resolver), + true + ); assert_eq!( get_agg(&data, &id), &DelayedChange::::Create(DelayedFieldValue::Aggregator(50)) ); - assert!(!data - .try_add_delta(id, max_value, SignedU128::Negative(70), &resolver) - .unwrap()); + assert_ok_eq!( + data.try_add_delta(id, max_value, SignedU128::Negative(70), &resolver), + false + ); assert_eq!( get_agg(&data, &id), &DelayedChange::::Create(DelayedFieldValue::Aggregator(50)) ); - assert!(!data - .try_add_delta(id, max_value, SignedU128::Positive(170), &resolver) - .unwrap()); + assert_ok_eq!( + data.try_add_delta(id, max_value, SignedU128::Positive(170), &resolver), + false + ); assert_eq!( get_agg(&data, &id), &DelayedChange::Create(DelayedFieldValue::Aggregator(50)) @@ -406,6 +431,20 @@ mod test { resolver.set_from_aggregator_id(id, 100); + assert_ok_eq!( + data.try_add_or_check_delta(id, max_value, SignedU128::Positive(400), &resolver, false), + true + ); + // checks only add to captured reads, not to writes + assert_none!(data.delayed_fields.get(&id)); + + assert_ok_eq!( + data.try_add_or_check_delta(id, max_value, SignedU128::Positive(550), &resolver, false), + false + ); + // checks only add to captured reads, not to writes + assert_none!(data.delayed_fields.get(&id)); + assert_ok_eq!( data.try_add_delta(id, max_value, SignedU128::Positive(400), &resolver), true @@ -414,6 +453,16 @@ mod test { get_agg(&data, &id), &aggregator_delta_change(400, max_value) ); + + assert_ok_eq!( + data.try_add_or_check_delta(id, max_value, SignedU128::Negative(100), &resolver, false), + true + ); + assert_eq!( + get_agg(&data, &id), + &aggregator_delta_change(400, max_value) + ); + assert_ok_eq!( data.try_add_delta(id, max_value, SignedU128::Negative(470), &resolver), true diff --git a/aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs b/aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs index 29a356cc3262d..801d44b6992c5 100644 --- a/aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs +++ b/aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs @@ -4,6 +4,7 @@ //! This module defines the gas parameters for Aptos Framework & Stdlib. use crate::{ + gas_feature_versions::{RELEASE_V1_14, RELEASE_V1_8, RELEASE_V1_9_SKIPPED}, gas_schedule::NativeGasParameters, ver::gas_feature_versions::{RELEASE_V1_12, RELEASE_V1_13}, }; @@ -297,18 +298,20 @@ crate::gas_schedule::macros::define_gas_parameters!( [aggregator_destroy_base: InternalGas, "aggregator.destroy.base", 1838], [aggregator_factory_new_aggregator_base: InternalGas, "aggregator_factory.new_aggregator.base", 1838], - [aggregator_v2_create_aggregator_base: InternalGas, {12.. => "aggregator_v2.create_aggregator.base"}, 1838], - [aggregator_v2_try_add_base: InternalGas, {12.. => "aggregator_v2.try_add.base"}, 1102], - [aggregator_v2_try_sub_base: InternalGas, {12.. => "aggregator_v2.try_sub.base"}, 1102], - [aggregator_v2_read_base: InternalGas, {12.. => "aggregator_v2.read.base"}, 2205], - [aggregator_v2_snapshot_base: InternalGas, {12.. => "aggregator_v2.snapshot.base"}, 1102], - - [aggregator_v2_create_snapshot_base: InternalGas, {11.. => "aggregator_v2.create_snapshot.base"}, 1102], - [aggregator_v2_create_snapshot_per_byte: InternalGasPerByte, { 12.. =>"aggregator_v2.create_snapshot.per_byte" }, 3], - [aggregator_v2_copy_snapshot_base: InternalGas, {11.. => "aggregator_v2.copy_snapshot.base"}, 1102], - [aggregator_v2_read_snapshot_base: InternalGas, {11.. => "aggregator_v2.read_snapshot.base"}, 2205], - [aggregator_v2_string_concat_base: InternalGas, {11.. => "aggregator_v2.string_concat.base"}, 1102], - [aggregator_v2_string_concat_per_byte: InternalGasPerByte, { 12.. =>"aggregator_v2.string_concat.per_byte" }, 3], + [aggregator_v2_create_aggregator_base: InternalGas, {RELEASE_V1_9_SKIPPED.. => "aggregator_v2.create_aggregator.base"}, 1838], + [aggregator_v2_try_add_base: InternalGas, {RELEASE_V1_9_SKIPPED.. => "aggregator_v2.try_add.base"}, 1102], + [aggregator_v2_try_sub_base: InternalGas, {RELEASE_V1_9_SKIPPED.. => "aggregator_v2.try_sub.base"}, 1102], + [aggregator_v2_is_at_least_base: InternalGas, {RELEASE_V1_14.. => "aggregator_v2.is_at_least.base"}, 500], + + [aggregator_v2_read_base: InternalGas, {RELEASE_V1_9_SKIPPED.. => "aggregator_v2.read.base"}, 2205], + [aggregator_v2_snapshot_base: InternalGas, {RELEASE_V1_9_SKIPPED.. => "aggregator_v2.snapshot.base"}, 1102], + + [aggregator_v2_create_snapshot_base: InternalGas, {RELEASE_V1_8.. => "aggregator_v2.create_snapshot.base"}, 1102], + [aggregator_v2_create_snapshot_per_byte: InternalGasPerByte, { RELEASE_V1_9_SKIPPED.. =>"aggregator_v2.create_snapshot.per_byte" }, 3], + [aggregator_v2_copy_snapshot_base: InternalGas, {RELEASE_V1_8.. => "aggregator_v2.copy_snapshot.base"}, 1102], + [aggregator_v2_read_snapshot_base: InternalGas, {RELEASE_V1_8.. => "aggregator_v2.read_snapshot.base"}, 2205], + [aggregator_v2_string_concat_base: InternalGas, {RELEASE_V1_8.. => "aggregator_v2.string_concat.base"}, 1102], + [aggregator_v2_string_concat_per_byte: InternalGasPerByte, { RELEASE_V1_9_SKIPPED.. =>"aggregator_v2.string_concat.per_byte" }, 3], [object_exists_at_base: InternalGas, { 7.. => "object.exists_at.base" }, 919], // Based on SHA3-256's cost diff --git a/aptos-move/aptos-gas-schedule/src/ver.rs b/aptos-move/aptos-gas-schedule/src/ver.rs index 412decaf9360c..78aa816a32bb1 100644 --- a/aptos-move/aptos-gas-schedule/src/ver.rs +++ b/aptos-move/aptos-gas-schedule/src/ver.rs @@ -8,6 +8,8 @@ /// - Changing how gas is calculated in any way /// /// Change log: +/// - V19 +/// - gas for aggregator_v2::is_at_least native function /// - V18 /// - Separate limits for governance scripts /// - Function info & dispatchable token gas params @@ -25,6 +27,7 @@ /// - V12 /// - Added BN254 operations. /// - IO gas change: 1. read bytes charged at 4KB intervals; 2. ignore free_write_bytes_quota +/// - aggregator v2 gas charges /// - V11 /// - Ristretto255 natives (point cloning & double-scalar multiplication) and Bulletproofs natives /// - Hard limit on the number of write ops per transaction @@ -59,11 +62,16 @@ /// global operations. /// - V1 /// - TBA -pub const LATEST_GAS_FEATURE_VERSION: u64 = 18; +pub const LATEST_GAS_FEATURE_VERSION: u64 = 19; #[allow(dead_code)] pub mod gas_feature_versions { + pub const RELEASE_V1_8: u64 = 11; + pub const RELEASE_V1_9_SKIPPED: u64 = 12; + pub const RELEASE_V1_9: u64 = 13; + pub const RELEASE_V1_10: u64 = 15; pub const RELEASE_V1_11: u64 = 16; pub const RELEASE_V1_12: u64 = 17; pub const RELEASE_V1_13: u64 = 18; + pub const RELEASE_V1_14: u64 = 19; } diff --git a/aptos-move/aptos-release-builder/src/components/feature_flags.rs b/aptos-move/aptos-release-builder/src/components/feature_flags.rs index 6ca970dbec51d..c8b6eca9654ff 100644 --- a/aptos-move/aptos-release-builder/src/components/feature_flags.rs +++ b/aptos-move/aptos-release-builder/src/components/feature_flags.rs @@ -116,6 +116,7 @@ pub enum FeatureFlag { DispatchableFungibleAsset, NewAccountsDefaultToFaAptStore, OperationsDefaultToFaAptStore, + AggregatorV2IsAtLeastApi, } fn generate_features_blob(writer: &CodeWriter, data: &[u64]) { @@ -300,6 +301,9 @@ impl From for AptosFeatureFlag { FeatureFlag::OperationsDefaultToFaAptStore => { AptosFeatureFlag::OPERATIONS_DEFAULT_TO_FA_APT_STORE }, + FeatureFlag::AggregatorV2IsAtLeastApi => { + AptosFeatureFlag::AGGREGATOR_V2_IS_AT_LEAST_API + }, } } } @@ -413,6 +417,9 @@ impl From for FeatureFlag { AptosFeatureFlag::OPERATIONS_DEFAULT_TO_FA_APT_STORE => { FeatureFlag::OperationsDefaultToFaAptStore }, + AptosFeatureFlag::AGGREGATOR_V2_IS_AT_LEAST_API => { + FeatureFlag::AggregatorV2IsAtLeastApi + }, } } } diff --git a/aptos-move/e2e-move-tests/proptest-regressions/tests/aggregator_v2.txt b/aptos-move/e2e-move-tests/proptest-regressions/tests/aggregator_v2.txt new file mode 100644 index 0000000000000..1bb78427cbd61 --- /dev/null +++ b/aptos-move/e2e-move-tests/proptest-regressions/tests/aggregator_v2.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc a8f570394fd4cd6dccbec4f0f8a866f365ac76eac32cb0e8a1665f3d09f06c80 # shrinks to test_env = TestEnvConfig { executor_mode: BothComparison, aggregator_execution_mode: DisabledOnly, block_split: Whole } diff --git a/aptos-move/e2e-move-tests/src/aggregator_v2.rs b/aptos-move/e2e-move-tests/src/aggregator_v2.rs index 47d8319070a43..de32570c756ef 100644 --- a/aptos-move/e2e-move-tests/src/aggregator_v2.rs +++ b/aptos-move/e2e-move-tests/src/aggregator_v2.rs @@ -371,6 +371,19 @@ impl AggV2TestHarness { self.create_entry_agg_func_with_args("0x1::aggregator_v2_test::add_sub", agg_loc, &[a, b]) } + pub fn add_if_at_least( + &mut self, + agg_loc: &AggregatorLocation, + min_value: u128, + delta: u128, + ) -> SignedTransaction { + self.create_entry_agg_func_with_args( + "0x1::aggregator_v2_test::add_if_at_least", + agg_loc, + &[min_value, delta], + ) + } + pub fn add_delete(&mut self, agg_loc: &AggregatorLocation, value: u128) -> SignedTransaction { self.create_entry_agg_func_with_args("0x1::aggregator_v2_test::add_delete", agg_loc, &[ value, diff --git a/aptos-move/e2e-move-tests/src/tests/aggregator_v2.data/pack/sources/aggregator_v2_test.move b/aptos-move/e2e-move-tests/src/tests/aggregator_v2.data/pack/sources/aggregator_v2_test.move index d854475a1a135..4a5c12ce8e2a7 100644 --- a/aptos-move/e2e-move-tests/src/tests/aggregator_v2.data/pack/sources/aggregator_v2_test.move +++ b/aptos-move/e2e-move-tests/src/tests/aggregator_v2.data/pack/sources/aggregator_v2_test.move @@ -184,7 +184,7 @@ module 0x1::aggregator_v2_test { f(value) } - public entry fun new(_account: &signer, addr: address, use_type: u32, i: u64, limit: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun new(addr: address, use_type: u32, i: u64, limit: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { insert>(addr, use_type, i, aggregator_v2::create_aggregator(limit)); } @@ -192,45 +192,45 @@ module 0x1::aggregator_v2_test { for_element_ref, Element>(addr, use_type, i, |aggregator| aggregator_v2::read(aggregator)) } - public entry fun try_add(_account: &signer, addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun try_add(addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { for_element_mut, bool>(addr, use_type, i, |aggregator| aggregator_v2::try_add(aggregator, value)); } - public entry fun add(_account: &signer, addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun add(addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { for_element_mut, bool>(addr, use_type, i, |aggregator| { aggregator_v2::add(aggregator, value); true }); } - public entry fun try_sub(_account: &signer, addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun try_sub(addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { for_element_mut, bool>(addr, use_type, i, |aggregator| aggregator_v2::try_sub(aggregator, value)); } - public entry fun sub(_account: &signer, addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun sub(addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { for_element_mut, bool>(addr, use_type, i, |aggregator| { aggregator_v2::sub(aggregator, value); true }); } - public entry fun materialize(_account: &signer, addr: address, use_type: u32, i: u64) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun materialize(addr: address, use_type: u32, i: u64) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { call_read(addr, use_type, i); } /// Checks that the ith aggregator has expected value. Useful to inject into /// transaction block to verify successful and correct execution. - public entry fun check(_account: &signer, addr: address, use_type: u32, i: u64, expected: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun check(addr: address, use_type: u32, i: u64, expected: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { let actual = call_read(addr, use_type, i); assert!(actual == expected, ENOT_EQUAL) } - public entry fun new_add(account: &signer, addr: address, use_type: u32, i: u64, limit: Element, a: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { - new(account, addr, use_type, i, limit); - add(account, addr, use_type, i, a); + public entry fun new_add(addr: address, use_type: u32, i: u64, limit: Element, a: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + new(addr, use_type, i, limit); + add(addr, use_type, i, a); } - public entry fun sub_add(_account: &signer, addr: address, use_type: u32, i: u64, a: Element, b: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun sub_add(addr: address, use_type: u32, i: u64, a: Element, b: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { for_element_mut, bool>(addr, use_type, i, |aggregator| { aggregator_v2::sub(aggregator, a); aggregator_v2::add(aggregator, b); @@ -238,7 +238,25 @@ module 0x1::aggregator_v2_test { }); } - public entry fun add_sub(_account: &signer, addr: address, use_type: u32, i: u64, a: Element, b: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun add_if_at_least(addr: address, use_type: u32, i: u64, a: Element, b: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + let is_at_least = for_element_ref, bool>(addr, use_type, i, |aggregator| { + aggregator_v2::is_at_least(aggregator, a) + }); + + if (is_at_least) { + add(addr, use_type, i, b); + } + + // issue with type inference of lambda or downcasting from mut to non-mut? + // for_element_mut, bool>(addr, use_type, i, |aggregator| { + // if (aggregator_v2::is_at_least(aggregator, a)) { + // aggregator_v2::add(aggregator, b); + // }; + // true + // }); + } + + public entry fun add_sub(addr: address, use_type: u32, i: u64, a: Element, b: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { for_element_mut, bool>(addr, use_type, i, |aggregator| { aggregator_v2::add(aggregator, b); aggregator_v2::sub(aggregator, a); @@ -246,14 +264,14 @@ module 0x1::aggregator_v2_test { }); } - public entry fun add_delete(account: &signer, addr: address, use_type: u32, i: u64, a: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { - add(account, addr, use_type, i, a); + public entry fun add_delete(addr: address, use_type: u32, i: u64, a: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + add(addr, use_type, i, a); delete_aggregator(addr, use_type); } - public entry fun materialize_and_add(account: &signer, addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun materialize_and_add(addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { call_read(addr, use_type, i); - add(account, addr, use_type, i, value); + add(addr, use_type, i, value); // issue with type inference of lambda? // for_element_mut, bool>(account, use_type, i, |aggregator| { @@ -262,9 +280,9 @@ module 0x1::aggregator_v2_test { // }); } - public entry fun materialize_and_sub(account: &signer, addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun materialize_and_sub(addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { call_read(addr, use_type, i); - sub(account, addr, use_type, i, value); + sub(addr, use_type, i, value); // issue with type inference of lambda? // for_element_mut, bool>(account, use_type, i, |aggregator| { @@ -273,54 +291,54 @@ module 0x1::aggregator_v2_test { // }); } - public entry fun add_and_materialize(_account: &signer, addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun add_and_materialize(addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { for_element_mut, Element>(addr, use_type, i, |aggregator| { aggregator_v2::add(aggregator, value); aggregator_v2::read(aggregator) }); } - public entry fun sub_and_materialize(_account: &signer, addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun sub_and_materialize(addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { for_element_mut, Element>(addr, use_type, i, |aggregator| { aggregator_v2::sub(aggregator, value); aggregator_v2::read(aggregator) }); } - public entry fun add_2(account: &signer, addr_a: address, use_type_a: u32, i_a: u64, a: A, addr_b: address, use_type_b: u32, i_b: u64, b: B) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { - add(account, addr_a, use_type_a, i_a, a); - add(account, addr_b, use_type_b, i_b, b); + public entry fun add_2(addr_a: address, use_type_a: u32, i_a: u64, a: A, addr_b: address, use_type_b: u32, i_b: u64, b: B) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + add(addr_a, use_type_a, i_a, a); + add(addr_b, use_type_b, i_b, b); } - public entry fun snapshot(_account: &signer, addr_i: address, use_type_i: u32, i: u64, addr_j: address, use_type_j: u32, j: u64) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun snapshot(addr_i: address, use_type_i: u32, i: u64, addr_j: address, use_type_j: u32, j: u64) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { let snapshot = for_element_ref, AggregatorSnapshot>(addr_i, use_type_i, i, |aggregator| { aggregator_v2::snapshot(aggregator) }); insert>(addr_j, use_type_j, j, snapshot); } - public entry fun concat(_account: &signer, addr_i: address, use_type_i: u32, i: u64, addr_j: address, use_type_j: u32, j: u64, prefix: String, suffix: String) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun concat(addr_i: address, use_type_i: u32, i: u64, addr_j: address, use_type_j: u32, j: u64, prefix: String, suffix: String) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { let snapshot = for_element_ref, DerivedStringSnapshot>(addr_i, use_type_i, i, |snapshot| { aggregator_v2::derive_string_concat(prefix, snapshot, suffix) }); insert(addr_j, use_type_j, j, snapshot); } - public entry fun read_snapshot(_account: &signer, addr: address, use_type: u32, i: u64) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun read_snapshot(addr: address, use_type: u32, i: u64) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { for_element_ref, Element>(addr, use_type, i, |snapshot| aggregator_v2::read_snapshot(snapshot)); } - public entry fun check_snapshot(_account: &signer, addr: address, use_type: u32, i: u64, expected: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun check_snapshot(addr: address, use_type: u32, i: u64, expected: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { let actual = for_element_ref, Element>(addr, use_type, i, |snapshot| aggregator_v2::read_snapshot(snapshot)); assert!(actual == expected, ENOT_EQUAL) } - public entry fun check_derived(_account: &signer, addr: address, use_type: u32, i: u64, expected: String) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun check_derived(addr: address, use_type: u32, i: u64, expected: String) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { let actual = for_element_ref(addr, use_type, i, |snapshot| aggregator_v2::read_derived_string(snapshot)); assert!(actual == expected, ENOT_EQUAL) } - public entry fun add_and_read_snapshot(_account: &signer, addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { + public entry fun add_and_read_snapshot(addr: address, use_type: u32, i: u64, value: Element) acquires AggregatorInResource, AggregatorInTable, AggregatorInResourceGroup { for_element_mut, Element>(addr, use_type, i, |aggregator| { aggregator_v2::add(aggregator, value); aggregator_v2::sub(aggregator, value); diff --git a/aptos-move/e2e-move-tests/src/tests/aggregator_v2.rs b/aptos-move/e2e-move-tests/src/tests/aggregator_v2.rs index 92153bb360deb..d24c681d7381d 100644 --- a/aptos-move/e2e-move-tests/src/tests/aggregator_v2.rs +++ b/aptos-move/e2e-move-tests/src/tests/aggregator_v2.rs @@ -530,6 +530,35 @@ proptest! { txns, ); } + + #[test] + fn test_aggregator_is_at_least(test_env in arb_test_env_non_equivalent(10)) { + println!("Testing test_aggregator_is_at_least {:?}", test_env); + let element_type = ElementType::U64; + let use_type = UseType::UseResourceType; + + let mut h = setup(test_env.executor_mode, test_env.aggregator_execution_mode, 10); + + let agg_loc = AggregatorLocation::new(*h.account.address(), element_type, use_type, 0); + + let txns = vec![ + (SUCCESS, h.init(None, use_type, element_type, StructType::Aggregator)), + (SUCCESS, h.init(None, use_type, element_type, StructType::Snapshot)), + (SUCCESS, h.init(None, use_type, ElementType::String, StructType::DerivedString)), + (SUCCESS, h.new_add(&agg_loc, 400, 100)), + (SUCCESS, h.add(&agg_loc, 50)), + (SUCCESS, h.add(&agg_loc, 50)), + (SUCCESS, h.add_if_at_least(&agg_loc, 180, 50)), + (SUCCESS, h.sub(&agg_loc, 50)), + (SUCCESS, h.add_if_at_least(&agg_loc, 220, 50)), + (SUCCESS, h.check(&agg_loc, 200)), + ]; + + h.run_block_in_parts_and_check( + test_env.block_split, + txns, + ); + } } #[test] diff --git a/aptos-move/framework/aptos-framework/doc/aggregator_v2.md b/aptos-move/framework/aptos-framework/doc/aggregator_v2.md index a13bd8b64e00d..5c6546de16e71 100644 --- a/aptos-move/framework/aptos-framework/doc/aggregator_v2.md +++ b/aptos-move/framework/aptos-framework/doc/aggregator_v2.md @@ -46,6 +46,7 @@ which has no parallelism impact. - [Function `create_unbounded_aggregator`](#@Specification_1_create_unbounded_aggregator) - [Function `try_add`](#@Specification_1_try_add) - [Function `try_sub`](#@Specification_1_try_sub) + - [Function `is_at_least_impl`](#@Specification_1_is_at_least_impl) - [Function `read`](#@Specification_1_read) - [Function `snapshot`](#@Specification_1_snapshot) - [Function `create_snapshot`](#@Specification_1_create_snapshot) @@ -468,7 +469,7 @@ If subtraction would result in a negative value, false is re -
fun is_at_least_impl<IntElement: copy, drop>(aggregator: &aggregator_v2::Aggregator<IntElement>, min_amount: IntElement): bool
+
fun is_at_least_impl<IntElement>(aggregator: &aggregator_v2::Aggregator<IntElement>, min_amount: IntElement): bool
 
@@ -477,7 +478,7 @@ If subtraction would result in a negative value, false is re Implementation -
native fun is_at_least_impl<IntElement: copy + drop>(aggregator: &Aggregator<IntElement>, min_amount: IntElement): bool;
+
native fun is_at_least_impl<IntElement>(aggregator: &Aggregator<IntElement>, min_amount: IntElement): bool;
 
@@ -490,7 +491,7 @@ If subtraction would result in a negative value, false is re -
public fun is_at_least<IntElement: copy, drop>(aggregator: &aggregator_v2::Aggregator<IntElement>, min_amount: IntElement): bool
+
public fun is_at_least<IntElement>(aggregator: &aggregator_v2::Aggregator<IntElement>, min_amount: IntElement): bool
 
@@ -499,7 +500,7 @@ If subtraction would result in a negative value, false is re Implementation -
public fun is_at_least<IntElement: copy + drop>(aggregator: &Aggregator<IntElement>, min_amount: IntElement): bool {
+
public fun is_at_least<IntElement>(aggregator: &Aggregator<IntElement>, min_amount: IntElement): bool {
     assert!(features::aggregator_v2_is_at_least_api_enabled(), EAGGREGATOR_API_V2_NOT_ENABLED);
     is_at_least_impl(aggregator, min_amount)
 }
@@ -801,6 +802,22 @@ DEPRECATED, use derive_string_concat() instead. always raises EAGGREGATOR_FUNCTI
 
 
 
+
pragma opaque;
+
+ + + + + +### Function `is_at_least_impl` + + +
fun is_at_least_impl<IntElement>(aggregator: &aggregator_v2::Aggregator<IntElement>, min_amount: IntElement): bool
+
+ + + +
pragma opaque;
 
diff --git a/aptos-move/framework/aptos-framework/sources/aggregator_v2/aggregator_v2.move b/aptos-move/framework/aptos-framework/sources/aggregator_v2/aggregator_v2.move index aec0c23f794a3..b46f383e2407e 100644 --- a/aptos-move/framework/aptos-framework/sources/aggregator_v2/aggregator_v2.move +++ b/aptos-move/framework/aptos-framework/sources/aggregator_v2/aggregator_v2.move @@ -108,9 +108,9 @@ module aptos_framework::aggregator_v2 { assert!(try_sub(aggregator, value), error::out_of_range(EAGGREGATOR_UNDERFLOW)); } - native fun is_at_least_impl(aggregator: &Aggregator, min_amount: IntElement): bool; + native fun is_at_least_impl(aggregator: &Aggregator, min_amount: IntElement): bool; - public fun is_at_least(aggregator: &Aggregator, min_amount: IntElement): bool { + public fun is_at_least(aggregator: &Aggregator, min_amount: IntElement): bool { assert!(features::aggregator_v2_is_at_least_api_enabled(), EAGGREGATOR_API_V2_NOT_ENABLED); is_at_least_impl(aggregator, min_amount) } diff --git a/aptos-move/framework/aptos-framework/sources/aggregator_v2/aggregator_v2.spec.move b/aptos-move/framework/aptos-framework/sources/aggregator_v2/aggregator_v2.spec.move index 459978eaa7186..ad53181cd793e 100644 --- a/aptos-move/framework/aptos-framework/sources/aggregator_v2/aggregator_v2.spec.move +++ b/aptos-move/framework/aptos-framework/sources/aggregator_v2/aggregator_v2.spec.move @@ -19,6 +19,11 @@ spec aptos_framework::aggregator_v2 { pragma opaque; } + spec is_at_least_impl { + // TODO: temporary mockup. + pragma opaque; + } + spec read { // TODO: temporary mockup. pragma opaque; diff --git a/aptos-move/framework/move-stdlib/doc/features.md b/aptos-move/framework/move-stdlib/doc/features.md index 3a31e7c473137..72a73a1cc3982 100644 --- a/aptos-move/framework/move-stdlib/doc/features.md +++ b/aptos-move/framework/move-stdlib/doc/features.md @@ -241,6 +241,15 @@ Lifetime: transient + + + + +
const AGGREGATOR_V2_IS_AT_LEAST_API: u64 = 66;
+
+ + + Whether the new aptos_stdlib::type_info::chain_id() native for fetching the chain ID is enabled. @@ -2793,9 +2802,8 @@ Lifetime: transient Implementation -
public fun aggregator_v2_is_at_least_api_enabled(): bool {
-    false
-    // is_enabled(AGGREGATOR_V2_IS_AT_LEAST_API)
+
public fun aggregator_v2_is_at_least_api_enabled(): bool acquires Features {
+    is_enabled(AGGREGATOR_V2_IS_AT_LEAST_API)
 }
 
diff --git a/aptos-move/framework/move-stdlib/sources/configs/features.move b/aptos-move/framework/move-stdlib/sources/configs/features.move index f8a7a607f4768..5158250b2794c 100644 --- a/aptos-move/framework/move-stdlib/sources/configs/features.move +++ b/aptos-move/framework/move-stdlib/sources/configs/features.move @@ -514,9 +514,10 @@ module std::features { is_enabled(PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS) } - public fun aggregator_v2_is_at_least_api_enabled(): bool { - false - // is_enabled(AGGREGATOR_V2_IS_AT_LEAST_API) + const AGGREGATOR_V2_IS_AT_LEAST_API: u64 = 66; + + public fun aggregator_v2_is_at_least_api_enabled(): bool acquires Features { + is_enabled(AGGREGATOR_V2_IS_AT_LEAST_API) } /// Whether we use more efficient native implementation of computing object derived address diff --git a/aptos-move/framework/src/natives/aggregator_natives/aggregator_v2.rs b/aptos-move/framework/src/natives/aggregator_natives/aggregator_v2.rs index fdc1f5f55398a..13d9b5611950b 100644 --- a/aptos-move/framework/src/natives/aggregator_natives/aggregator_v2.rs +++ b/aptos-move/framework/src/natives/aggregator_natives/aggregator_v2.rs @@ -291,7 +291,7 @@ fn native_is_at_least_impl( debug_assert_eq!(args.len(), 2); debug_assert_eq!(ty_args.len(), 1); - context.charge(AGGREGATOR_V2_TRY_SUB_BASE)?; + context.charge(AGGREGATOR_V2_IS_AT_LEAST_BASE)?; let aggregator_value_ty = &ty_args[0]; let rhs = pop_value_by_type(aggregator_value_ty, &mut args, EUNSUPPORTED_AGGREGATOR_TYPE)?; diff --git a/types/src/on_chain_config/aptos_features.rs b/types/src/on_chain_config/aptos_features.rs index 010b69f33600c..eb7bcfabbaf49 100644 --- a/types/src/on_chain_config/aptos_features.rs +++ b/types/src/on_chain_config/aptos_features.rs @@ -82,6 +82,7 @@ pub enum FeatureFlag { DISPATCHABLE_FUNGIBLE_ASSET = 63, NEW_ACCOUNTS_DEFAULT_TO_FA_APT_STORE = 64, OPERATIONS_DEFAULT_TO_FA_APT_STORE = 65, + AGGREGATOR_V2_IS_AT_LEAST_API = 66, } impl FeatureFlag { @@ -144,6 +145,7 @@ impl FeatureFlag { FeatureFlag::DISPATCHABLE_FUNGIBLE_ASSET, FeatureFlag::REMOVE_DETAILED_ERROR_FROM_HASH, FeatureFlag::CONCURRENT_FUNGIBLE_ASSETS, + FeatureFlag::AGGREGATOR_V2_IS_AT_LEAST_API, ] } }