diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index bde01f335b19c..313470715ee4f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -245,6 +245,9 @@ impl pallet_transaction_payment::Config for Runtime { type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_transaction_payment::BenchmarkConfig for Runtime {} + parameter_types! { pub const AssetDeposit: Balance = UNITS / 10; // 1 / 10 UNITS deposit to create asset pub const AssetAccountDeposit: Balance = deposit(1, 16); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 6ee07f6fe0a8a..5f45999d74783 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -275,6 +275,9 @@ impl pallet_transaction_payment::Config for Runtime { type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_transaction_payment::BenchmarkConfig for Runtime {} + parameter_types! { pub const AssetDeposit: Balance = UNITS / 10; // 1 / 10 WND deposit to create asset pub const AssetAccountDeposit: Balance = deposit(1, 16); @@ -2227,6 +2230,7 @@ pallet_revive::impl_runtime_apis_plus_revive_traits!( use xcm_config::{MaxAssetsIntoHolding, WestendLocation}; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use testnet_parachains_constants::westend::locations::{PeopleParaId, PeopleLocation}; parameter_types! { pub ExistentialDepositAsset: Option = Some(( diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 7dbcbb0975eb4..c506beca63c16 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -382,6 +382,9 @@ impl pallet_transaction_payment::Config for Runtime { type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_transaction_payment::BenchmarkConfig for Runtime {} + parameter_types! { pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); @@ -1059,7 +1062,6 @@ impl_runtime_apis! { use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types // are referenced in that call. diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 6e55033bc20ba..48242613c3708 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -372,6 +372,9 @@ impl pallet_transaction_payment::Config for Runtime { type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_transaction_payment::BenchmarkConfig for Runtime {} + parameter_types! { pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); @@ -1002,7 +1005,6 @@ impl_runtime_apis! { use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types // are referenced in that call. diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 85521a8db084e..e17933e23da3f 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -252,6 +252,9 @@ impl pallet_transaction_payment::Config for Runtime { type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_transaction_payment::BenchmarkConfig for Runtime {} + parameter_types! { // One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes. pub const DepositBase: Balance = deposit(1, 88); @@ -1112,7 +1115,6 @@ impl_runtime_apis! { use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types // are referenced in that call. @@ -1148,6 +1150,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use xcm_config::WndLocation; use testnet_parachains_constants::westend::locations::{AssetHubParaId, AssetHubLocation}; diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index dec1be2786bd2..8e44d062d703e 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -259,6 +259,9 @@ impl pallet_transaction_payment::Config for Runtime { type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_transaction_payment::BenchmarkConfig for Runtime {} + parameter_types! { pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); @@ -880,7 +883,6 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; - // This is defined once again in dispatch_benchmark, because list_benchmarks! // and add_benchmarks! are macros exported by define_benchmarks! macros and those types // are referenced in that call. @@ -915,6 +917,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} + use testnet_parachains_constants::rococo::locations::{AssetHubParaId, AssetHubLocation}; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 2f224384a904f..fc88f8d98f75c 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -438,6 +438,9 @@ impl pallet_transaction_payment::Config for Runtime { type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_transaction_payment::BenchmarkConfig for Runtime {} + parameter_types! { pub const MinimumPeriod: u64 = SLOT_DURATION / 2; } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index bdef88df7e8e1..4de7df6d1cc32 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -491,6 +491,9 @@ impl pallet_transaction_payment::Config for Runtime { type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_transaction_payment::BenchmarkConfig for Runtime {} + parameter_types! { pub const MinimumPeriod: u64 = SLOT_DURATION / 2; } diff --git a/prdoc/pr_10444.prdoc b/prdoc/pr_10444.prdoc new file mode 100644 index 0000000000000..5382e903605c8 --- /dev/null +++ b/prdoc/pr_10444.prdoc @@ -0,0 +1,16 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Improve `charge_transaction_payment benchmark` ergonomics + +doc: + - audience: Runtime Dev + description: | + Adds a `setup_benchmark_environment()` hook to allow runtimes to configure + required state before running the benchmark (e.g., setting block author for + fee distribution). Also fixes `amount_to_endow` calculation to use actual + computed fee and ensure it meets the existential deposit. + +crates: + - name: pallet-transaction-payment + bump: patch diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 3a54a6bb09f13..bd79f30099a5f 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -625,6 +625,9 @@ impl pallet_transaction_payment::Config for Runtime { type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_transaction_payment::BenchmarkConfig for Runtime {} + pub type AssetsFreezerInstance = pallet_assets_freezer::Instance1; impl pallet_assets_freezer::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; diff --git a/substrate/frame/staking-async/runtimes/parachain/src/lib.rs b/substrate/frame/staking-async/runtimes/parachain/src/lib.rs index 3346ff10736ea..8625e4a57a061 100644 --- a/substrate/frame/staking-async/runtimes/parachain/src/lib.rs +++ b/substrate/frame/staking-async/runtimes/parachain/src/lib.rs @@ -247,6 +247,9 @@ impl pallet_transaction_payment::Config for Runtime { type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_transaction_payment::BenchmarkConfig for Runtime {} + parameter_types! { pub const AssetDeposit: Balance = UNITS / 10; // 1 / 10 WND deposit to create asset pub const AssetAccountDeposit: Balance = deposit(1, 16); diff --git a/substrate/frame/staking-async/runtimes/rc/src/lib.rs b/substrate/frame/staking-async/runtimes/rc/src/lib.rs index 950010ee6cc14..4037bdffd421f 100644 --- a/substrate/frame/staking-async/runtimes/rc/src/lib.rs +++ b/substrate/frame/staking-async/runtimes/rc/src/lib.rs @@ -534,6 +534,9 @@ impl pallet_transaction_payment::Config for Runtime { type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_transaction_payment::BenchmarkConfig for Runtime {} + parameter_types! { pub const MinimumPeriod: u64 = SLOT_DURATION / 2; } diff --git a/substrate/frame/transaction-payment/src/benchmarking.rs b/substrate/frame/transaction-payment/src/benchmarking.rs index 70ecfbf149e57..e718ab65cb276 100644 --- a/substrate/frame/transaction-payment/src/benchmarking.rs +++ b/substrate/frame/transaction-payment/src/benchmarking.rs @@ -26,7 +26,21 @@ use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; use frame_system::{EventRecord, RawOrigin}; use sp_runtime::traits::{AsTransactionAuthorizedOrigin, DispatchTransaction, Dispatchable}; -fn assert_last_event(generic_event: ::RuntimeEvent) { +/// Benchmark configuration trait. +/// +/// This extends the pallet's Config trait to allow runtimes to set up any +/// required state before running benchmarks. For example, runtimes that +/// distribute fees to block authors may need to set the author before +/// the benchmark runs. +pub trait Config: crate::Config { + /// Called at the start of each benchmark to set up any required state. + /// + /// The default implementation is a no-op. Runtimes can override this + /// to perform setup like setting the block author for fee distribution. + fn setup_benchmark_environment() {} +} + +fn assert_last_event(generic_event: ::RuntimeEvent) { let events = frame_system::Pallet::::events(); let system_event: ::RuntimeEvent = generic_event.into(); // compare to the last event record @@ -44,19 +58,17 @@ mod benchmarks { #[benchmark] fn charge_transaction_payment() { + ::setup_benchmark_environment(); + let caller: T::AccountId = account("caller", 0, 0); let existential_deposit = >::minimum_balance(); - let (amount_to_endow, tip) = if existential_deposit.is_zero() { - let min_tip: <::OnChargeTransaction as payment::OnChargeTransaction>::Balance = 1_000_000_000u32.into(); - (min_tip * 1000u32.into(), min_tip) - } else { - (existential_deposit * 1000u32.into(), existential_deposit) - }; - - >::endow_account(&caller, amount_to_endow); + // Use a reasonable minimum tip that works for most runtimes + let min_tip: BalanceOf = 1_000_000_000u32.into(); + let tip = if existential_deposit.is_zero() { min_tip } else { existential_deposit }; + // Build the call and dispatch info first so we can compute the actual fee let ext: ChargeTransactionPayment = ChargeTransactionPayment::from(tip); let inner = frame_system::Call::remark { remark: alloc::vec![] }; let call = T::RuntimeCall::from(inner); @@ -72,18 +84,32 @@ mod benchmarks { pays_fee: Pays::Yes, }; + // Calculate the actual fee that will be charged, then endow enough to cover it + // with a 10x buffer to account for any fee multiplier variations. + // Ensure we endow at least the existential deposit so the account can exist. + let len: u32 = 10; + let expected_fee = Pallet::::compute_fee(len, &info, tip); + let amount_to_endow = expected_fee.max(existential_deposit).saturating_mul(10u32.into()); + + >::endow_account(&caller, amount_to_endow); + #[block] { assert!(ext - .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 10, 0, |_| Ok( - post_info - )) + .test_run( + RawOrigin::Signed(caller.clone()).into(), + &call, + &info, + len as usize, + 0, + |_| Ok(post_info) + ) .unwrap() .is_ok()); } post_info.actual_weight.as_mut().map(|w| w.saturating_accrue(extension_weight)); - let actual_fee = Pallet::::compute_actual_fee(10, &info, &post_info, tip); + let actual_fee = Pallet::::compute_actual_fee(len, &info, &post_info, tip); assert_last_event::( Event::::TransactionFeePaid { who: caller, actual_fee, tip }.into(), ); diff --git a/substrate/frame/transaction-payment/src/lib.rs b/substrate/frame/transaction-payment/src/lib.rs index 4c20b0fdd298f..ce6948fa66540 100644 --- a/substrate/frame/transaction-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/src/lib.rs @@ -79,6 +79,8 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +#[cfg(feature = "runtime-benchmarks")] +pub use benchmarking::Config as BenchmarkConfig; mod payment; mod types; diff --git a/substrate/frame/transaction-payment/src/mock.rs b/substrate/frame/transaction-payment/src/mock.rs index 3995c41e8b197..57d588f00574e 100644 --- a/substrate/frame/transaction-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/src/mock.rs @@ -138,6 +138,9 @@ impl Config for Runtime { type WeightInfo = MockWeights; } +#[cfg(feature = "runtime-benchmarks")] +impl crate::BenchmarkConfig for Runtime {} + #[cfg(feature = "runtime-benchmarks")] pub fn new_test_ext() -> sp_io::TestExternalities { crate::tests::ExtBuilder::default()