From 979ba30935acb5daddc2ac87dc8701b384692c30 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 29 Jun 2022 21:26:07 +0100 Subject: [PATCH] backport minimum weight to fee to master (#5739) * propose fix fees * add tests to kusama runtime as well * better tests * last change * last update * Fix test * ignore tests again --- parachain/test-parachains/Cargo.toml | 2 +- runtime/common/src/lib.rs | 117 +---------------- runtime/kusama/Cargo.toml | 2 +- runtime/kusama/src/lib.rs | 125 ++++++++++++++++++ runtime/polkadot/Cargo.toml | 2 +- runtime/polkadot/src/lib.rs | 190 ++++++++++++++++++++++++--- runtime/test-runtime/Cargo.toml | 2 +- runtime/westend/Cargo.toml | 2 +- 8 files changed, 303 insertions(+), 139 deletions(-) diff --git a/parachain/test-parachains/Cargo.toml b/parachain/test-parachains/Cargo.toml index 6fe51fc0d3dc..63d3de210be5 100644 --- a/parachain/test-parachains/Cargo.toml +++ b/parachain/test-parachains/Cargo.toml @@ -6,7 +6,7 @@ description = "Integration tests using the test-parachains" edition = "2021" [dependencies] -tiny-keccak = "2.0.2" +tiny-keccak = { version = "2.0.2", features = ["keccak"] } parity-scale-codec = { version = "3.1.5", default-features = false, features = ["derive"] } adder = { package = "test-parachain-adder", path = "adder" } diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index 0a6ca7b6e9c8..73c3ae0c5f39 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -81,11 +81,11 @@ parameter_types! { pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to /// change the fees more rapidly. - pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000); + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(75, 1000_000); /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure /// that combined with `AdjustmentVariable`, we can recover from the minimum. /// See `multiplier_can_grow_from_zero`. - pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); + pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 10u128); /// Maximum length of block. Up to 5MB. pub BlockLength: limits::BlockLength = limits::BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); @@ -244,116 +244,3 @@ macro_rules! prod_or_fast { } }; } - -#[cfg(test)] -mod multiplier_tests { - use super::*; - use frame_support::{ - parameter_types, - weights::{DispatchClass, Weight}, - }; - use sp_core::H256; - use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, Convert, IdentityLookup, One}, - Perbill, - }; - - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; - type Block = frame_system::mocking::MockBlock; - - frame_support::construct_runtime!( - pub enum Runtime where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event} - } - ); - - parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const AvailableBlockRatio: Perbill = Perbill::one(); - pub BlockLength: frame_system::limits::BlockLength = - frame_system::limits::BlockLength::max(2 * 1024); - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(1024); - } - - impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Call = Call; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = Event; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; - } - - fn run_with_system_weight(w: Weight, mut assertions: F) - where - F: FnMut() -> (), - { - let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap() - .into(); - t.execute_with(|| { - System::set_block_consumed_resources(w, 0); - assertions() - }); - } - - #[test] - fn multiplier_can_grow_from_zero() { - let minimum_multiplier = MinimumMultiplier::get(); - let target = TargetBlockFullness::get() * - BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); - // if the min is too small, then this will not change, and we are doomed forever. - // the weight is 1/100th bigger than target. - run_with_system_weight(target * 101 / 100, || { - let next = SlowAdjustingFeeUpdate::::convert(minimum_multiplier); - assert!(next > minimum_multiplier, "{:?} !>= {:?}", next, minimum_multiplier); - }) - } - - #[test] - #[ignore] - fn multiplier_growth_simulator() { - // assume the multiplier is initially set to its minimum. We update it with values twice the - //target (target is 25%, thus 50%) and we see at which point it reaches 1. - let mut multiplier = MinimumMultiplier::get(); - let block_weight = TargetBlockFullness::get() * - BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap() * - 2; - let mut blocks = 0; - while multiplier <= Multiplier::one() { - run_with_system_weight(block_weight, || { - let next = SlowAdjustingFeeUpdate::::convert(multiplier); - // ensure that it is growing as well. - assert!(next > multiplier, "{:?} !>= {:?}", next, multiplier); - multiplier = next; - }); - blocks += 1; - println!("block = {} multiplier {:?}", blocks, multiplier); - } - } -} diff --git a/runtime/kusama/Cargo.toml b/runtime/kusama/Cargo.toml index 5c936764d7fb..17692ffbd05f 100644 --- a/runtime/kusama/Cargo.toml +++ b/runtime/kusama/Cargo.toml @@ -98,7 +98,7 @@ xcm-builder = { package = "xcm-builder", path = "../../xcm/xcm-builder", default [dev-dependencies] hex-literal = "0.3.4" -tiny-keccak = "2.0.2" +tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", git = "https://github.com/paritytech/substrate", branch = "master" } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } separator = "0.4.1" diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 93a6e6f836f0..98b217352429 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -2171,3 +2171,128 @@ mod tests_fess { assert_eq_error_rate!(deposit, UNITS * 16 / 100, UNITS / 100); } } + +#[cfg(test)] +mod multiplier_tests { + use super::*; + use frame_support::{dispatch::GetDispatchInfo, traits::OnFinalize}; + use runtime_common::{MinimumMultiplier, TargetBlockFullness}; + use separator::Separatable; + use sp_runtime::traits::Convert; + + fn run_with_system_weight(w: Weight, mut assertions: F) + where + F: FnMut() -> (), + { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); + } + + #[test] + fn multiplier_can_grow_from_zero() { + let minimum_multiplier = MinimumMultiplier::get(); + let target = TargetBlockFullness::get() * + BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = SlowAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!(next > minimum_multiplier, "{:?} !>= {:?}", next, minimum_multiplier); + }) + } + + #[test] + #[ignore] + fn multiplier_growth_simulator() { + // assume the multiplier is initially set to its minimum. We update it with values twice the + //target (target is 25%, thus 50%) and we see at which point it reaches 1. + let mut multiplier = MinimumMultiplier::get(); + let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); + let mut blocks = 0; + let mut fees_paid = 0; + + let call = frame_system::Call::::fill_block { + ratio: Perbill::from_rational( + block_weight, + BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(), + ), + }; + println!("calling {:?}", call); + let info = call.get_dispatch_info(); + // convert to outer call. + let call = Call::System(call); + let len = call.using_encoded(|e| e.len()) as u32; + + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap() + .into(); + // set the minimum + t.execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::set(MinimumMultiplier::get()); + }); + + while multiplier <= Multiplier::from_u32(1) { + t.execute_with(|| { + // imagine this tx was called. + let fee = TransactionPayment::compute_fee(len, &info, 0); + fees_paid += fee; + + // this will update the multiplier. + System::set_block_consumed_resources(block_weight, 0); + TransactionPayment::on_finalize(1); + let next = TransactionPayment::next_fee_multiplier(); + + assert!(next > multiplier, "{:?} !>= {:?}", next, multiplier); + multiplier = next; + + println!( + "block = {} / multiplier {:?} / fee = {:?} / fess so far {:?}", + blocks, + multiplier, + fee.separated_string(), + fees_paid.separated_string() + ); + }); + blocks += 1; + } + } + + #[test] + #[ignore] + fn multiplier_cool_down_simulator() { + // assume the multiplier is initially set to its minimum. We update it with values twice the + //target (target is 25%, thus 50%) and we see at which point it reaches 1. + let mut multiplier = Multiplier::from_u32(2); + let mut blocks = 0; + + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap() + .into(); + // set the minimum + t.execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + }); + + while multiplier > Multiplier::from_u32(0) { + t.execute_with(|| { + // this will update the multiplier. + TransactionPayment::on_finalize(1); + let next = TransactionPayment::next_fee_multiplier(); + + assert!(next < multiplier, "{:?} !>= {:?}", next, multiplier); + multiplier = next; + + println!("block = {} / multiplier {:?}", blocks, multiplier); + }); + blocks += 1; + } + } +} diff --git a/runtime/polkadot/Cargo.toml b/runtime/polkadot/Cargo.toml index 4763d7f04283..ef88115655e3 100644 --- a/runtime/polkadot/Cargo.toml +++ b/runtime/polkadot/Cargo.toml @@ -91,7 +91,7 @@ xcm-builder = { package = "xcm-builder", path = "../../xcm/xcm-builder", default [dev-dependencies] hex-literal = "0.3.4" -tiny-keccak = "2.0.2" +tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", git = "https://github.com/paritytech/substrate", branch = "master" } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } trie-db = "0.23.1" diff --git a/runtime/polkadot/src/lib.rs b/runtime/polkadot/src/lib.rs index 5cb94013c2fc..37c0778e680e 100644 --- a/runtime/polkadot/src/lib.rs +++ b/runtime/polkadot/src/lib.rs @@ -1998,11 +1998,11 @@ sp_api::impl_runtime_apis! { mod test_fees { use super::*; use frame_support::weights::{GetDispatchInfo, WeightToFee as WeightToFeeT}; - use keyring::Sr25519Keyring::Charlie; + use keyring::Sr25519Keyring::{Alice, Charlie}; use pallet_transaction_payment::Multiplier; use runtime_common::MinimumMultiplier; use separator::Separatable; - use sp_runtime::{assert_eq_error_rate, FixedPointNumber}; + use sp_runtime::{assert_eq_error_rate, FixedPointNumber, MultiAddress, MultiSignature}; #[test] fn payout_weight_portion() { @@ -2023,20 +2023,25 @@ mod test_fees { } #[test] - #[ignore] fn block_cost() { let max_block_weight = BlockWeights::get().max_block; let raw_fee = WeightToFee::weight_to_fee(&max_block_weight); - println!( - "Full Block weight == {} // WeightToFee(full_block) == {} plank", - max_block_weight, - raw_fee.separated_string(), - ); + let fee_with_multiplier = |m: Multiplier| { + println!( + "Full Block weight == {} // multiplier: {:?} // WeightToFee(full_block) == {} plank", + max_block_weight, + m, + m.saturating_mul_int(raw_fee).separated_string(), + ); + }; + fee_with_multiplier(MinimumMultiplier::get()); + fee_with_multiplier(Multiplier::from_rational(1, 2)); + fee_with_multiplier(Multiplier::from_u32(1)); + fee_with_multiplier(Multiplier::from_u32(2)); } #[test] - #[ignore] fn transfer_cost_min_multiplier() { let min_multiplier = MinimumMultiplier::get(); let call = pallet_balances::Call::::transfer_keep_alive { @@ -2044,29 +2049,51 @@ mod test_fees { value: Default::default(), }; let info = call.get_dispatch_info(); + println!("call = {:?} / info = {:?}", call, info); // convert to outer call. let call = Call::Balances(call); - let len = call.using_encoded(|e| e.len()) as u32; + let extra: SignedExtra = ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckMortality::::from(generic::Era::immortal()), + frame_system::CheckNonce::::from(1), + frame_system::CheckWeight::::new(), + pallet_transaction_payment::ChargeTransactionPayment::::from(0), + claims::PrevalidateAttests::::new(), + ); + let uxt = UncheckedExtrinsic { + function: call, + signature: Some(( + MultiAddress::Id(Alice.to_account_id()), + MultiSignature::Sr25519(Alice.sign(b"foo")), + extra, + )), + }; + let len = uxt.encoded_size(); let mut ext = sp_io::TestExternalities::new_empty(); - let mut test_with_multiplier = |m| { + let mut test_with_multiplier = |m: Multiplier| { ext.execute_with(|| { pallet_transaction_payment::NextFeeMultiplier::::put(m); - let fee = TransactionPayment::compute_fee(len, &info, 0); + let fee = TransactionPayment::query_fee_details(uxt.clone(), len as u32); println!( - "weight = {:?} // multiplier = {:?} // full transfer fee = {:?}", - info.weight.separated_string(), + "multiplier = {:?} // fee details = {:?} // final fee = {:?}", pallet_transaction_payment::NextFeeMultiplier::::get(), - fee.separated_string(), + fee, + fee.final_fee().separated_string(), ); }); }; test_with_multiplier(min_multiplier); - test_with_multiplier(Multiplier::saturating_from_rational(1, 1u128)); - test_with_multiplier(Multiplier::saturating_from_rational(1, 1_000u128)); - test_with_multiplier(Multiplier::saturating_from_rational(1, 1_000_000u128)); - test_with_multiplier(Multiplier::saturating_from_rational(1, 1_000_000_000u128)); + test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1u128)); + test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_0u128)); + test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_00u128)); + test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_000u128)); + test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_000_000u128)); + test_with_multiplier(Multiplier::saturating_from_rational(1u128, 1_000_000_000u128)); } #[test] @@ -2151,3 +2178,128 @@ mod test { ); } } + +#[cfg(test)] +mod multiplier_tests { + use super::*; + use frame_support::{dispatch::GetDispatchInfo, traits::OnFinalize}; + use runtime_common::{MinimumMultiplier, TargetBlockFullness}; + use separator::Separatable; + use sp_runtime::traits::Convert; + + fn run_with_system_weight(w: Weight, mut assertions: F) + where + F: FnMut() -> (), + { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap() + .into(); + t.execute_with(|| { + System::set_block_consumed_resources(w, 0); + assertions() + }); + } + + #[test] + fn multiplier_can_grow_from_zero() { + let minimum_multiplier = MinimumMultiplier::get(); + let target = TargetBlockFullness::get() * + BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); + // if the min is too small, then this will not change, and we are doomed forever. + // the weight is 1/100th bigger than target. + run_with_system_weight(target * 101 / 100, || { + let next = SlowAdjustingFeeUpdate::::convert(minimum_multiplier); + assert!(next > minimum_multiplier, "{:?} !>= {:?}", next, minimum_multiplier); + }) + } + + #[test] + #[ignore] + fn multiplier_growth_simulator() { + // assume the multiplier is initially set to its minimum. We update it with values twice the + //target (target is 25%, thus 50%) and we see at which point it reaches 1. + let mut multiplier = MinimumMultiplier::get(); + let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(); + let mut blocks = 0; + let mut fees_paid = 0; + + let call = frame_system::Call::::fill_block { + ratio: Perbill::from_rational( + block_weight, + BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap(), + ), + }; + println!("calling {:?}", call); + let info = call.get_dispatch_info(); + // convert to outer call. + let call = Call::System(call); + let len = call.using_encoded(|e| e.len()) as u32; + + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap() + .into(); + // set the minimum + t.execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::set(MinimumMultiplier::get()); + }); + + while multiplier <= Multiplier::from_u32(1) { + t.execute_with(|| { + // imagine this tx was called. + let fee = TransactionPayment::compute_fee(len, &info, 0); + fees_paid += fee; + + // this will update the multiplier. + System::set_block_consumed_resources(block_weight, 0); + TransactionPayment::on_finalize(1); + let next = TransactionPayment::next_fee_multiplier(); + + assert!(next > multiplier, "{:?} !>= {:?}", next, multiplier); + multiplier = next; + + println!( + "block = {} / multiplier {:?} / fee = {:?} / fess so far {:?}", + blocks, + multiplier, + fee.separated_string(), + fees_paid.separated_string() + ); + }); + blocks += 1; + } + } + + #[test] + #[ignore] + fn multiplier_cool_down_simulator() { + // assume the multiplier is initially set to its minimum. We update it with values twice the + //target (target is 25%, thus 50%) and we see at which point it reaches 1. + let mut multiplier = Multiplier::from_u32(2); + let mut blocks = 0; + + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap() + .into(); + // set the minimum + t.execute_with(|| { + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + }); + + while multiplier > Multiplier::from_u32(0) { + t.execute_with(|| { + // this will update the multiplier. + TransactionPayment::on_finalize(1); + let next = TransactionPayment::next_fee_multiplier(); + + assert!(next < multiplier, "{:?} !>= {:?}", next, multiplier); + multiplier = next; + + println!("block = {} / multiplier {:?}", blocks, multiplier); + }); + blocks += 1; + } + } +} diff --git a/runtime/test-runtime/Cargo.toml b/runtime/test-runtime/Cargo.toml index b7b2c6ec2b10..fa3a69df7f4d 100644 --- a/runtime/test-runtime/Cargo.toml +++ b/runtime/test-runtime/Cargo.toml @@ -65,7 +65,7 @@ xcm = { path = "../../xcm", default-features = false } [dev-dependencies] hex-literal = "0.3.4" -tiny-keccak = "2.0.2" +tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", git = "https://github.com/paritytech/substrate", branch = "master" } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } serde_json = "1.0.81" diff --git a/runtime/westend/Cargo.toml b/runtime/westend/Cargo.toml index 778483353ee3..3fbabea56a7c 100644 --- a/runtime/westend/Cargo.toml +++ b/runtime/westend/Cargo.toml @@ -94,7 +94,7 @@ xcm-builder = { package = "xcm-builder", path = "../../xcm/xcm-builder", default [dev-dependencies] hex-literal = "0.3.4" -tiny-keccak = "2.0.2" +tiny-keccak = { version = "2.0.2", features = ["keccak"] } keyring = { package = "sp-keyring", git = "https://github.com/paritytech/substrate", branch = "master" } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } serde_json = "1.0.81"