From cada1a7b61235f45e06359ff5440c25f97b190fa Mon Sep 17 00:00:00 2001 From: Andrea Giacobino Date: Sun, 26 May 2024 21:05:41 +0200 Subject: [PATCH] set the target block fullness to 35% (#2816) * set the target block fullness to 35% * update tests constants for target block fullness * add fee integration tests for moonbeam and moonriver runtimes --------- Co-authored-by: Rodrigo Quelhas --- runtime/moonbase/src/lib.rs | 2 +- runtime/moonbase/tests/integration_test.rs | 38 ++--- runtime/moonbeam/src/lib.rs | 4 +- runtime/moonbeam/tests/integration_test.rs | 133 +++++++++++++++++- runtime/moonriver/src/lib.rs | 2 +- runtime/moonriver/tests/integration_test.rs | 133 +++++++++++++++++- test/helpers/constants.ts | 6 +- .../test-fees/test-fee-multiplier-max.ts | 4 +- .../test-fees/test-fee-multiplier-xcm.ts | 4 +- .../moonbase/test-fees/test-length-fees.ts | 4 +- 10 files changed, 293 insertions(+), 37 deletions(-) diff --git a/runtime/moonbase/src/lib.rs b/runtime/moonbase/src/lib.rs index c072d3ec5e..ede2456965 100644 --- a/runtime/moonbase/src/lib.rs +++ b/runtime/moonbase/src/lib.rs @@ -412,7 +412,7 @@ parameter_types! { = U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS); /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less /// than this will decrease the weight and more will increase. - pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(50); + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(35); /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to /// change the fees more rapidly. This fast multiplier responds by doubling/halving in /// approximately one hour at extreme block congestion levels. diff --git a/runtime/moonbase/tests/integration_test.rs b/runtime/moonbase/tests/integration_test.rs index aeb9965aef..5f372a6eb2 100644 --- a/runtime/moonbase/tests/integration_test.rs +++ b/runtime/moonbase/tests/integration_test.rs @@ -2962,54 +2962,54 @@ mod fee_tests { assert_eq!( sim(1_000_000_000, Perbill::from_percent(0), 1), - U256::from(998_002_000), + U256::from(998_600_980), ); assert_eq!( sim(1_000_000_000, Perbill::from_percent(25), 1), - U256::from(999_000_500), + U256::from(999_600_080), ); assert_eq!( sim(1_000_000_000, Perbill::from_percent(50), 1), - U256::from(1_000_000_000), + U256::from(1_000_600_180), ); assert_eq!( sim(1_000_000_000, Perbill::from_percent(100), 1), - U256::from(1_002_002_000), + U256::from(1_002_603_380), ); - // 1 "real" hour (at 12-second blocks) + // 1 "real" hour (at 6-second blocks) assert_eq!( - sim(1_000_000_000, Perbill::from_percent(0), 300), - U256::from(548_811_855), + sim(1_000_000_000, Perbill::from_percent(0), 600), + U256::from(431_710_642), ); assert_eq!( - sim(1_000_000_000, Perbill::from_percent(25), 300), - U256::from(740_818_257), + sim(1_000_000_000, Perbill::from_percent(25), 600), + U256::from(786_627_866), ); assert_eq!( - sim(1_000_000_000, Perbill::from_percent(50), 300), - U256::from(1_000_000_000), + sim(1_000_000_000, Perbill::from_percent(50), 600), + U256::from(1_433_329_383u128), ); assert_eq!( - sim(1_000_000_000, Perbill::from_percent(100), 300), - U256::from(1_822_118_072u128), + sim(1_000_000_000, Perbill::from_percent(100), 600), + U256::from(4_758_812_897u128), ); - // 1 "real" day (at 12-second blocks) + // 1 "real" day (at 6-second blocks) assert_eq!( - sim(1_000_000_000, Perbill::from_percent(0), 7200), + sim(1_000_000_000, Perbill::from_percent(0), 14400), U256::from(125_000_000), // lower bound enforced ); assert_eq!( - sim(1_000_000_000, Perbill::from_percent(25), 7200), + sim(1_000_000_000, Perbill::from_percent(25), 14400), U256::from(125_000_000), ); assert_eq!( - sim(1_000_000_000, Perbill::from_percent(50), 7200), - U256::from(1_000_000_000u128), + sim(1_000_000_000, Perbill::from_percent(50), 14400), + U256::from(5_653_326_895_069u128), ); assert_eq!( - sim(1_000_000_000, Perbill::from_percent(100), 7200), + sim(1_000_000_000, Perbill::from_percent(100), 14400), U256::from(125_000_000_000_000u128), // upper bound enforced ); }); diff --git a/runtime/moonbeam/src/lib.rs b/runtime/moonbeam/src/lib.rs index bd085bbb89..3bbd0d11ac 100644 --- a/runtime/moonbeam/src/lib.rs +++ b/runtime/moonbeam/src/lib.rs @@ -200,7 +200,7 @@ pub fn native_version() -> NativeVersion { } const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -const NORMAL_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_mul(3).saturating_div(4); +pub const NORMAL_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_mul(3).saturating_div(4); // Here we assume Ethereum's base fee of 21000 gas and convert to weight, but we // subtract roughly the cost of a balance transfer from it (about 1/3 the cost) // and some cost to account for per-byte-fee. @@ -394,7 +394,7 @@ parameter_types! { = U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS); /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less /// than this will decrease the weight and more will increase. - pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(50); + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(35); /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to /// change the fees more rapidly. This low value causes changes to occur slowly over time. pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(4, 1_000); diff --git a/runtime/moonbeam/tests/integration_test.rs b/runtime/moonbeam/tests/integration_test.rs index 1c16839f58..112ac878b4 100644 --- a/runtime/moonbeam/tests/integration_test.rs +++ b/runtime/moonbeam/tests/integration_test.rs @@ -2667,16 +2667,17 @@ fn evm_success_keeps_substrate_events() { #[cfg(test)] mod fee_tests { use super::*; + use fp_evm::FeeCalculator; use frame_support::{ - traits::ConstU128, + traits::{ConstU128, OnFinalize}, weights::{ConstantMultiplier, WeightToFee}, }; use moonbeam_runtime::{ currency, LengthToFee, MinimumMultiplier, RuntimeBlockWeights, SlowAdjustingFeeUpdate, - TargetBlockFullness, TransactionPayment, + TargetBlockFullness, NORMAL_WEIGHT, WEIGHT_PER_GAS, }; use sp_core::Get; - use sp_runtime::FixedPointNumber; + use sp_runtime::{BuildStorage, FixedPointNumber, Perbill}; fn run_with_system_weight(w: Weight, mut assertions: F) where @@ -2757,4 +2758,130 @@ mod fee_tests { ); }); } + + #[test] + fn test_min_gas_price_is_deterministic() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier = sp_runtime::FixedU128::from_u32(1); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual = TransactionPaymentAsGasPrice::min_gas_price().0; + let expected: U256 = multiplier + .saturating_mul_int(currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128)) + .into(); + + assert_eq!(expected, actual); + }); + } + + #[test] + fn test_min_gas_price_has_no_precision_loss_from_saturating_mul_int() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier_1 = sp_runtime::FixedU128::from_float(0.999593900000000000); + let multiplier_2 = sp_runtime::FixedU128::from_float(0.999593200000000000); + + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_1); + let a = TransactionPaymentAsGasPrice::min_gas_price(); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_2); + let b = TransactionPaymentAsGasPrice::min_gas_price(); + + assert_ne!( + a, b, + "both gas prices were equal, unexpected precision loss incurred" + ); + }); + } + + #[test] + fn test_fee_scenarios() { + use sp_runtime::FixedU128; + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let weight_fee_per_gas = currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128); + let sim = |start_gas_price: u128, fullness: Perbill, num_blocks: u64| -> U256 { + let start_multiplier = + FixedU128::from_rational(start_gas_price, weight_fee_per_gas); + pallet_transaction_payment::NextFeeMultiplier::::set(start_multiplier); + + let block_weight = NORMAL_WEIGHT * fullness; + + for i in 0..num_blocks { + System::set_block_number(i as u32); + System::set_block_consumed_resources(block_weight, 0); + TransactionPayment::on_finalize(i as u32); + } + + TransactionPaymentAsGasPrice::min_gas_price().0 + }; + + // The expected values are the ones observed during test execution, + // they are expected to change when parameters that influence + // the fee calculation are changed, and should be updated accordingly. + // If a test fails when nothing specific to fees has changed, + // it may indicate an unexpected collateral effect and should be investigated + + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 1), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 1), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 1), + U256::from(125_075_022_500u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 1), + U256::from(125_325_422_500u128), + ); + + // 1 "real" hour (at 12-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 600), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 600), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 600), + U256::from(179_166_172_951u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 600), + U256::from(594_851_612_166u128), + ); + + // 1 "real" day (at 12-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 14400), + U256::from(125_000_000_000u128), // lower bound enforced + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 14400), + U256::from(125_000_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 14400), + U256::from(706_665_861_883_635u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 14400), + U256::from(12_500_000_000_000_000u128), // upper bound enforced + ); + }); + } } diff --git a/runtime/moonriver/src/lib.rs b/runtime/moonriver/src/lib.rs index 00a56e2d0e..ee53d14205 100644 --- a/runtime/moonriver/src/lib.rs +++ b/runtime/moonriver/src/lib.rs @@ -396,7 +396,7 @@ parameter_types! { = U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS); /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less /// than this will decrease the weight and more will increase. - pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(50); + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(35); /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to /// change the fees more rapidly. This low value causes changes to occur slowly over time. pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(4, 1_000); diff --git a/runtime/moonriver/tests/integration_test.rs b/runtime/moonriver/tests/integration_test.rs index a2b57635de..9bbad4c0b6 100644 --- a/runtime/moonriver/tests/integration_test.rs +++ b/runtime/moonriver/tests/integration_test.rs @@ -2580,16 +2580,17 @@ fn evm_success_keeps_substrate_events() { #[cfg(test)] mod fee_tests { use super::*; + use fp_evm::FeeCalculator; use frame_support::{ - traits::ConstU128, + traits::{ConstU128, OnFinalize}, weights::{ConstantMultiplier, WeightToFee}, }; use moonriver_runtime::{ currency, LengthToFee, MinimumMultiplier, RuntimeBlockWeights, SlowAdjustingFeeUpdate, - TargetBlockFullness, TransactionPayment, + TargetBlockFullness, NORMAL_WEIGHT, WEIGHT_PER_GAS, }; use sp_core::Get; - use sp_runtime::FixedPointNumber; + use sp_runtime::{BuildStorage, FixedPointNumber, Perbill}; fn run_with_system_weight(w: Weight, mut assertions: F) where @@ -2668,4 +2669,130 @@ mod fee_tests { ); }); } + + #[test] + fn test_min_gas_price_is_deterministic() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier = sp_runtime::FixedU128::from_u32(1); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier); + let actual = TransactionPaymentAsGasPrice::min_gas_price().0; + let expected: U256 = multiplier + .saturating_mul_int(currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128)) + .into(); + + assert_eq!(expected, actual); + }); + } + + #[test] + fn test_min_gas_price_has_no_precision_loss_from_saturating_mul_int() { + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let multiplier_1 = sp_runtime::FixedU128::from_float(0.999593900000000000); + let multiplier_2 = sp_runtime::FixedU128::from_float(0.999593200000000000); + + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_1); + let a = TransactionPaymentAsGasPrice::min_gas_price(); + pallet_transaction_payment::NextFeeMultiplier::::set(multiplier_2); + let b = TransactionPaymentAsGasPrice::min_gas_price(); + + assert_ne!( + a, b, + "both gas prices were equal, unexpected precision loss incurred" + ); + }); + } + + #[test] + fn test_fee_scenarios() { + use sp_runtime::FixedU128; + let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + t.execute_with(|| { + let weight_fee_per_gas = currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128); + let sim = |start_gas_price: u128, fullness: Perbill, num_blocks: u64| -> U256 { + let start_multiplier = + FixedU128::from_rational(start_gas_price, weight_fee_per_gas); + pallet_transaction_payment::NextFeeMultiplier::::set(start_multiplier); + + let block_weight = NORMAL_WEIGHT * fullness; + + for i in 0..num_blocks { + System::set_block_number(i as u32); + System::set_block_consumed_resources(block_weight, 0); + TransactionPayment::on_finalize(i as u32); + } + + TransactionPaymentAsGasPrice::min_gas_price().0 + }; + + // The expected values are the ones observed during test execution, + // they are expected to change when parameters that influence + // the fee calculation are changed, and should be updated accordingly. + // If a test fails when nothing specific to fees has changed, + // it may indicate an unexpected collateral effect and should be investigated + + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 1), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 1), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 1), + U256::from(1_250_750_225u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 1), + U256::from(1_253_254_225u128), + ); + + // 1 "real" hour (at 6-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 600), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 600), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 600), + U256::from(1_791_661_729u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 600), + U256::from(5_948_516_121u128), + ); + + // 1 "real" day (at 6-second blocks) + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(0), 14400), + U256::from(1_250_000_000u128), // lower bound enforced + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(25), 14400), + U256::from(1_250_000_000u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(50), 14400), + U256::from(7_066_658_618_836u128), + ); + assert_eq!( + sim(1_000_000_000, Perbill::from_percent(100), 14400), + U256::from(125_000_000_000_000u128), // upper bound enforced + ); + }); + } } diff --git a/test/helpers/constants.ts b/test/helpers/constants.ts index b850322cc3..0b84ceece5 100644 --- a/test/helpers/constants.ts +++ b/test/helpers/constants.ts @@ -33,7 +33,7 @@ export const RUNTIME_CONSTANTS = { MAX_FEE_MULTIPLIER: 100_000_000_000_000_000_000_000n, MIN_BASE_FEE_IN_WEI: "125000000", MAX_BASE_FEE_IN_WEI: "125000000000000", - TARGET_FILL_PERMILL: 500_000n, + TARGET_FILL_PERMILL: 350_000n, OLD_TARGET_FILL_PERMILL: 250_000n, }, MOONRIVER: { @@ -41,7 +41,7 @@ export const RUNTIME_CONSTANTS = { MAX_FEE_MULTIPLIER: 100_000_000_000_000_000_000_000n, MIN_BASE_FEE_IN_WEI: "1250000000", MAX_BASE_FEE_IN_WEI: "125000000000000", - TARGET_FILL_PERMILL: 500_000n, + TARGET_FILL_PERMILL: 350_000n, OLD_TARGET_FILL_PERMILL: 250_000n, }, MOONBEAM: { @@ -49,7 +49,7 @@ export const RUNTIME_CONSTANTS = { MAX_FEE_MULTIPLIER: 100_000_000_000_000_000_000_000n, MIN_BASE_FEE_IN_WEI: "125000000000", MAX_BASE_FEE_IN_WEI: "12500000000000000", - TARGET_FILL_PERMILL: 500_000n, + TARGET_FILL_PERMILL: 350_000n, OLD_TARGET_FILL_PERMILL: 250_000n, }, } as const; diff --git a/test/suites/dev/moonbase/test-fees/test-fee-multiplier-max.ts b/test/suites/dev/moonbase/test-fees/test-fee-multiplier-max.ts index 735a888cb1..b9113ee790 100644 --- a/test/suites/dev/moonbase/test-fees/test-fee-multiplier-max.ts +++ b/test/suites/dev/moonbase/test-fees/test-fee-multiplier-max.ts @@ -139,7 +139,7 @@ describeSuite({ blockNumber = (await context.polkadotJs().rpc.chain.getHeader()).number.toBigInt(); baseFeePerGas = (await context.viem().getBlock({ blockNumber: blockNumber })) .baseFeePerGas!; - expect(baseFeePerGas).to.equal(124_752_134_188_357n); + expect(baseFeePerGas).to.equal(124_827_007_821_127n); const rawSigned = await createEthersTransaction(context, { to: contractAddress, @@ -171,7 +171,7 @@ describeSuite({ expect(withdrawEvents?.length).to.equal(1); const withdrawEvent = withdrawEvents![0]; const amount = withdrawEvent.event.data.amount.toBigInt(); - expect(amount).to.equal(11_867_920_029_606_778_124n); + expect(amount).to.equal(11_875_042_908_039_453_764n); }, }); }, diff --git a/test/suites/dev/moonbase/test-fees/test-fee-multiplier-xcm.ts b/test/suites/dev/moonbase/test-fees/test-fee-multiplier-xcm.ts index e19abf974a..b44e057a03 100644 --- a/test/suites/dev/moonbase/test-fees/test-fee-multiplier-xcm.ts +++ b/test/suites/dev/moonbase/test-fees/test-fee-multiplier-xcm.ts @@ -14,7 +14,7 @@ import { // export const TARGET_FILL_AMOUNT = // ((MAX_BLOCK_WEIGHT * 0.75 * 0.25 - EXTRINSIC_BASE_WEIGHT) / MAX_BLOCK_WEIGHT) * 1_000_000_000; // In 0.9.43 rootTesting::fillBlock() now uses more weight so we need to account for that -const TARGET_FILL_AMOUNT = 374_713_000; +const TARGET_FILL_AMOUNT = 262_212_900; // Note on the values from 'transactionPayment.nextFeeMultiplier': this storage item is actually a // FixedU128, which is basically a u128 with an implicit denominator of 10^18. However, this @@ -102,6 +102,8 @@ describeSuite({ // this is useful to manually find out what is the // TARGET_FILL_AMOUNT that will result in a static fee multiplier + // run the tests with + // pnpm moonwall test dev_moonbase -d test-fees D011604T02 // console.log(`pre ${initialValue.toHuman()}`); // console.log(`post ${postValue.toHuman()}`); // console.log(`diff ${initialValue.sub(postValue)}`); diff --git a/test/suites/dev/moonbase/test-fees/test-length-fees.ts b/test/suites/dev/moonbase/test-fees/test-length-fees.ts index 0e73c9db6c..2fdf3f346d 100644 --- a/test/suites/dev/moonbase/test-fees/test-length-fees.ts +++ b/test/suites/dev/moonbase/test-fees/test-length-fees.ts @@ -13,7 +13,7 @@ describeSuite({ title: "should have low balance transfer fees", test: async () => { const fee = await testBalanceTransfer(context); - expect(fee).toBeLessThanOrEqual(90215001520875n); + expect(fee).toBeLessThanOrEqual(90_215_001_520_875n); }, }); @@ -22,7 +22,7 @@ describeSuite({ title: "should have expensive runtime-upgrade fees", test: async () => { const fee = await testRuntimeUpgrade(context); - expect(fee).toBeLessThanOrEqual(9274087607203200560n); + expect(fee).toBeLessThanOrEqual(9_274_115_948_197_898_805n); }, }); },