From 4e63b656db487153d6c028bd04d1704824191f47 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 1 Oct 2024 10:35:00 +0200 Subject: [PATCH 01/43] Add overhead benchmark to frame-omni-bencher --- Cargo.lock | 53 +++ cumulus/client/parachain-inherent/src/mock.rs | 1 + .../polkadot-parachain-lib/Cargo.toml | 34 +- .../polkadot-parachain-lib/src/command.rs | 25 +- .../src/common/command.rs | 16 +- cumulus/polkadot-parachain/src/main.rs | 5 +- cumulus/test/client/src/lib.rs | 6 +- cumulus/test/runtime/Cargo.toml | 4 + .../runtime/src/genesis_config_presets.rs | 71 +++ cumulus/test/runtime/src/lib.rs | 13 +- cumulus/test/service/Cargo.toml | 1 + cumulus/test/service/src/bench_utils.rs | 7 +- cumulus/test/service/src/chain_spec.rs | 121 ++--- cumulus/test/service/src/lib.rs | 4 +- cumulus/zombienet/examples/small_network.toml | 26 +- polkadot/cli/src/command.rs | 66 ++- polkadot/node/service/src/benchmarking.rs | 47 -- .../client/chain-spec/src/genesis_block.rs | 9 + .../utils/frame/benchmarking-cli/Cargo.toml | 14 + .../benchmarking-cli/src/extrinsic/bench.rs | 61 ++- .../benchmarking-cli/src/extrinsic/cmd.rs | 3 +- .../utils/frame/benchmarking-cli/src/lib.rs | 5 +- .../benchmarking-cli/src/overhead/cmd.rs | 447 +++++++++++++++++- .../src/overhead/fake_runtime_api.rs | 108 +++++ .../benchmarking-cli/src/overhead/mod.rs | 4 +- .../src/overhead/remark_builders.rs | 156 ++++++ .../benchmarking-cli/src/overhead/template.rs | 17 +- .../benchmarking-cli/src/overhead/weights.hbs | 6 +- .../benchmarking-cli/src/pallet/command.rs | 131 +---- .../frame/benchmarking-cli/src/pallet/mod.rs | 2 +- .../benchmarking-cli/src/pallet/types.rs | 19 - .../src/shared/genesis_state.rs | 138 ++++++ .../frame/benchmarking-cli/src/shared/mod.rs | 20 + .../utils/frame/omni-bencher/src/command.rs | 30 +- 34 files changed, 1246 insertions(+), 424 deletions(-) create mode 100644 cumulus/test/runtime/src/genesis_config_presets.rs create mode 100644 substrate/utils/frame/benchmarking-cli/src/overhead/fake_runtime_api.rs create mode 100644 substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs create mode 100644 substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs diff --git a/Cargo.lock b/Cargo.lock index 97bdc9351357a..aa780a7a695b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,6 +1615,22 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "bip32" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa13fae8b6255872fd86f7faf4b41168661d7d78609f7bfe6771b85c6739a15b" +dependencies = [ + "bs58", + "hmac 0.12.1", + "k256", + "rand_core 0.6.4", + "ripemd", + "sha2 0.10.8", + "subtle 2.5.0", + "zeroize", +] + [[package]] name = "bip39" version = "2.0.0" @@ -2563,6 +2579,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ + "sha2 0.10.8", "tinyvec", ] @@ -4776,6 +4793,7 @@ dependencies = [ "pallet-transaction-payment", "parity-scale-codec", "scale-info", + "serde_json", "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", @@ -4783,6 +4801,7 @@ dependencies = [ "sp-genesis-builder", "sp-inherents", "sp-io 30.0.0", + "sp-keyring", "sp-offchain", "sp-runtime 31.0.1", "sp-session", @@ -4859,6 +4878,7 @@ dependencies = [ "sp-consensus", "sp-consensus-aura", "sp-core 28.0.0", + "sp-genesis-builder", "sp-io 30.0.0", "sp-keyring", "sp-runtime 31.0.1", @@ -6204,16 +6224,21 @@ dependencies = [ "chrono", "clap 4.5.13", "comfy-table", + "cumulus-client-parachain-inherent", + "cumulus-primitives-proof-size-hostfunction", "frame-benchmarking", "frame-support", "frame-system", "gethostname", "handlebars", + "hex", "itertools 0.11.0", "lazy_static", "linked-hash-map", "log", "parity-scale-codec", + "polkadot-parachain-primitives", + "polkadot-primitives", "rand", "rand_pcg", "sc-block-builder", @@ -6227,8 +6252,10 @@ dependencies = [ "serde", "serde_json", "sp-api 26.0.0", + "sp-block-builder", "sp-blockchain", "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-database", "sp-externalities 0.25.0", "sp-genesis-builder", @@ -6238,8 +6265,13 @@ dependencies = [ "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-storage 19.0.0", + "sp-timestamp", + "sp-transaction-pool", "sp-trie 29.0.0", + "sp-version 29.0.0", "sp-wasm-interface 20.0.0", + "subxt", + "subxt-signer", "thiserror", "thousands", ] @@ -8348,6 +8380,16 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keccak-hash" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c" +dependencies = [ + "primitive-types", + "tiny-keccak", +] + [[package]] name = "keccak-hasher" version = "0.16.0" @@ -17670,6 +17712,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "rle-decode-fast" version = "1.0.3" @@ -24285,10 +24336,12 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49888ae6ae90fe01b471193528eea5bd4ed52d8eecd2d13f4a2333b87388850" dependencies = [ + "bip32", "bip39", "cfg-if", "hex", "hmac 0.12.1", + "keccak-hash", "parity-scale-codec", "pbkdf2", "regex", diff --git a/cumulus/client/parachain-inherent/src/mock.rs b/cumulus/client/parachain-inherent/src/mock.rs index a3f881e6ef9db..950cba2aaa7de 100644 --- a/cumulus/client/parachain-inherent/src/mock.rs +++ b/cumulus/client/parachain-inherent/src/mock.rs @@ -45,6 +45,7 @@ pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; /// in addition to the messages themselves, you must provide some information about /// your parachain's configuration in order to mock the MQC heads properly. /// See [`MockXcmConfig`] for more information +#[derive(Default)] pub struct MockValidationDataInherentDataProvider { /// The current block number of the local block chain (the parachain). pub current_para_block: u32, diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml b/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml index 066cbfae53ae7..733ea09ef2b80 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml @@ -93,27 +93,27 @@ wait-timeout = { workspace = true } [features] default = [] rococo-native = [ - "polkadot-cli/rococo-native", + "polkadot-cli/rococo-native", ] westend-native = [ - "polkadot-cli/westend-native", + "polkadot-cli/westend-native", ] runtime-benchmarks = [ - "cumulus-primitives-core/runtime-benchmarks", - "frame-benchmarking-cli/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "parachains-common/runtime-benchmarks", - "polkadot-cli/runtime-benchmarks", - "polkadot-primitives/runtime-benchmarks", - "sc-client-db/runtime-benchmarks", - "sc-service/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "frame-benchmarking-cli/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "polkadot-cli/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks", + "sc-client-db/runtime-benchmarks", + "sc-service/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] try-runtime = [ - "frame-support/try-runtime", - "frame-try-runtime/try-runtime", - "pallet-transaction-payment/try-runtime", - "polkadot-cli/try-runtime", - "sp-runtime/try-runtime", + "frame-support/try-runtime", + "frame-try-runtime/try-runtime", + "pallet-transaction-payment/try-runtime", + "polkadot-cli/try-runtime", + "sp-runtime/try-runtime", ] diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs index 63562f192aee4..7e6fd564b1c70 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs @@ -33,7 +33,7 @@ use crate::{ #[cfg(feature = "runtime-benchmarks")] use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; use cumulus_primitives_core::ParaId; -use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; +use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicBuilder, SUBSTRATE_REFERENCE_HARDWARE}; use log::info; use sc_cli::{Result, SubstrateCli}; use sp_runtime::traits::AccountIdConversion; @@ -47,6 +47,21 @@ pub struct RunConfig { pub chain_spec_loader: Box, /// A custom runtime resolver. pub runtime_resolver: Box, + /// Extrinsic builder to use in benchmarks. + /// + /// Some benchmarks attempt to build blocks. This extrinsic builder + /// is used to populate these blocks with extrinsics. + pub extrinsic_builder: Option>, +} + +impl RunConfig { + /// Create a new `RunConfig` + pub fn new( + runtime_resolver: Box, + chain_spec_loader: Box, + ) -> Self { + RunConfig { chain_spec_loader, runtime_resolver, extrinsic_builder: None } + } } pub fn new_aura_node_spec( @@ -199,6 +214,14 @@ pub fn run(cmd_config: RunConfig) -> Result<() }), BenchmarkCmd::Machine(cmd) => runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())), + BenchmarkCmd::Overhead(cmd) => runner.sync_run(|config| { + let node = new_node_spec( + &config, + &cmd_config.runtime_resolver, + &cli.node_extra_args(), + )?; + node.run_benchmark_overhead_cmd(cmd, cmd_config.extrinsic_builder) + }), #[allow(unreachable_patterns)] _ => Err("Benchmarking sub-command unsupported or compilation feature missing. \ Make sure to compile with --features=runtime-benchmarks \ diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs index e2826826d40ed..969ccd2800055 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs @@ -16,9 +16,9 @@ use crate::common::spec::NodeSpec; use cumulus_client_cli::ExportGenesisHeadCommand; -use frame_benchmarking_cli::BlockCmd; #[cfg(any(feature = "runtime-benchmarks"))] use frame_benchmarking_cli::StorageCmd; +use frame_benchmarking_cli::{BlockCmd, ExtrinsicBuilder, OverheadCmd}; use sc_cli::{CheckBlockCmd, ExportBlocksCmd, ExportStateCmd, ImportBlocksCmd, RevertCmd}; use sc_service::{Configuration, TaskManager}; use std::{future::Future, pin::Pin}; @@ -77,6 +77,12 @@ pub trait NodeCommandRunner { config: Configuration, cmd: &StorageCmd, ) -> SyncCmdResult; + + fn run_benchmark_overhead_cmd( + self: Box, + cmd: &OverheadCmd, + ext_builder: Option>, + ) -> SyncCmdResult; } impl NodeCommandRunner for T @@ -158,4 +164,12 @@ where cmd.run(config, partial.client, db, storage) } + + fn run_benchmark_overhead_cmd( + self: Box, + cmd: &OverheadCmd, + ext_builder: Option>, + ) -> SyncCmdResult { + cmd.run_with_extrinsic_builder::<::Block, ()>(ext_builder) + } } diff --git a/cumulus/polkadot-parachain/src/main.rs b/cumulus/polkadot-parachain/src/main.rs index f2dce552c51a1..c5c9997875fed 100644 --- a/cumulus/polkadot-parachain/src/main.rs +++ b/cumulus/polkadot-parachain/src/main.rs @@ -46,9 +46,6 @@ impl CliConfigT for CliConfig { fn main() -> color_eyre::eyre::Result<()> { color_eyre::install()?; - let config = RunConfig { - chain_spec_loader: Box::new(chain_spec::ChainSpecLoader), - runtime_resolver: Box::new(chain_spec::RuntimeResolver), - }; + let config = RunConfig::new(Box::new(chain_spec::RuntimeResolver), Box::new(chain_spec::ChainSpecLoader)); Ok(run::(config)?) } diff --git a/cumulus/test/client/src/lib.rs b/cumulus/test/client/src/lib.rs index f26413e441e72..5615bb6eba5d6 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -39,7 +39,7 @@ use sp_consensus_aura::{AuraApi, Slot}; use sp_core::Pair; use sp_io::TestExternalities; use sp_keystore::testing::MemoryKeystore; -use sp_runtime::{generic::Era, traits::Header, BuildStorage, SaturatedConversion}; +use sp_runtime::{generic::Era, traits::Header, BuildStorage, MultiAddress, SaturatedConversion}; use std::sync::Arc; pub use substrate_test_client::*; @@ -157,7 +157,7 @@ pub fn generate_extrinsic_with_pair( UncheckedExtrinsic::new_signed( function, - origin.public().into(), + MultiAddress::Id(origin.public().into()), Signature::Sr25519(signature), extra, ) @@ -180,7 +180,7 @@ pub fn transfer( value: Balance, ) -> UncheckedExtrinsic { let function = RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { - dest: dest.public().into(), + dest: MultiAddress::Id(dest.public().into()), value, }); diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index 54b83e2dfedae..f6a95bf16010f 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -11,6 +11,7 @@ workspace = true [dependencies] codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } +serde_json = { workspace = true } # Substrate frame-executive = { workspace = true } @@ -38,6 +39,7 @@ sp-session = { workspace = true } sp-consensus-aura = { workspace = true } sp-transaction-pool = { workspace = true } sp-version = { workspace = true } +sp-keyring = { workspace = true } # Cumulus cumulus-pallet-parachain-system = { workspace = true } @@ -89,6 +91,8 @@ std = [ "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", + "serde_json/std", + "sp-keyring/std" ] increment-spec-version = [] elastic-scaling = [] diff --git a/cumulus/test/runtime/src/genesis_config_presets.rs b/cumulus/test/runtime/src/genesis_config_presets.rs new file mode 100644 index 0000000000000..c9fe1d89f4c5f --- /dev/null +++ b/cumulus/test/runtime/src/genesis_config_presets.rs @@ -0,0 +1,71 @@ +use super::{ + AccountId, AuraConfig, AuraId, BalancesConfig, ParachainInfoConfig, RuntimeGenesisConfig, + SudoConfig, +}; +use alloc::{vec, vec::Vec}; + +use cumulus_primitives_core::ParaId; +use sp_genesis_builder::PresetId; +use sp_keyring::Sr25519Keyring; + +fn cumulus_test_runtime( + invulnerables: Vec, + endowed_accounts: Vec, + id: ParaId, +) -> serde_json::Value { + let config = RuntimeGenesisConfig { + system: Default::default(), + balances: BalancesConfig { + balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), + }, + sudo: SudoConfig { key: Some(Sr25519Keyring::Alice.public().into()) }, + transaction_payment: Default::default(), + test_pallet: Default::default(), + parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, + // no need to pass anything to aura, in fact it will panic if we do. Session will take care + // of this. `aura: Default::default()` + aura: AuraConfig { authorities: invulnerables }, + aura_ext: Default::default(), + parachain_system: Default::default(), + glutton: Default::default(), + }; + + serde_json::to_value(config).expect("Could not build genesis config.") +} + +pub fn testnet_genesis_with_default_endowed(self_para_id: ParaId) -> serde_json::Value { + let endowed = Sr25519Keyring::iter().map(|x| x.to_account_id()).collect::>(); + + let invulnerables = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Eve, + Sr25519Keyring::Ferdie, + ] + .into_iter() + .map(|x| x.public().into()) + .collect::>(); + cumulus_test_runtime(invulnerables, endowed, self_para_id) +} + +pub fn preset_names() -> Vec { + vec![ + PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET), + PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET), + ] +} +pub fn get_preset(id: &PresetId) -> Option> { + let patch = match id.try_into() { + Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) | + Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => + testnet_genesis_with_default_endowed(100.into()), + _ => return None, + }; + Some( + serde_json::to_string(&patch) + .expect("serialization to json is expected to work. qed.") + .into_bytes(), + ) +} diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 861d55c77cdc0..45cbed6ded6e7 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -32,6 +32,7 @@ pub mod elastic_scaling { include!(concat!(env!("OUT_DIR"), "/wasm_binary_elastic_scaling.rs")); } +mod genesis_config_presets; mod test_pallet; extern crate alloc; @@ -45,9 +46,9 @@ use sp_core::{ConstBool, ConstU32, ConstU64, OpaqueMetadata}; use cumulus_primitives_core::{ClaimQueueOffset, CoreSelector}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, IdentityLookup, Verify}, + traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, Verify}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, MultiSignature, + ApplyExtrinsicResult, MultiAddress, MultiSignature, }; #[cfg(feature = "std")] use sp_version::NativeVersion; @@ -208,8 +209,6 @@ parameter_types! { impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; - /// The lookup mechanism to get account ID from whatever is passed in dispatchers. - type Lookup = IdentityLookup; /// The index type for storing how many extrinsics an account has signed. type Nonce = Nonce; /// The type for hashing blocks and tries. @@ -361,7 +360,7 @@ pub type AccountId = <::Signer as IdentifyAccount>::Account pub type NodeBlock = generic::Block; /// The address format for describing accounts. -pub type Address = AccountId; +pub type Address = MultiAddress; /// Block header type as expected by this runtime. pub type Header = generic::Header; /// Block type as expected by this runtime. @@ -542,11 +541,11 @@ impl_runtime_apis! { } fn get_preset(id: &Option) -> Option> { - get_preset::(id, |_| None) + get_preset::(id, genesis_config_presets::get_preset) } fn preset_names() -> Vec { - vec![] + genesis_config_presets::preset_names() } } } diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index a1b70c5239525..e9cd1277d5646 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -49,6 +49,7 @@ sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } +sp-genesis-builder = { workspace = true, default-features = true } sp-runtime = { workspace = true } sp-state-machine = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } diff --git a/cumulus/test/service/src/bench_utils.rs b/cumulus/test/service/src/bench_utils.rs index 67ffbdd1d2129..ce1428dee88cf 100644 --- a/cumulus/test/service/src/bench_utils.rs +++ b/cumulus/test/service/src/bench_utils.rs @@ -41,7 +41,7 @@ use sp_core::{sr25519, Pair}; use sp_keyring::Sr25519Keyring::Alice; use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionValidityError}, - AccountId32, FixedU64, OpaqueExtrinsic, + AccountId32, FixedU64, MultiAddress, OpaqueExtrinsic, }; /// Accounts to use for transfer transactions. Enough for 5000 transactions. @@ -153,7 +153,10 @@ pub fn create_benchmarking_transfer_extrinsics( for (src, dst) in src_accounts.iter().zip(dst_accounts.iter()) { let extrinsic: UncheckedExtrinsic = construct_extrinsic( client, - BalancesCall::transfer_keep_alive { dest: AccountId::from(dst.public()), value: 10000 }, + BalancesCall::transfer_keep_alive { + dest: MultiAddress::Id(AccountId::from(dst.public())), + value: 10000, + }, src.clone(), Some(0), ); diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index ae71028ad486a..b55c8a025c4ca 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -16,25 +16,17 @@ #![allow(missing_docs)] +use cumulus_client_service::ParachainHostFunctions; use cumulus_primitives_core::ParaId; -use cumulus_test_runtime::{AccountId, Signature}; -use parachains_common::AuraId; -use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; +use cumulus_test_runtime::AccountId; +use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup, GenesisConfigBuilderRuntimeCaller}; use sc_service::ChainType; use serde::{Deserialize, Serialize}; -use sp_core::{sr25519, Pair, Public}; -use sp_runtime::traits::{IdentifyAccount, Verify}; +use serde_json::json; /// Specialized `ChainSpec` for the normal parachain runtime. pub type ChainSpec = sc_service::GenericChainSpec; -/// Helper function to generate a crypto pair from seed -pub fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - /// The extensions for the [`ChainSpec`]. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] #[serde(deny_unknown_fields)] @@ -50,16 +42,6 @@ impl Extensions { } } -type AccountPublic = ::Signer; - -/// Helper function to generate an account ID from seed. -pub fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} - /// Get the chain spec for a specific parachain ID. /// The given accounts are initialized with funds in addition /// to the default known accounts. @@ -68,17 +50,39 @@ pub fn get_chain_spec_with_extra_endowed( extra_endowed_accounts: Vec, code: &[u8], ) -> ChainSpec { + let mut patch_json = json!({ + "balances": { + "balances": extra_endowed_accounts.into_iter().map(|a| (a, 1u64 << 60)).collect::>(), + } + }); + + if let Some(id) = id { + // Merge parachain ID if given, otherwise use the one from the preset. + sc_chain_spec::json_merge( + &mut patch_json, + json!({ + "parachainInfo": { + "parachainId": id, + }, + }), + ); + }; + + let runtime_caller = GenesisConfigBuilderRuntimeCaller::::new(code); + let mut development_preset = runtime_caller + .get_named_preset(Some(&sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET.to_string())) + .expect("development preset is available on test runtime; qed"); + + sc_chain_spec::json_merge(&mut development_preset, patch_json.into()); + ChainSpec::builder( code, Extensions { para_id: id.unwrap_or(cumulus_test_runtime::PARACHAIN_ID.into()).into() }, ) .with_name("Local Testnet") - .with_id("local_testnet") + .with_id(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) .with_chain_type(ChainType::Local) - .with_genesis_config_patch(testnet_genesis_with_default_endowed( - extra_endowed_accounts.clone(), - id, - )) + .with_genesis_config(development_preset) .build() } @@ -100,66 +104,3 @@ pub fn get_elastic_scaling_chain_spec(id: Option) -> ChainSpec { .expect("WASM binary was not built, please build it!"), ) } - -/// Local testnet genesis for testing. -pub fn testnet_genesis_with_default_endowed( - mut extra_endowed_accounts: Vec, - self_para_id: Option, -) -> serde_json::Value { - let mut endowed = vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ]; - endowed.append(&mut extra_endowed_accounts); - let invulnerables = vec![ - get_collator_keys_from_seed::("Alice"), - get_collator_keys_from_seed::("Bob"), - get_collator_keys_from_seed::("Charlie"), - get_collator_keys_from_seed::("Dave"), - get_collator_keys_from_seed::("Eve"), - get_collator_keys_from_seed::("Ferdie"), - ]; - testnet_genesis( - get_account_id_from_seed::("Alice"), - invulnerables, - endowed, - self_para_id, - ) -} - -/// Generate collator keys from seed. -/// -/// This function's return type must always match the session keys of the chain in tuple format. -pub fn get_collator_keys_from_seed(seed: &str) -> ::Public { - get_from_seed::(seed) -} - -/// Creates a local testnet genesis with endowed accounts. -pub fn testnet_genesis( - root_key: AccountId, - invulnerables: Vec, - endowed_accounts: Vec, - self_para_id: Option, -) -> serde_json::Value { - let self_para_id = self_para_id.unwrap_or(cumulus_test_runtime::PARACHAIN_ID.into()); - serde_json::json!({ - "balances": cumulus_test_runtime::BalancesConfig { - balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), - }, - "sudo": cumulus_test_runtime::SudoConfig { key: Some(root_key) }, - "parachainInfo": { - "parachainId": self_para_id, - }, - "aura": cumulus_test_runtime::AuraConfig { authorities: invulnerables } - }) -} diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 9f93572e9cea5..a18e70b43b8ab 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -90,7 +90,7 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_blockchain::HeaderBackend; use sp_core::Pair; use sp_keyring::Sr25519Keyring; -use sp_runtime::{codec::Encode, generic}; +use sp_runtime::{codec::Encode, generic, MultiAddress}; use sp_state_machine::BasicExternalities; use std::sync::Arc; use substrate_test_client::{ @@ -987,7 +987,7 @@ pub fn construct_extrinsic( let signature = raw_payload.using_encoded(|e| caller.sign(e)); runtime::UncheckedExtrinsic::new_signed( function, - caller.public().into(), + MultiAddress::Id(caller.public().into()), runtime::Signature::Sr25519(signature), extra, ) diff --git a/cumulus/zombienet/examples/small_network.toml b/cumulus/zombienet/examples/small_network.toml index ab7265712308f..64765566471a0 100644 --- a/cumulus/zombienet/examples/small_network.toml +++ b/cumulus/zombienet/examples/small_network.toml @@ -3,23 +3,23 @@ default_image = "parity/polkadot:latest" default_command = "polkadot" chain = "rococo-local" - [[relaychain.nodes]] - name = "alice" - validator = true +[[relaychain.nodes]] +name = "alice" +validator = true - [[relaychain.nodes]] - name = "bob" - validator = true +[[relaychain.nodes]] +name = "bob" +validator = true [[parachains]] id = 2000 cumulus_based = true chain = "asset-hub-rococo-local" - # run charlie as parachain collator - [[parachains.collators]] - name = "charlie" - validator = true - image = "parity/polkadot-parachain:latest" - command = "polkadot-parachain" - args = ["--force-authoring"] +# run charlie as parachain collator +[[parachains.collators]] +name = "charlie" +validator = true +image = "parity/polkadot-parachain:latest" +command = "polkadot-parachain" +args = ["--force-authoring"] diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index 34ada58bbcdbe..a67791b462a69 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -15,12 +15,14 @@ // along with Polkadot. If not, see . use crate::cli::{Cli, Subcommand, NODE_VERSION}; -use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicFactory, SUBSTRATE_REFERENCE_HARDWARE}; +use frame_benchmarking_cli::{ + BenchmarkCmd, ExtrinsicFactory, SubstrateRemarkBuilder, SUBSTRATE_REFERENCE_HARDWARE, +}; use futures::future::TryFutureExt; use log::info; use polkadot_service::{ self, - benchmarking::{benchmark_inherent_data, RemarkBuilder, TransferKeepAliveBuilder}, + benchmarking::{benchmark_inherent_data, TransferKeepAliveBuilder}, HeaderBackend, IdentifyVariant, }; use sc_cli::SubstrateCli; @@ -404,44 +406,30 @@ pub fn run() -> Result<()> { cmd.run(client.clone()).map_err(Error::SubstrateCli) }), + BenchmarkCmd::Overhead(cmd) => cmd + .run_with_extrinsic_builder::(None) + .map_err(Error::SubstrateCli), // These commands are very similar and can be handled in nearly the same way. - BenchmarkCmd::Extrinsic(_) | BenchmarkCmd::Overhead(_) => - runner.sync_run(|mut config| { - let (client, _, _, _) = polkadot_service::new_chain_ops(&mut config, None)?; - let header = client.header(client.info().genesis_hash).unwrap().unwrap(); - let inherent_data = benchmark_inherent_data(header) - .map_err(|e| format!("generating inherent data: {:?}", e))?; - let remark_builder = - RemarkBuilder::new(client.clone(), config.chain_spec.identify_chain()); - - match cmd { - BenchmarkCmd::Extrinsic(cmd) => { - let tka_builder = TransferKeepAliveBuilder::new( - client.clone(), - Sr25519Keyring::Alice.to_account_id(), - config.chain_spec.identify_chain(), - ); - - let ext_factory = ExtrinsicFactory(vec![ - Box::new(remark_builder), - Box::new(tka_builder), - ]); - - cmd.run(client.clone(), inherent_data, Vec::new(), &ext_factory) - .map_err(Error::SubstrateCli) - }, - BenchmarkCmd::Overhead(cmd) => cmd - .run( - config, - client.clone(), - inherent_data, - Vec::new(), - &remark_builder, - ) - .map_err(Error::SubstrateCli), - _ => unreachable!("Ensured by the outside match; qed"), - } - }), + BenchmarkCmd::Extrinsic(cmd) => runner.sync_run(|mut config| { + let (client, _, _, _) = polkadot_service::new_chain_ops(&mut config, None)?; + let header = client.header(client.info().genesis_hash).unwrap().unwrap(); + let inherent_data = benchmark_inherent_data(header) + .map_err(|e| format!("generating inherent data: {:?}", e))?; + + let remark_builder = SubstrateRemarkBuilder::new_from_client(client.clone())?; + + let tka_builder = TransferKeepAliveBuilder::new( + client.clone(), + Sr25519Keyring::Alice.to_account_id(), + config.chain_spec.identify_chain(), + ); + + let ext_factory = + ExtrinsicFactory(vec![Box::new(remark_builder), Box::new(tka_builder)]); + + cmd.run(client.clone(), inherent_data, Vec::new(), &ext_factory) + .map_err(Error::SubstrateCli) + }), BenchmarkCmd::Pallet(cmd) => { set_default_ss58_version(chain_spec); diff --git a/polkadot/node/service/src/benchmarking.rs b/polkadot/node/service/src/benchmarking.rs index 4dcff2078419c..9b38a696e0e80 100644 --- a/polkadot/node/service/src/benchmarking.rs +++ b/polkadot/node/service/src/benchmarking.rs @@ -79,53 +79,6 @@ macro_rules! identify_chain { }; } -/// Generates `System::Remark` extrinsics for the benchmarks. -/// -/// Note: Should only be used for benchmarking. -pub struct RemarkBuilder { - client: Arc, - chain: Chain, -} - -impl RemarkBuilder { - /// Creates a new [`Self`] from the given client. - pub fn new(client: Arc, chain: Chain) -> Self { - Self { client, chain } - } -} - -impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder { - fn pallet(&self) -> &str { - "system" - } - - fn extrinsic(&self) -> &str { - "remark" - } - - fn build(&self, nonce: u32) -> std::result::Result { - // We apply the extrinsic directly, so let's take some random period. - let period = 128; - let genesis = self.client.usage_info().chain.best_hash; - let signer = Sr25519Keyring::Bob.pair(); - let current_block = 0; - - identify_chain! { - self.chain, - nonce, - current_block, - period, - genesis, - signer, - { - runtime::RuntimeCall::System( - runtime::SystemCall::remark { remark: vec![] } - ) - }, - } - } -} - /// Generates `Balances::TransferKeepAlive` extrinsics for the benchmarks. /// /// Note: Should only be used for benchmarking. diff --git a/substrate/client/chain-spec/src/genesis_block.rs b/substrate/client/chain-spec/src/genesis_block.rs index 3c7b9f64dcd6b..d41211cd6206d 100644 --- a/substrate/client/chain-spec/src/genesis_block.rs +++ b/substrate/client/chain-spec/src/genesis_block.rs @@ -108,6 +108,15 @@ impl, E: RuntimeVersionOf> GenesisBlockBuilder< ) -> sp_blockchain::Result { let genesis_storage = build_genesis_storage.build_storage().map_err(sp_blockchain::Error::Storage)?; + Self::new_with_storage(genesis_storage, commit_genesis_state, backend, executor) + } + + pub fn new_with_storage( + genesis_storage: Storage, + commit_genesis_state: bool, + backend: Arc, + executor: E, + ) -> sp_blockchain::Result { Ok(Self { genesis_storage, commit_genesis_state, diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 4e88e3360e391..08ba1728b74fc 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -52,13 +52,25 @@ sp-externalities = { workspace = true, default-features = true } sp-genesis-builder = { workspace = true, default-features = true } sp-inherents = { workspace = true, default-features = true } sp-keystore = { workspace = true, default-features = true } +sp-crypto-hashing = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-state-machine = { workspace = true, default-features = true } sp-storage = { workspace = true, default-features = true } sp-trie = { workspace = true, default-features = true } +sp-block-builder = { workspace = true, default-features = true } +sp-transaction-pool = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } sp-wasm-interface = { workspace = true, default-features = true } +subxt = { workspace = true, features = ["substrate-compat", "native"] } +subxt-signer = { workspace = true, features = ["unstable-eth"] } +cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } +cumulus-client-parachain-inherent = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } gethostname = { workspace = true } +hex = "0.4.3" [features] default = ["rocksdb"] @@ -69,5 +81,7 @@ runtime-benchmarks = [ "sc-client-db/runtime-benchmarks", "sc-service/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks" ] rocksdb = ["sc-cli/rocksdb", "sc-client-db/rocksdb"] diff --git a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index f0a7436dc729a..dcd8d1530aef1 100644 --- a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -31,14 +31,14 @@ use sp_runtime::{ Digest, DigestItem, OpaqueExtrinsic, }; +use super::ExtrinsicBuilder; +use crate::shared::{StatSelect, Stats}; use clap::Args; use log::info; use serde::Serialize; +use sp_trie::proof_size_extension::ProofSizeExt; use std::{marker::PhantomData, sync::Arc, time::Instant}; -use super::ExtrinsicBuilder; -use crate::shared::{StatSelect, Stats}; - /// Parameters to configure an *overhead* benchmark. #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] pub struct BenchmarkParams { @@ -66,6 +66,7 @@ pub(crate) struct Benchmark { params: BenchmarkParams, inherent_data: sp_inherents::InherentData, digest_items: Vec, + record_proof: bool, _p: PhantomData, } @@ -84,15 +85,19 @@ where params: BenchmarkParams, inherent_data: sp_inherents::InherentData, digest_items: Vec, + record_proof: bool, ) -> Self { - Self { client, params, inherent_data, digest_items, _p: PhantomData } + Self { client, params, inherent_data, digest_items, record_proof, _p: PhantomData } } /// Benchmark a block with only inherents. - pub fn bench_block(&self) -> Result { - let (block, _) = self.build_block(None)?; + /// + /// Returns the Ref time stats and the proof size. + pub fn bench_block(&self) -> Result<(Stats, u64)> { + let (block, _, proof_size) = self.build_block(None)?; let record = self.measure_block(&block)?; - Stats::new(&record) + + Ok((Stats::new(&record)?, proof_size)) } /// Benchmark the time of an extrinsic in a full block. @@ -100,13 +105,14 @@ where /// First benchmarks an empty block, analogous to `bench_block` and use it as baseline. /// Then benchmarks a full block built with the given `ext_builder` and subtracts the baseline /// from the result. - /// This is necessary to account for the time the inherents use. - pub fn bench_extrinsic(&self, ext_builder: &dyn ExtrinsicBuilder) -> Result { - let (block, _) = self.build_block(None)?; + /// This is necessary to account for the time the inherents use. Returns ref time stats and the + /// proof size. + pub fn bench_extrinsic(&self, ext_builder: &dyn ExtrinsicBuilder) -> Result<(Stats, u64)> { + let (block, _, base_proof_size) = self.build_block(None)?; let base = self.measure_block(&block)?; let base_time = Stats::new(&base)?.select(StatSelect::Average); - let (block, num_ext) = self.build_block(Some(ext_builder))?; + let (block, num_ext, proof_size) = self.build_block(Some(ext_builder))?; let num_ext = num_ext.ok_or_else(|| Error::Input("Block was empty".into()))?; let mut records = self.measure_block(&block)?; @@ -117,23 +123,24 @@ where *r = ((*r as f64) / (num_ext as f64)).ceil() as u64; } - Stats::new(&records) + Ok((Stats::new(&records)?, proof_size.saturating_sub(base_proof_size))) } /// Builds a block with some optional extrinsics. /// /// Returns the block and the number of extrinsics in the block - /// that are not inherents. + /// that are not inherents together with the proof size. /// Returns a block with only inherents if `ext_builder` is `None`. fn build_block( &self, ext_builder: Option<&dyn ExtrinsicBuilder>, - ) -> Result<(Block, Option)> { + ) -> Result<(Block, Option, u64)> { let chain = self.client.usage_info().chain; let mut builder = BlockBuilderBuilder::new(&*self.client) .on_parent_block(chain.best_hash) .with_parent_block_number(chain.best_number) .with_inherent_digests(Digest { logs: self.digest_items.clone() }) + .enable_proof_recording() .build()?; // Create and insert the inherents. @@ -146,7 +153,8 @@ where let ext_builder = if let Some(ext_builder) = ext_builder { ext_builder } else { - return Ok((builder.build()?.block, None)) + let proof_size = builder.estimate_block_size(true) - builder.estimate_block_size(false); + return Ok((builder.build()?.block, None, proof_size as u64)) }; // Put as many extrinsics into the block as possible and count them. @@ -167,9 +175,10 @@ where return Err("A Block must hold at least one extrinsic".into()) } info!("Extrinsics per block: {}", num_ext); + let proof_size = builder.estimate_block_size(true) - builder.estimate_block_size(false); let block = builder.build()?.block; - Ok((block, Some(num_ext))) + Ok((block, Some(num_ext), proof_size as u64)) } /// Measures the time that it take to execute a block or an extrinsic. @@ -179,8 +188,15 @@ where info!("Running {} warmups...", self.params.warmup); for _ in 0..self.params.warmup { - self.client - .runtime_api() + let mut runtime_api = self.client.runtime_api(); + if self.record_proof { + runtime_api.record_proof(); + let recorder = runtime_api + .proof_recorder() + .expect("Proof recording is enabled in the line above; qed."); + runtime_api.register_extension(ProofSizeExt::new(recorder)); + } + runtime_api .execute_block(genesis, block.clone()) .map_err(|e| Error::Client(RuntimeApiError(e)))?; } @@ -190,7 +206,14 @@ where // Execute a block multiple times and record each execution time. for _ in 0..self.params.repeat { let block = block.clone(); - let runtime_api = self.client.runtime_api(); + let mut runtime_api = self.client.runtime_api(); + if self.record_proof { + runtime_api.record_proof(); + let recorder = runtime_api + .proof_recorder() + .expect("Proof recording is enabled in the line above; qed."); + runtime_api.register_extension(ProofSizeExt::new(recorder)); + } let start = Instant::now(); runtime_api diff --git a/substrate/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs index 99c0230617cb3..949b8211556a4 100644 --- a/substrate/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs @@ -118,7 +118,8 @@ impl ExtrinsicCmd { return Err("Unknown pallet or extrinsic. Use --list for a complete list.".into()), }; - let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data, digest_items); + let bench = + Benchmark::new(client, self.params.bench.clone(), inherent_data, digest_items, false); let stats = bench.bench_extrinsic(ext_builder)?; info!( "Executing a {}::{} extrinsic takes[ns]:\n{:?}", diff --git a/substrate/utils/frame/benchmarking-cli/src/lib.rs b/substrate/utils/frame/benchmarking-cli/src/lib.rs index 0ef2c299de63e..36b856927f347 100644 --- a/substrate/utils/frame/benchmarking-cli/src/lib.rs +++ b/substrate/utils/frame/benchmarking-cli/src/lib.rs @@ -28,7 +28,10 @@ mod storage; pub use block::BlockCmd; pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; pub use machine::{MachineCmd, SUBSTRATE_REFERENCE_HARDWARE}; -pub use overhead::OverheadCmd; +pub use overhead::{ + remark_builders::{DynamicRemarkBuilder, SubstrateRemarkBuilder}, + OpaqueBlock, OverheadCmd, +}; pub use pallet::PalletCmd; pub use sc_service::BasePath; pub use storage::StorageCmd; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 4fa8cecf2f7dd..f20b14727ca18 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -18,26 +18,50 @@ //! Contains the [`OverheadCmd`] as entry point for the CLI to execute //! the *overhead* benchmarks. -use sc_block_builder::BlockBuilderApi; -use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; -use sc_client_api::UsageProvider; -use sc_service::Configuration; -use sp_api::{ApiExt, CallApiAt, ProvideRuntimeApi}; -use sp_runtime::{traits::Block as BlockT, DigestItem, OpaqueExtrinsic}; - -use clap::{Args, Parser}; -use log::info; -use serde::Serialize; -use std::{fmt::Debug, path::PathBuf, sync::Arc}; - +use super::remark_builders::*; use crate::{ extrinsic::{ bench::{Benchmark, BenchmarkParams as ExtrinsicBenchmarkParams}, ExtrinsicBuilder, }, - overhead::template::TemplateData, - shared::{HostInfoParams, WeightParams}, + overhead::{ + cmd::ChainType::{Parachain, Relaychain, Unknown}, + fake_runtime_api, + template::TemplateData, + }, + shared::{self, GenesisBuilderPolicy, HostInfoParams, WeightParams}, }; +use clap::{Args, Parser}; +use codec::{Decode, Encode}; +use cumulus_client_parachain_inherent::MockValidationDataInherentDataProvider; +use fake_runtime_api::RuntimeApi as FakeRuntimeApi; +use frame_support::Deserialize; +use log::info; +use polkadot_parachain_primitives::primitives::Id as ParaId; +use sc_block_builder::BlockBuilderApi; +use sc_chain_spec::{ChainSpec, ChainSpecExtension, GenericChainSpec, GenesisBlockBuilder}; +use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; +use sc_client_api::{execution_extensions::ExecutionExtensions, UsageProvider}; +use sc_client_db::{BlocksPruning, DatabaseSettings, DatabaseSource}; +use sc_executor::WasmExecutor; +use sc_service::{new_client, new_db_backend, BasePath, ClientConfig, TFullClient, TaskManager}; +use serde::Serialize; +use serde_json::{json, Value}; +use sp_api::{ApiExt, CallApiAt, Core, ProvideRuntimeApi}; +use sp_blockchain::HeaderBackend; +use sp_core::crypto::AccountId32; +use sp_inherents::{InherentData, InherentDataProvider}; +use sp_runtime::{ + generic, + traits::{BlakeTwo256, Block as BlockT}, + DigestItem, OpaqueExtrinsic, +}; +use sp_wasm_interface::HostFunctions; +use std::{fmt::Debug, path::PathBuf, sync::Arc}; +use subxt::{ext::futures, utils::H256, Metadata}; +use subxt_signer::{eth::Keypair as EthKeypair, DeriveJunction}; + +const DEFAULT_PARA_ID: u32 = 100; /// Benchmark the execution overhead per-block and per-extrinsic. #[derive(Debug, Parser)] @@ -81,6 +105,48 @@ pub struct OverheadParams { /// This should only be used for performance analysis and not for final results. #[arg(long)] pub enable_trie_cache: bool, + + /// Optional runtime blob to use instead of the one from the genesis config. + #[arg(long, value_name = "PATH")] + pub runtime: Option, + + /// The preset that we expect to find in the GenesisBuilder runtime API. + /// + /// This can be useful when a runtime has a dedicated benchmarking preset instead of using the + /// default one. + #[arg(long, default_value = sp_genesis_builder::DEV_RUNTIME_PRESET)] + pub genesis_builder_preset: String, + + /// How to construct the genesis state. + /// + /// Uses `GenesisBuilderPolicy::Spec` by default and `GenesisBuilderPolicy::Runtime` if + /// `runtime` is set. + #[arg(long, value_enum)] + pub genesis_builder: Option, + + /// Account type to generate. + #[arg(long)] + pub account_type: Option, + + /// Inflate the genesis state by generating accounts. + /// + /// Can be used together with `--account_type` to specify the type of accounts to generate. + #[arg(long)] + pub generate_num_accounts: Option, + + /// Parachain Id to use for parachains. If not specified, the benchmark code will choose + /// a para-id and patch the state accordingly. + #[arg(long)] + pub para_id: Option, +} + +/// Enum representing the type of account to generate. +#[derive(Debug, Clone, PartialEq, clap::ValueEnum, Serialize)] +pub enum AccountType { + /// Sr25519 account type. + Sr25519, + /// ECDSA account type. + ECDSA, } /// Type of a benchmark. @@ -92,18 +158,319 @@ pub(crate) enum BenchmarkType { Block, } +/// Hostfunctions that are typically used by parachains. +pub type ParachainHostFunctions = ( + cumulus_primitives_proof_size_hostfunction::storage_proof_size::HostFunctions, + sp_io::SubstrateHostFunctions, +); + +pub type BlockNumber = u32; + +/// Typical block type using `OpaqueExtrinsic`. +pub type Header = generic::Header; + +/// Typical block type using `OpaqueExtrinsic`. +pub type OpaqueBlock = generic::Block; + +/// Client type used throughout the benchmarking code. +type OverheadClient = TFullClient>; + +/// Creates inherent data for a given parachain ID. +/// +/// This function constructs the inherent data required for block execution, +/// including the relay chain state and validation data. Not all of these +/// inherents are required for every chain. The runtime will pick the ones +/// it requires based on their identifier. +fn create_inherent_data + HeaderBackend, Block: BlockT>( + client: &Arc, + chain_type: &ChainType, +) -> InherentData { + let genesis = client.usage_info().chain.best_hash; + let header = client.header(genesis).unwrap().unwrap(); + + let mut inherent_data = sp_inherents::InherentData::new(); + + // Para inherent can only makes sense when we are handling a parachain. + if let Parachain(para_id) = chain_type { + let parachain_validation_data_provider = MockValidationDataInherentDataProvider::<()> { + para_id: ParaId::from(*para_id), + current_para_block_head: Some(header.encode().into()), + relay_offset: 1, + ..Default::default() + }; + let _ = futures::executor::block_on( + parachain_validation_data_provider.provide_inherent_data(&mut inherent_data), + ); + } + + // Parachain inherent that is used on relay chains to perform parachain validation. + let para_inherent = polkadot_primitives::InherentData { + bitfields: Vec::new(), + backed_candidates: Vec::new(), + disputes: Vec::new(), + parent_header: header, + }; + + // Timestamp inherent that is very common in substrate chains. + let timestamp = sp_timestamp::InherentDataProvider::new(std::time::Duration::default().into()); + + let _ = futures::executor::block_on(timestamp.provide_inherent_data(&mut inherent_data)); + let _ = + inherent_data.put_data(polkadot_primitives::PARACHAINS_INHERENT_IDENTIFIER, ¶_inherent); + + inherent_data +} + +#[derive(Deserialize, Serialize, Clone, ChainSpecExtension)] +pub struct ParachainExtension { + /// The id of the Parachain. + pub para_id: Option, +} + +fn generate_balances_sr25519(num_accounts: u64) -> Vec { + let alice_pair = subxt_signer::sr25519::dev::alice(); + (0..num_accounts) + .into_iter() + .map(|path| { + let derived = alice_pair.derive([DeriveJunction::hard(path.to_string())]); + json!((AccountId32::from(derived.public_key().0), 1u64 << 60,)) + }) + .collect() +} + +fn generate_balances_ecdsa(num_accounts: u64) -> Vec { + let alice_pair = subxt_signer::ecdsa::dev::alice(); + (0..num_accounts) + .into_iter() + .map(|path| { + let derived = alice_pair.derive([DeriveJunction::hard(path.to_string())]).unwrap(); + json!(( + "0x".to_string() + &hex::encode(EthKeypair::from(derived).account_id()), + 1u64 << 60, + )) + }) + .collect() +} + +/// Patch the genesis state. +/// +/// We perform two actions: +/// 1. Inflate the genesis state by generating accounts. +/// 2. Patch the parachain id into the genesis config. This is necessary since the inherents +/// also contain a parachain id and they need to match. +fn patch_genesis( + mut input_value: Value, + num_accounts: Option, + chain_type: ChainType, + generate_accounts: Option, +) -> Value { + // If we identified a parachain we should patch a parachain id into the genesis config. + // This ensures compatibility with the inherents that we provide to successfully build a + // block. + if let Parachain(para_id) = chain_type { + sc_chain_spec::json_patch::merge( + &mut input_value, + json!({ + "parachainInfo": { + "parachainId": para_id, + } + }), + ); + log::debug!("Genesis Config Json"); + log::debug!("{}", input_value); + } + + if let Some(num_accounts) = num_accounts { + // Attempt to patch balances + if let Some(balances) = input_value + .get_mut("balances") + .and_then(|info| info.get_mut("balances")) + .and_then(|balance| balance.as_array_mut()) + { + let generated = match &generate_accounts { + None => Default::default(), + Some(AccountType::Sr25519) => generate_balances_sr25519(num_accounts), + Some(AccountType::ECDSA) => generate_balances_ecdsa(num_accounts), + }; + balances.extend(generated); + } else { + log::warn!("No balances found."); + } + } + input_value +} + impl OverheadCmd { + /// Make an educated guess what kind of chain we are dealing with. + fn identify_chain(&self, metadata: &Metadata, para_id: Option) -> Result { + let parachain_info_exists = metadata.pallet_by_name("ParachainInfo").is_some(); + let parachain_system_exists = metadata.pallet_by_name("ParachainSystem").is_some(); + let para_inherent_exists = metadata.pallet_by_name("ParaInherent").is_some(); + + log::info!("Identifying chain type based on metadata."); + log::info!("{} ParachainSystem", if parachain_system_exists { "✅" } else { "❌" }); + log::info!("{} ParachainInfo", if parachain_info_exists { "✅" } else { "❌" }); + log::info!("{} ParaInherent", if para_inherent_exists { "✅" } else { "❌" }); + + if parachain_system_exists && parachain_info_exists { + log::info!("Parachain Identified"); + Ok(Parachain(para_id.or(self.params.para_id).unwrap_or(DEFAULT_PARA_ID))) + } else if para_inherent_exists { + log::info!("Relaychain Identified"); + Ok(Relaychain) + } else { + log::info!("Found Custom chain"); + Ok(Unknown) + } + } + fn chain_spec_from_path( + &self, + ) -> Result<(Option>, Option)> { + let chain_spec = self + .shared_params + .chain + .clone() + .map(|path| { + GenericChainSpec::::from_json_file(path.into()) + .map_err(|e| format!("Unable to load chain spec: {:?}", e)) + }) + .transpose()?; + + let para_id_from_chain_spec = + chain_spec.as_ref().and_then(|spec| spec.extensions().para_id); + Ok((chain_spec.map(|c| Box::new(c) as Box<_>), para_id_from_chain_spec)) + } + + /// Run the benchmark overhead command. + pub fn run_with_extrinsic_builder( + &self, + ext_builder: Option>, + ) -> Result<()> + where + Block: BlockT, + ExtraHF: HostFunctions, + { + let (chain_spec, para_id_from_chain_spec) = + self.chain_spec_from_path::<(ParachainHostFunctions, ExtraHF)>()?; + let code_bytes = shared::genesis_state::get_code_bytes(&chain_spec, &self.params.runtime)?; + + let executor = WasmExecutor::<(ParachainHostFunctions, ExtraHF)>::builder() + .with_allow_missing_host_functions(true) + .build(); + + let opaque_metadata = fetch_latest_metadata_from_blob(&executor, &code_bytes)?; + let metadata = Metadata::decode(&mut (*opaque_metadata).as_slice())?; + let chain_type = self.identify_chain(&metadata, para_id_from_chain_spec)?; + + let client = self.build_client_components::( + chain_spec, + &code_bytes, + executor, + &chain_type, + )?; + + let inherent_data = create_inherent_data(&client, &chain_type); + + let ext_builder = ext_builder.unwrap_or_else(|| { + let genesis = client.usage_info().chain.best_hash; + let version = client.runtime_api().version(genesis).unwrap(); + let runtime_version = subxt::client::RuntimeVersion { + spec_version: version.spec_version, + transaction_version: version.transaction_version, + }; + Box::new(SubstrateRemarkBuilder::new(metadata, genesis, runtime_version)) + }); + + self.run( + "Overhead Benchmark".to_string(), + client, + inherent_data, + Default::default(), + &*ext_builder, + chain_type.requires_proof_recording(), + ) + } + + fn build_client_components( + &self, + chain_spec: Option>, + code_bytes: &Vec, + executor: WasmExecutor, + chain_type: &ChainType, + ) -> Result>> { + let extensions = ExecutionExtensions::new(None, Arc::new(executor.clone())); + + let backend = new_db_backend(DatabaseSettings { + trie_cache_maximum_size: self.trie_cache_maximum_size()?, + state_pruning: None, + blocks_pruning: BlocksPruning::KeepAll, + source: DatabaseSource::RocksDb { + cache_size: self.database_cache_size()?.unwrap_or(1024), + path: BasePath::new_temp_dir()?.path().into(), + }, + })?; + + //let storage = self.storage(&code_bytes, chain_spec, &chain_type)?; + let chain_type_for_closure = chain_type.clone(); + let num_accounts = self.params.generate_num_accounts; + let account_type = self.params.account_type.clone(); + let storage = shared::genesis_state::genesis_storage::( + self.params.genesis_builder, + &self.params.runtime, + Some(&code_bytes), + &self.params.genesis_builder_preset, + &chain_spec, + Some(Box::new(move |val| { + patch_genesis(val, num_accounts, chain_type_for_closure, account_type) + })), + )?; + + let genesis_block_builder = GenesisBlockBuilder::new_with_storage( + storage, + true, + backend.clone(), + executor.clone(), + )?; + + let tokio_runtime = sc_cli::build_runtime()?; + let task_manager = TaskManager::new(tokio_runtime.handle().clone(), None) + .map_err(|_| "Unable to build task manager")?; + + let client: Arc> = Arc::new(new_client( + backend.clone(), + executor, + genesis_block_builder, + Default::default(), + Default::default(), + extensions, + Box::new(task_manager.spawn_handle()), + None, + None, + ClientConfig { + offchain_worker_enabled: false, + offchain_indexing_api: false, + wasm_runtime_overrides: None, + no_genesis: false, + wasm_runtime_substitutes: Default::default(), + enable_import_proof_recording: chain_type.requires_proof_recording(), + }, + )?); + + Ok(client) + } + /// Measure the per-block and per-extrinsic execution overhead. /// /// Writes the results to console and into two instances of the /// `weights.hbs` template, one for each benchmark. pub fn run( &self, - cfg: Configuration, + chain_name: String, client: Arc, inherent_data: sp_inherents::InherentData, digest_items: Vec, ext_builder: &dyn ExtrinsicBuilder, + should_record_proof: bool, ) -> Result<()> where Block: BlockT, @@ -116,20 +483,39 @@ impl OverheadCmd { if ext_builder.pallet() != "system" || ext_builder.extrinsic() != "remark" { return Err(format!("The extrinsic builder is required to build `System::Remark` extrinsics but builds `{}` extrinsics instead", ext_builder.name()).into()); } - let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data, digest_items); + + let bench = Benchmark::new( + client, + self.params.bench.clone(), + inherent_data, + digest_items, + should_record_proof, + ); // per-block execution overhead { - let stats = bench.bench_block()?; + let (stats, proof_size) = bench.bench_block()?; info!("Per-block execution overhead [ns]:\n{:?}", stats); - let template = TemplateData::new(BenchmarkType::Block, &cfg, &self.params, &stats)?; + let template = TemplateData::new( + BenchmarkType::Block, + &chain_name, + &self.params, + &stats, + proof_size, + )?; template.write(&self.params.weight.weight_path)?; } // per-extrinsic execution overhead { - let stats = bench.bench_extrinsic(ext_builder)?; + let (stats, proof_size) = bench.bench_extrinsic(ext_builder)?; info!("Per-extrinsic execution overhead [ns]:\n{:?}", stats); - let template = TemplateData::new(BenchmarkType::Extrinsic, &cfg, &self.params, &stats)?; + let template = TemplateData::new( + BenchmarkType::Extrinsic, + &chain_name, + &self.params, + &stats, + proof_size, + )?; template.write(&self.params.weight.weight_path)?; } @@ -155,6 +541,23 @@ impl BenchmarkType { } } +#[derive(Clone)] +enum ChainType { + Parachain(u32), + Relaychain, + Unknown, +} + +impl ChainType { + fn requires_proof_recording(&self) -> bool { + match self { + Parachain(_) => true, + Relaychain => false, + Unknown => false, + } + } +} + // Boilerplate impl CliConfiguration for OverheadCmd { fn shared_params(&self) -> &SharedParams { @@ -172,4 +575,8 @@ impl CliConfiguration for OverheadCmd { Ok(None) } } + + fn base_path(&self) -> Result> { + Ok(Some(BasePath::new_temp_dir()?)) + } } diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/fake_runtime_api.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/fake_runtime_api.rs new file mode 100644 index 0000000000000..10187383d9722 --- /dev/null +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/fake_runtime_api.rs @@ -0,0 +1,108 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! A fake runtime struct that allows us to instantiate a client. +//! Has all the required runtime APIs implemented to satisfy trait bounds, +//! but the methods are never called since we use WASM exclusively. + +use sp_core::OpaqueMetadata; +use sp_runtime::{ + generic, + traits::{BlakeTwo256, Block as BlockT}, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, OpaqueExtrinsic, +}; + +/// Block number +type BlockNumber = u32; +/// Opaque block header type. +type Header = generic::Header; +/// Opaque block type. +type Block = generic::Block; + +#[allow(unused)] +pub struct Runtime; + +sp_api::impl_runtime_apis! { + impl sp_api::Core for Runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + + fn execute_block(_: Block) { + unimplemented!() + } + + fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { + unimplemented!() + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + unimplemented!() + } + + fn metadata_at_version(_: u32) -> Option { + unimplemented!() + } + + fn metadata_versions() -> Vec { + unimplemented!() + } + } + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(_: ::Extrinsic) -> ApplyExtrinsicResult { + unimplemented!() + } + + fn finalize_block() -> ::Header { + unimplemented!() + } + + fn inherent_extrinsics(_: sp_inherents::InherentData) -> Vec<::Extrinsic> { + unimplemented!() + } + + fn check_inherents(_: Block, _: sp_inherents::InherentData) -> sp_inherents::CheckInherentsResult { + unimplemented!() + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + _: TransactionSource, + _: ::Extrinsic, + _: ::Hash, + ) -> TransactionValidity { + unimplemented!() + } + } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn build_state(_: Vec) -> sp_genesis_builder::Result { + unimplemented!() + } + + fn get_preset(_id: &Option) -> Option> { + unimplemented!() + } + + fn preset_names() -> Vec { + unimplemented!() + } + } +} diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs index 00cde66fd7221..1d8a78dc5bfbb 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs @@ -18,4 +18,6 @@ pub mod cmd; pub mod template; -pub use cmd::OverheadCmd; +pub use cmd::{OpaqueBlock, OverheadCmd}; +mod fake_runtime_api; +pub mod remark_builders; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs new file mode 100644 index 0000000000000..0664e5b9470f2 --- /dev/null +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs @@ -0,0 +1,156 @@ +use crate::extrinsic::ExtrinsicBuilder; +use codec::{Decode, Encode}; +use sc_client_api::UsageProvider; +use sc_executor::WasmExecutor; +use sp_api::{Core, Metadata, ProvideRuntimeApi}; +use sp_core::{ + traits::{CallContext, CodeExecutor, FetchRuntimeCode, RuntimeCode}, + OpaqueMetadata, +}; +use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; +use sp_state_machine::BasicExternalities; +use sp_wasm_interface::HostFunctions; +use std::{borrow::Cow, sync::Arc}; +use subxt::{ + client::RuntimeVersion, config::substrate::SubstrateExtrinsicParamsBuilder, Config, + OfflineClient, SubstrateConfig, +}; + +pub type SubstrateRemarkBuilder = DynamicRemarkBuilder; + +pub struct DynamicRemarkBuilder { + offline_client: OfflineClient, +} + +impl DynamicRemarkBuilder { + pub fn new_from_client(client: Arc) -> sc_cli::Result + where + Block: BlockT, + Client: UsageProvider + ProvideRuntimeApi, + Client::Api: Metadata + Core, + { + let genesis = client.usage_info().chain.best_hash; + let api = client.runtime_api(); + let mut supported_metadata_versions = api.metadata_versions(genesis).unwrap(); + let latest = supported_metadata_versions + .pop() + .ok_or("No runtime version supported".to_string())?; + let version = api.version(genesis).unwrap(); + let runtime_version = RuntimeVersion { + spec_version: version.spec_version, + transaction_version: version.transaction_version, + }; + let metadata = api + .metadata_at_version(genesis, latest) + .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? + .ok_or("Unable to decode metadata".to_string())?; + let metadata = subxt::Metadata::decode(&mut (*metadata).as_slice())?; + + Ok(Self { offline_client: OfflineClient::new(genesis, runtime_version, metadata) }) + } +} + +impl DynamicRemarkBuilder { + pub fn new( + metadata: subxt::Metadata, + genesis_hash: C::Hash, + runtime_version: RuntimeVersion, + ) -> Self { + Self { offline_client: OfflineClient::new(genesis_hash, runtime_version, metadata) } + } +} + +impl ExtrinsicBuilder for DynamicRemarkBuilder { + fn pallet(&self) -> &str { + "system" + } + + fn extrinsic(&self) -> &str { + "remark" + } + + fn build(&self, nonce: u32) -> std::result::Result { + let signer = subxt_signer::sr25519::dev::alice(); + let dynamic_tx = subxt::dynamic::tx("System", "remark", vec![Vec::::new()]); + + let params = SubstrateExtrinsicParamsBuilder::new().nonce(nonce.into()).build(); + + // Default transaction parameters assume a nonce of 0. + let transaction = self + .offline_client + .tx() + .create_signed_offline(&dynamic_tx, &signer, params) + .unwrap(); + let mut encoded = transaction.into_encoded(); + + OpaqueExtrinsic::from_bytes(&mut encoded).map_err(|_| "Unable to construct OpaqueExtrinsic") + } +} + +struct BasicCodeFetcher<'a>(Cow<'a, [u8]>); +impl<'a> FetchRuntimeCode for BasicCodeFetcher<'a> { + fn fetch_runtime_code(&self) -> Option> { + Some(self.0.clone()) + } +} +impl<'a> BasicCodeFetcher<'a> { + pub fn runtime_code(&'a self) -> RuntimeCode<'a> { + RuntimeCode { + code_fetcher: self as &'a dyn FetchRuntimeCode, + heap_pages: None, + hash: sp_crypto_hashing::blake2_256(&self.0).to_vec(), + } + } +} + +pub fn fetch_latest_metadata_from_blob( + executor: &WasmExecutor, + code_bytes: &Vec, +) -> sc_cli::Result { + let mut ext = BasicExternalities::default(); + let fetcher = BasicCodeFetcher(code_bytes.into()); + let version_result = executor + .call( + &mut ext, + &fetcher.runtime_code(), + "Metadata_metadata_versions", + &[], + CallContext::Offchain, + ) + .0; + + let opaque_metadata: Option = match version_result { + Ok(supported_versions) => { + let versions = Vec::::decode(&mut supported_versions.as_slice()) + .map_err(|e| format!("Error {e}"))?; + let version_to_use = versions.last().ok_or("No versions available.")?; + let parameters = (*version_to_use).encode(); + let encoded = executor + .call( + &mut ext, + &fetcher.runtime_code(), + "Metadata_metadata_at_version", + ¶meters, + CallContext::Offchain, + ) + .0 + .map_err(|e| format!("Unable to fetch metadata from blob: {e}"))?; + Decode::decode(&mut encoded.as_slice())? + }, + Err(_) => { + let encoded = executor + .call( + &mut ext, + &fetcher.runtime_code(), + "Metadata_metadata", + &[], + CallContext::Offchain, + ) + .0 + .map_err(|e| format!("Unable to fetch metadata from blob: {e}"))?; + Decode::decode(&mut encoded.as_slice())? + }, + }; + + opaque_metadata.ok_or_else(|| "Metadata not found".into()) +} diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/template.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/template.rs index 7c8c92b07d747..a515295968421 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/template.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/template.rs @@ -19,7 +19,6 @@ //! it into the `weights.hbs` template. use sc_cli::Result; -use sc_service::Configuration; use handlebars::Handlebars; use log::info; @@ -59,19 +58,22 @@ pub(crate) struct TemplateData { params: OverheadParams, /// Stats about the benchmark result. stats: Stats, - /// The resulting weight in ns. - weight: u64, + /// The resulting ref time weight. + ref_time: u64, + /// The size of the proof weight. + proof_size: u64, } impl TemplateData { /// Returns a new [`Self`] from the given params. pub(crate) fn new( t: BenchmarkType, - cfg: &Configuration, + chain_name: &String, params: &OverheadParams, stats: &Stats, + proof_size: u64, ) -> Result { - let weight = params.weight.calc_weight(stats)?; + let ref_time = params.weight.calc_weight(stats)?; let header = params .header .as_ref() @@ -82,7 +84,7 @@ impl TemplateData { Ok(TemplateData { short_name: t.short_name().into(), long_name: t.long_name().into(), - runtime_name: cfg.chain_spec.name().into(), + runtime_name: chain_name.to_owned(), version: VERSION.into(), date: chrono::Utc::now().format("%Y-%m-%d (Y/M/D)").to_string(), hostname: params.hostinfo.hostname(), @@ -91,7 +93,8 @@ impl TemplateData { args: env::args().collect::>(), params: params.clone(), stats: stats.clone(), - weight, + ref_time, + proof_size, }) } diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/substrate/utils/frame/benchmarking-cli/src/overhead/weights.hbs index 6e364facc12f4..8c48baaf79c0f 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -18,9 +18,9 @@ use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; parameter_types! { {{#if (eq short_name "block")}} - /// Time to execute an empty block. + /// Weight fo executing an empty block. {{else}} - /// Time to execute a NO-OP extrinsic, for example `System::remark`. + /// Weight of executing a NO-OP extrinsic, for example `System::remark`. {{/if}} /// Calculated by multiplying the *{{params.weight.weight_metric}}* with `{{params.weight.weight_mul}}` and adding `{{params.weight.weight_add}}`. /// @@ -35,7 +35,7 @@ parameter_types! { /// 95th: {{underscore stats.p95}} /// 75th: {{underscore stats.p75}} pub const {{long_name}}Weight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul({{underscore weight}}), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul({{underscore ref_time}}), {{underscore proof_size}}); } #[cfg(test)] diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index f1499f41c2ea8..fd07e12b64fa5 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -19,7 +19,10 @@ use super::{ types::{ComponentRange, ComponentRangeMap}, writer, ListOutput, PalletCmd, }; -use crate::pallet::{types::FetchedCode, GenesisBuilderPolicy}; +use crate::{ + pallet::types::FetchedCode, + shared::genesis_state::{genesis_storage, get_code_bytes}, +}; use codec::{Decode, Encode}; use frame_benchmarking::{ Analysis, BenchmarkBatch, BenchmarkBatchSplitResults, BenchmarkList, BenchmarkParameter, @@ -27,7 +30,6 @@ use frame_benchmarking::{ }; use frame_support::traits::StorageInfo; use linked_hash_map::LinkedHashMap; -use sc_chain_spec::GenesisConfigBuilderRuntimeCaller; use sc_cli::{execution_method_from_cli, ChainSpec, CliConfiguration, Result, SharedParams}; use sc_client_db::BenchmarkingState; use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; @@ -43,7 +45,6 @@ use sp_externalities::Extensions; use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::traits::Hash; use sp_state_machine::StateMachine; -use sp_storage::{well_known_keys::CODE, Storage}; use sp_trie::{proof_size_extension::ProofSizeExt, recorder::Recorder}; use sp_wasm_interface::HostFunctions; use std::{ @@ -57,6 +58,11 @@ use std::{ /// Logging target const LOG_TARGET: &'static str = "polkadot_sdk_frame::benchmark::pallet"; +type SubstrateAndExtraHF = ( + sp_io::SubstrateHostFunctions, + frame_benchmarking::benchmarking::HostFunctions, + T, +); /// How the PoV size of a storage item should be estimated. #[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy)] pub enum PovEstimationMode { @@ -149,18 +155,6 @@ This could mean that you either did not build the node correctly with the \ `--features runtime-benchmarks` flag, or the chain spec that you are using was \ not created by a node that was compiled with the flag"; -/// When the runtime could not build the genesis storage. -const ERROR_CANNOT_BUILD_GENESIS: &str = "The runtime returned \ -an error when trying to build the genesis storage. Please ensure that all pallets \ -define a genesis config that can be built. This can be tested with: \ -https://github.com/paritytech/polkadot-sdk/pull/3412"; - -/// Warn when using the chain spec to generate the genesis state. -const WARN_SPEC_GENESIS_CTOR: &'static str = "Using the chain spec instead of the runtime to \ -generate the genesis state is deprecated. Please remove the `--chain`/`--dev`/`--local` argument, \ -point `--runtime` to your runtime blob and set `--genesis-builder=runtime`. This warning may \ -become a hard error any time after December 2024."; - impl PalletCmd { /// Runs the command and benchmarks a pallet. #[deprecated( @@ -210,7 +204,15 @@ impl PalletCmd { return self.output_from_results(&batches) } - let genesis_storage = self.genesis_storage::(&chain_spec)?; + let code_bytes = get_code_bytes(&chain_spec, &self.runtime)?; + let genesis_storage = genesis_storage::>( + self.genesis_builder, + &self.runtime, + Some(&code_bytes), + &self.genesis_builder_preset, + &chain_spec, + None + )?; let cache_size = Some(self.database_cache_size as usize); let state_with_tracking = BenchmarkingState::::new( @@ -239,11 +241,7 @@ impl PalletCmd { let runtime_code = runtime.code()?; let alloc_strategy = self.alloc_strategy(runtime_code.heap_pages); - let executor = WasmExecutor::<( - sp_io::SubstrateHostFunctions, - frame_benchmarking::benchmarking::HostFunctions, - ExtraHostFunctions, - )>::builder() + let executor = WasmExecutor::>::builder() .with_execution_method(method) .with_allow_missing_host_functions(self.allow_missing_host_functions) .with_onchain_heap_alloc_strategy(alloc_strategy) @@ -558,97 +556,6 @@ impl PalletCmd { Ok(benchmarks_to_run) } - /// Build the genesis storage by either the Genesis Builder API, chain spec or nothing. - /// - /// Behaviour can be controlled by the `--genesis-builder` flag. - fn genesis_storage( - &self, - chain_spec: &Option>, - ) -> Result { - Ok(match (self.genesis_builder, self.runtime.as_ref()) { - (Some(GenesisBuilderPolicy::None), Some(_)) => return Err("Cannot use `--genesis-builder=none` with `--runtime` since the runtime would be ignored.".into()), - (Some(GenesisBuilderPolicy::None), None) => Storage::default(), - (Some(GenesisBuilderPolicy::SpecGenesis | GenesisBuilderPolicy::Spec), Some(_)) => - return Err("Cannot use `--genesis-builder=spec-genesis` with `--runtime` since the runtime would be ignored.".into()), - (Some(GenesisBuilderPolicy::SpecGenesis | GenesisBuilderPolicy::Spec), None) | (None, None) => { - log::warn!("{WARN_SPEC_GENESIS_CTOR}"); - let Some(chain_spec) = chain_spec else { - return Err("No chain spec specified to generate the genesis state".into()); - }; - - let storage = chain_spec - .build_storage() - .map_err(|e| format!("{ERROR_CANNOT_BUILD_GENESIS}\nError: {e}"))?; - - storage - }, - (Some(GenesisBuilderPolicy::SpecRuntime), Some(_)) => - return Err("Cannot use `--genesis-builder=spec` with `--runtime` since the runtime would be ignored.".into()), - (Some(GenesisBuilderPolicy::SpecRuntime), None) => { - let Some(chain_spec) = chain_spec else { - return Err("No chain spec specified to generate the genesis state".into()); - }; - - self.genesis_from_spec_runtime::(chain_spec.as_ref())? - }, - (Some(GenesisBuilderPolicy::Runtime), None) => return Err("Cannot use `--genesis-builder=runtime` without `--runtime`".into()), - (Some(GenesisBuilderPolicy::Runtime), Some(runtime)) | (None, Some(runtime)) => { - log::info!("Loading WASM from {}", runtime.display()); - - let code = fs::read(&runtime).map_err(|e| { - format!( - "Could not load runtime file from path: {}, error: {}", - runtime.display(), - e - ) - })?; - - self.genesis_from_code::(&code)? - } - }) - } - - /// Setup the genesis state by calling the runtime APIs of the chain-specs genesis runtime. - fn genesis_from_spec_runtime( - &self, - chain_spec: &dyn ChainSpec, - ) -> Result { - log::info!("Building genesis state from chain spec runtime"); - let storage = chain_spec - .build_storage() - .map_err(|e| format!("{ERROR_CANNOT_BUILD_GENESIS}\nError: {e}"))?; - - let code: &Vec = - storage.top.get(CODE).ok_or("No runtime code in the genesis storage")?; - - self.genesis_from_code::(code) - } - - fn genesis_from_code(&self, code: &[u8]) -> Result { - let genesis_config_caller = GenesisConfigBuilderRuntimeCaller::<( - sp_io::SubstrateHostFunctions, - frame_benchmarking::benchmarking::HostFunctions, - EHF, - )>::new(code); - let preset = Some(&self.genesis_builder_preset); - - let mut storage = - genesis_config_caller.get_storage_for_named_preset(preset).inspect_err(|e| { - let presets = genesis_config_caller.preset_names().unwrap_or_default(); - log::error!( - "Please pick one of the available presets with \ - `--genesis-builder-preset=`. Available presets ({}): {:?}. Error: {:?}", - presets.len(), - presets, - e - ); - })?; - - storage.top.insert(CODE.into(), code.into()); - - Ok(storage) - } - /// Execute a state machine and decode its return value as `R`. fn exec_state_machine( mut machine: StateMachine, H, Exec>, diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs index a507c1d1f5484..873a1b9eb04e0 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -19,7 +19,7 @@ mod command; mod types; mod writer; -use crate::{pallet::types::GenesisBuilderPolicy, shared::HostInfoParams}; +use crate::shared::{GenesisBuilderPolicy, HostInfoParams}; use clap::ValueEnum; use sc_cli::{ WasmExecutionMethod, WasmtimeInstantiationStrategy, DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/types.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/types.rs index ce37be455e8a1..6b1c0639e3e6e 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/types.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/types.rs @@ -21,25 +21,6 @@ use sc_cli::Result; use sp_core::traits::RuntimeCode; use sp_runtime::traits::Hash; -/// How the genesis state for benchmarking should be build. -#[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy)] -#[clap(rename_all = "kebab-case")] -pub enum GenesisBuilderPolicy { - /// Do not provide any genesis state. - /// - /// Benchmarks are advised to function with this, since they should setup their own required - /// state. However, to keep backwards compatibility, this is not the default. - None, - /// Let the runtime build the genesis state through its `BuildGenesisConfig` runtime API. - Runtime, - // Use the runtime from the Spec file to build the genesis state. - SpecRuntime, - /// Use the spec file to build the genesis state. This fails when there is no spec. - SpecGenesis, - /// Same as `SpecGenesis` - only here for backwards compatibility. - Spec, -} - /// A runtime blob that was either fetched from genesis storage or loaded from a file. // NOTE: This enum is only needed for the annoying lifetime bounds on `RuntimeCode`. Otherwise we // could just directly return the blob. diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs new file mode 100644 index 0000000000000..308096895f2d3 --- /dev/null +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -0,0 +1,138 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +use crate::shared::GenesisBuilderPolicy; +use sc_chain_spec::{ChainSpec, GenesisConfigBuilderRuntimeCaller}; +use sc_cli::Result; +use serde_json::Value; +use sp_storage::{well_known_keys::CODE, Storage}; +use sp_wasm_interface::HostFunctions; +use std::{fs, path::PathBuf}; + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/// Build the genesis storage by either the Genesis Builder API, chain spec or nothing. +/// +/// Behaviour can be controlled by the `genesis_builder` parameter. + +/// When the runtime could not build the genesis storage. +const ERROR_CANNOT_BUILD_GENESIS: &str = "The runtime returned \ +an error when trying to build the genesis storage. Please ensure that all pallets \ +define a genesis config that can be built. This can be tested with: \ +https://github.com/paritytech/polkadot-sdk/pull/3412"; + +/// Warn when using the chain spec to generate the genesis state. +const WARN_SPEC_GENESIS_CTOR: &'static str = "Using the chain spec instead of the runtime to \ +generate the genesis state is deprecated. Please remove the `--chain`/`--dev`/`--local` argument, \ +point `--runtime` to your runtime blob and set `--genesis-builder=runtime`. This warning may \ +become a hard error any time after December 2024."; + +pub fn get_code_bytes( + chain_spec: &Option>, + runtime: &Option, +) -> Result> { + match (chain_spec, runtime) { + (None, Some(runtime_code_path)) => Ok(fs::read(runtime_code_path)?), + // Get the code blob from the chain spec. + // First transform the chain_spec to storage, then extract the code. + (Some(chain_spec), None) => { + let mut storage = chain_spec + .as_storage_builder() + .build_storage() + .map_err(|e| format!("Can not transform chain-spec to storage {}", e))?; + Ok(storage.top.remove(CODE).ok_or("chain spec genesis does not contain code")?) + }, + (Some(_), Some(_)) => + Err("Both runtime and chain spec provided, please only provide one of both.".into()), + (_, _) => Err("Please provide either a runtime or a chain spec.".into()), + } +} +pub fn genesis_storage( + genesis_builder: Option, + runtime: &Option, + code_bytes: Option<&Vec>, + genesis_builder_preset: &String, + chain_spec: &Option>, + storage_patcher: Option Value + 'static>>, +) -> Result { + Ok(match (genesis_builder, runtime) { + (Some(GenesisBuilderPolicy::None), Some(_)) => return Err("Cannot use `--genesis-builder=none` with `--runtime` since the runtime would be ignored.".into()), + (Some(GenesisBuilderPolicy::None), None) => Storage::default(), + (Some(GenesisBuilderPolicy::SpecGenesis | GenesisBuilderPolicy::Spec), Some(_)) => + return Err("Cannot use `--genesis-builder=spec-genesis` with `--runtime` since the runtime would be ignored.".into()), + (Some(GenesisBuilderPolicy::SpecGenesis | GenesisBuilderPolicy::Spec), None) | (None, None) => { + log::warn!("{WARN_SPEC_GENESIS_CTOR}"); + let Some(chain_spec) = chain_spec else { + return Err("No chain spec specified to generate the genesis state".into()); + }; + + let storage = chain_spec + .build_storage() + .map_err(|e| format!("{ERROR_CANNOT_BUILD_GENESIS}\nError: {e}"))?; + + storage + }, + (Some(GenesisBuilderPolicy::SpecRuntime), Some(_)) => + return Err("Cannot use `--genesis-builder=spec` with `--runtime` since the runtime would be ignored.".into()), + (Some(GenesisBuilderPolicy::SpecRuntime), None) => { + let Some(code) = code_bytes else { + return Err("Can not build genesis from runtime. Please provide a runtime.".into()); + }; + + genesis_from_code::(code.as_slice(), genesis_builder_preset, storage_patcher)? + }, + (Some(GenesisBuilderPolicy::Runtime), None) => return Err("Cannot use `--genesis-builder=runtime` without `--runtime`".into()), + (Some(GenesisBuilderPolicy::Runtime), Some(_)) | (None, Some(_)) => { + let Some(code) = code_bytes else { + return Err("Can not build genesis from runtime. Please provide a runtime.".into()); + }; + + genesis_from_code::(code.as_slice(), genesis_builder_preset, storage_patcher)? + } + }) +} + +fn genesis_from_code( + code: &[u8], + genesis_builder_preset: &String, + storage_patcher: Option Value>>, +) -> Result { + let genesis_config_caller = GenesisConfigBuilderRuntimeCaller::<( + sp_io::SubstrateHostFunctions, + frame_benchmarking::benchmarking::HostFunctions, + EHF, + )>::new(code); + + let mut preset_json = + genesis_config_caller.get_named_preset(Some(&genesis_builder_preset.to_string()))?; + if let Some(patcher) = storage_patcher { + preset_json = patcher(preset_json); + } + + let mut storage = + genesis_config_caller.get_storage_for_patch(preset_json).inspect_err(|e| { + let presets = genesis_config_caller.preset_names().unwrap_or_default(); + log::error!( + "Please pick one of the available presets with \ + `--genesis-builder-preset=`. Available presets ({}): {:?}. Error: {:?}", + presets.len(), + presets, + e + ); + })?; + + storage.top.insert(CODE.into(), code.into()); + + Ok(storage) +} diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs b/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs index f8aa49b867f7d..d727e89c3dc94 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs @@ -17,6 +17,7 @@ //! Code that is shared among all benchmarking sub-commands. +pub mod genesis_state; pub mod record; pub mod stats; pub mod weight_params; @@ -132,3 +133,22 @@ impl HostInfoParams { gather_sysinfo().cpu.unwrap_or(self.cpuname_fallback.clone()) } } + +/// How the genesis state for benchmarking should be build. +#[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy, Serialize)] +#[clap(rename_all = "kebab-case")] +pub enum GenesisBuilderPolicy { + /// Do not provide any genesis state. + /// + /// Benchmarks are advised to function with this, since they should setup their own required + /// state. However, to keep backwards compatibility, this is not the default. + None, + /// Let the runtime build the genesis state through its `BuildGenesisConfig` runtime API. + Runtime, + /// Use the runtime from the Spec file to build the genesis state. + SpecRuntime, + /// Use the spec file to build the genesis state. This fails when there is no spec. + SpecGenesis, + /// Same as `SpecGenesis` - only here for backwards compatibility. + Spec, +} diff --git a/substrate/utils/frame/omni-bencher/src/command.rs b/substrate/utils/frame/omni-bencher/src/command.rs index 19177ed549b78..51fd79668b0d7 100644 --- a/substrate/utils/frame/omni-bencher/src/command.rs +++ b/substrate/utils/frame/omni-bencher/src/command.rs @@ -16,7 +16,7 @@ // limitations under the License. use clap::Parser; -use frame_benchmarking_cli::BenchmarkCmd; +use frame_benchmarking_cli::{BenchmarkCmd, OpaqueBlock}; use sc_cli::Result; use sp_runtime::traits::BlakeTwo256; @@ -129,27 +129,29 @@ impl Command { } } } - +// impl V1SubCommand { pub fn run(self) -> Result<()> { - let pallet = match self { + match self { V1SubCommand::Benchmark(V1BenchmarkCommand { sub }) => match sub { - BenchmarkCmd::Pallet(pallet) => pallet, + BenchmarkCmd::Pallet(pallet) => { + if let Some(spec) = pallet.shared_params.chain { + return Err(format!( + "Chain specs are not supported. Please remove `--chain={spec}` and use \ + `--runtime=` instead" + ) + .into()); + } + + pallet.run_with_spec::(None) + }, + BenchmarkCmd::Overhead(overhead_cmd) => + overhead_cmd.run_with_extrinsic_builder::(None), _ => return Err( "Only the `v1 benchmark pallet` command is currently supported".into() ), }, - }; - - if let Some(spec) = pallet.shared_params.chain { - return Err(format!( - "Chain specs are not supported. Please remove `--chain={spec}` and use \ - `--runtime=` instead" - ) - .into()) } - - pallet.run_with_spec::(None) } } From 61ead77969ab0c88445057f5f4a302f458f0741c Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 1 Oct 2024 14:33:44 +0200 Subject: [PATCH 02/43] Add missing license --- .../test/runtime/src/genesis_config_presets.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cumulus/test/runtime/src/genesis_config_presets.rs b/cumulus/test/runtime/src/genesis_config_presets.rs index c9fe1d89f4c5f..327e8437f258d 100644 --- a/cumulus/test/runtime/src/genesis_config_presets.rs +++ b/cumulus/test/runtime/src/genesis_config_presets.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use super::{ AccountId, AuraConfig, AuraId, BalancesConfig, ParachainInfoConfig, RuntimeGenesisConfig, SudoConfig, From 8cfa9439a9b314300f1727f6e9b35dbd841582e5 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 2 Oct 2024 10:15:00 +0200 Subject: [PATCH 03/43] Change ExtrinsicBuilder parameter to function --- .../utils/frame/benchmarking-cli/src/lib.rs | 5 ++- .../benchmarking-cli/src/overhead/cmd.rs | 25 +++++++++---- .../src/overhead/remark_builders.rs | 36 ++++++++++++++++--- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/substrate/utils/frame/benchmarking-cli/src/lib.rs b/substrate/utils/frame/benchmarking-cli/src/lib.rs index 36b856927f347..eb20c0ef3e593 100644 --- a/substrate/utils/frame/benchmarking-cli/src/lib.rs +++ b/substrate/utils/frame/benchmarking-cli/src/lib.rs @@ -29,7 +29,10 @@ pub use block::BlockCmd; pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; pub use machine::{MachineCmd, SUBSTRATE_REFERENCE_HARDWARE}; pub use overhead::{ - remark_builders::{DynamicRemarkBuilder, SubstrateRemarkBuilder}, + remark_builders::{ + fetch_latest_metadata_from_blob, fetch_relevant_runtime_data, fetch_version, + DynamicRemarkBuilder, SubstrateRemarkBuilder, + }, OpaqueBlock, OverheadCmd, }; pub use pallet::PalletCmd; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index f20b14727ca18..e04e810db4f2e 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -49,7 +49,7 @@ use serde::Serialize; use serde_json::{json, Value}; use sp_api::{ApiExt, CallApiAt, Core, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; -use sp_core::crypto::AccountId32; +use sp_core::{crypto::AccountId32, H256}; use sp_inherents::{InherentData, InherentDataProvider}; use sp_runtime::{ generic, @@ -58,7 +58,7 @@ use sp_runtime::{ }; use sp_wasm_interface::HostFunctions; use std::{fmt::Debug, path::PathBuf, sync::Arc}; -use subxt::{ext::futures, utils::H256, Metadata}; +use subxt::{ext::futures, Metadata}; use subxt_signer::{eth::Keypair as EthKeypair, DeriveJunction}; const DEFAULT_PARA_ID: u32 = 100; @@ -344,7 +344,15 @@ impl OverheadCmd { /// Run the benchmark overhead command. pub fn run_with_extrinsic_builder( &self, - ext_builder: Option>, + ext_builder_provider: Option< + Box< + dyn FnOnce( + subxt::Metadata, + H256, + subxt::client::RuntimeVersion, + ) -> Box, + >, + >, ) -> Result<()> where Block: BlockT, @@ -371,15 +379,20 @@ impl OverheadCmd { let inherent_data = create_inherent_data(&client, &chain_type); - let ext_builder = ext_builder.unwrap_or_else(|| { + let ext_builder = { let genesis = client.usage_info().chain.best_hash; let version = client.runtime_api().version(genesis).unwrap(); let runtime_version = subxt::client::RuntimeVersion { spec_version: version.spec_version, transaction_version: version.transaction_version, }; - Box::new(SubstrateRemarkBuilder::new(metadata, genesis, runtime_version)) - }); + + match ext_builder_provider { + Some(provider) => provider(metadata, genesis, runtime_version), + None => Box::new(SubstrateRemarkBuilder::new(metadata, genesis, runtime_version)) + as Box<_>, + } + }; self.run( "Overhead Benchmark".to_string(), diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs index 0664e5b9470f2..b5f2494474e4e 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs @@ -9,11 +9,12 @@ use sp_core::{ }; use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; use sp_state_machine::BasicExternalities; +use sp_version::RuntimeVersion; use sp_wasm_interface::HostFunctions; use std::{borrow::Cow, sync::Arc}; use subxt::{ - client::RuntimeVersion, config::substrate::SubstrateExtrinsicParamsBuilder, Config, - OfflineClient, SubstrateConfig, + client::RuntimeVersion as SubxtRuntimeVersion, + config::substrate::SubstrateExtrinsicParamsBuilder, Config, OfflineClient, SubstrateConfig, }; pub type SubstrateRemarkBuilder = DynamicRemarkBuilder; @@ -36,7 +37,7 @@ impl DynamicRemarkBuilder { .pop() .ok_or("No runtime version supported".to_string())?; let version = api.version(genesis).unwrap(); - let runtime_version = RuntimeVersion { + let runtime_version = SubxtRuntimeVersion { spec_version: version.spec_version, transaction_version: version.transaction_version, }; @@ -54,7 +55,7 @@ impl DynamicRemarkBuilder { pub fn new( metadata: subxt::Metadata, genesis_hash: C::Hash, - runtime_version: RuntimeVersion, + runtime_version: SubxtRuntimeVersion, ) -> Self { Self { offline_client: OfflineClient::new(genesis_hash, runtime_version, metadata) } } @@ -103,6 +104,33 @@ impl<'a> BasicCodeFetcher<'a> { } } +pub fn fetch_relevant_runtime_data( + code_bytes: &Vec, +) -> Result<(SubxtRuntimeVersion, subxt::Metadata), String> { + let executor = WasmExecutor::::builder().with_allow_missing_host_functions(true).build(); + let version = fetch_version(&executor, code_bytes).unwrap(); + let opaque_metadata = fetch_latest_metadata_from_blob(&executor, code_bytes).unwrap(); + let metadata = subxt::Metadata::decode(&mut (*opaque_metadata).as_slice()).unwrap(); + Ok((version, metadata)) +} + +pub fn fetch_version( + executor: &WasmExecutor, + code_bytes: &Vec, +) -> sc_cli::Result { + let mut ext = BasicExternalities::default(); + let fetcher = BasicCodeFetcher(code_bytes.into()); + let version_result = executor + .call(&mut ext, &fetcher.runtime_code(), "Core_version", &[], CallContext::Offchain) + .0 + .map_err(|e| format!("Unable to fetch version from blob: {e}"))?; + let version = RuntimeVersion::decode(&mut version_result.as_slice())?; + Ok(SubxtRuntimeVersion { + spec_version: version.spec_version, + transaction_version: version.transaction_version, + }) +} + pub fn fetch_latest_metadata_from_blob( executor: &WasmExecutor, code_bytes: &Vec, From 8b0e4aa8a6c624b308b79cabbb708d829cd6e0a9 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Sun, 13 Oct 2024 22:27:14 +0200 Subject: [PATCH 04/43] Compilation fixes --- Cargo.lock | 1 + .../polkadot-parachain-lib/Cargo.toml | 1 + .../polkadot-parachain-lib/src/command.rs | 11 ++++++++++- .../src/common/command.rs | 19 +++++++++++++++++-- substrate/bin/node/cli/src/command.rs | 2 +- templates/solochain/node/src/command.rs | 2 +- 6 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa780a7a695b9..2e19000c54fcf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15066,6 +15066,7 @@ dependencies = [ "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-state-trie-migration-rpc", + "subxt", "tokio", "wait-timeout", ] diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml b/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml index 733ea09ef2b80..87b0dc9c33f65 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml @@ -22,6 +22,7 @@ log = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } docify = { workspace = true } +subxt = { workspace = true } # Local jsonrpsee = { features = ["server"], workspace = true } diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs index 7e6fd564b1c70..adf50b66ed763 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs @@ -37,6 +37,7 @@ use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicBuilder, SUBSTRATE_REFERENCE use log::info; use sc_cli::{Result, SubstrateCli}; use sp_runtime::traits::AccountIdConversion; +use sp_core::H256; #[cfg(feature = "runtime-benchmarks")] use sp_runtime::traits::HashingFor; @@ -51,7 +52,15 @@ pub struct RunConfig { /// /// Some benchmarks attempt to build blocks. This extrinsic builder /// is used to populate these blocks with extrinsics. - pub extrinsic_builder: Option>, + pub extrinsic_builder: Option< + Box< + dyn FnOnce( + subxt::Metadata, + H256, + subxt::client::RuntimeVersion, + ) -> Box, + >, + >, } impl RunConfig { diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs index 969ccd2800055..3f23b3bb8a919 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs +++ b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs @@ -21,6 +21,7 @@ use frame_benchmarking_cli::StorageCmd; use frame_benchmarking_cli::{BlockCmd, ExtrinsicBuilder, OverheadCmd}; use sc_cli::{CheckBlockCmd, ExportBlocksCmd, ExportStateCmd, ImportBlocksCmd, RevertCmd}; use sc_service::{Configuration, TaskManager}; +use sp_core::H256; use std::{future::Future, pin::Pin}; type SyncCmdResult = sc_cli::Result<()>; @@ -81,7 +82,14 @@ pub trait NodeCommandRunner { fn run_benchmark_overhead_cmd( self: Box, cmd: &OverheadCmd, - ext_builder: Option>, + ext_builder: Option< + Box< + dyn FnOnce( + subxt::Metadata, + H256, + subxt::client::RuntimeVersion, + ) -> Box, + >> ) -> SyncCmdResult; } @@ -168,7 +176,14 @@ where fn run_benchmark_overhead_cmd( self: Box, cmd: &OverheadCmd, - ext_builder: Option>, + ext_builder: Option< + Box< + dyn FnOnce( + subxt::Metadata, + H256, + subxt::client::RuntimeVersion, + ) -> Box, + >> ) -> SyncCmdResult { cmd.run_with_extrinsic_builder::<::Block, ()>(ext_builder) } diff --git a/substrate/bin/node/cli/src/command.rs b/substrate/bin/node/cli/src/command.rs index 51fbf0904cf8c..aca82c2de7943 100644 --- a/substrate/bin/node/cli/src/command.rs +++ b/substrate/bin/node/cli/src/command.rs @@ -136,7 +136,7 @@ pub fn run() -> Result<()> { let ext_builder = RemarkBuilder::new(partial.client.clone()); cmd.run( - config, + config.chain_spec.name().into(), partial.client, inherent_benchmark_data()?, Vec::new(), diff --git a/templates/solochain/node/src/command.rs b/templates/solochain/node/src/command.rs index 624ace1bf350a..aaad21d0e6419 100644 --- a/templates/solochain/node/src/command.rs +++ b/templates/solochain/node/src/command.rs @@ -144,7 +144,7 @@ pub fn run() -> sc_cli::Result<()> { let ext_builder = RemarkBuilder::new(client.clone()); cmd.run( - config, + config.chain_spec.name().into(), client, inherent_benchmark_data()?, Vec::new(), From e514afbac110d4f75d9c28af47bb0ffba984a2c1 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 15 Oct 2024 10:14:27 +0200 Subject: [PATCH 05/43] Compilation Fixes --- Cargo.lock | 54 +++++++++++++++++++ .../lib/src/common/command.rs | 4 +- cumulus/polkadot-omni-node/src/main.rs | 5 +- substrate/bin/node/cli/src/command.rs | 1 + .../benchmarking-cli/src/overhead/cmd.rs | 6 ++- .../src/overhead/remark_builders.rs | 5 +- templates/solochain/node/src/command.rs | 1 + 7 files changed, 66 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca71985b69f07..2a9421a565590 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1615,6 +1615,22 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "bip32" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa13fae8b6255872fd86f7faf4b41168661d7d78609f7bfe6771b85c6739a15b" +dependencies = [ + "bs58", + "hmac 0.12.1", + "k256", + "rand_core 0.6.4", + "ripemd", + "sha2 0.10.8", + "subtle 2.5.0", + "zeroize", +] + [[package]] name = "bip39" version = "2.0.0" @@ -2564,6 +2580,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ + "sha2 0.10.8", "tinyvec", ] @@ -4777,6 +4794,7 @@ dependencies = [ "pallet-transaction-payment", "parity-scale-codec", "scale-info", + "serde_json", "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", @@ -4784,6 +4802,7 @@ dependencies = [ "sp-genesis-builder", "sp-inherents", "sp-io 30.0.0", + "sp-keyring", "sp-offchain", "sp-runtime 31.0.1", "sp-session", @@ -4860,6 +4879,7 @@ dependencies = [ "sp-consensus", "sp-consensus-aura", "sp-core 28.0.0", + "sp-genesis-builder", "sp-io 30.0.0", "sp-keyring", "sp-runtime 31.0.1", @@ -6205,15 +6225,20 @@ dependencies = [ "chrono", "clap 4.5.13", "comfy-table", + "cumulus-client-parachain-inherent", + "cumulus-primitives-proof-size-hostfunction", "frame-benchmarking", "frame-support", "frame-system", "gethostname", "handlebars", + "hex", "itertools 0.11.0", "linked-hash-map", "log", "parity-scale-codec", + "polkadot-parachain-primitives", + "polkadot-primitives", "rand", "rand_pcg", "sc-block-builder", @@ -6227,8 +6252,10 @@ dependencies = [ "serde", "serde_json", "sp-api 26.0.0", + "sp-block-builder", "sp-blockchain", "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-database", "sp-externalities 0.25.0", "sp-genesis-builder", @@ -6238,8 +6265,13 @@ dependencies = [ "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-storage 19.0.0", + "sp-timestamp", + "sp-transaction-pool", "sp-trie 29.0.0", + "sp-version 29.0.0", "sp-wasm-interface 20.0.0", + "subxt", + "subxt-signer", "thiserror", "thousands", ] @@ -8369,6 +8401,16 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keccak-hash" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c" +dependencies = [ + "primitive-types 0.12.2", + "tiny-keccak", +] + [[package]] name = "keccak-hasher" version = "0.16.0" @@ -14913,6 +14955,7 @@ dependencies = [ "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-state-trie-migration-rpc", + "subxt", "tokio", "wait-timeout", ] @@ -17633,6 +17676,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "rle-decode-fast" version = "1.0.3" @@ -24182,10 +24234,12 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49888ae6ae90fe01b471193528eea5bd4ed52d8eecd2d13f4a2333b87388850" dependencies = [ + "bip32", "bip39", "cfg-if", "hex", "hmac 0.12.1", + "keccak-hash", "parity-scale-codec", "pbkdf2", "regex", diff --git a/cumulus/polkadot-omni-node/lib/src/common/command.rs b/cumulus/polkadot-omni-node/lib/src/common/command.rs index 683a9f6ba2dd3..6ca8903d84b4e 100644 --- a/cumulus/polkadot-omni-node/lib/src/common/command.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/command.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::common::spec::BaseNodeSpec; +use crate::common::spec::{BaseNodeSpec}; use cumulus_client_cli::ExportGenesisHeadCommand; #[cfg(any(feature = "runtime-benchmarks"))] use frame_benchmarking_cli::StorageCmd; @@ -185,6 +185,6 @@ where ) -> Box, >> ) -> SyncCmdResult { - cmd.run_with_extrinsic_builder::<::Block, ()>(ext_builder) + cmd.run_with_extrinsic_builder::<::Block, ()>(ext_builder) } } diff --git a/cumulus/polkadot-omni-node/src/main.rs b/cumulus/polkadot-omni-node/src/main.rs index a86ec6f6fde61..5f0cff93eb171 100644 --- a/cumulus/polkadot-omni-node/src/main.rs +++ b/cumulus/polkadot-omni-node/src/main.rs @@ -52,9 +52,6 @@ impl CliConfigT for CliConfig { fn main() -> color_eyre::eyre::Result<()> { color_eyre::install()?; - let config = RunConfig { - chain_spec_loader: Box::new(DiskChainSpecLoader), - runtime_resolver: Box::new(DefaultRuntimeResolver), - }; + let config = RunConfig::new(Box::new(DefaultRuntimeResolver), Box::new(DiskChainSpecLoader)); Ok(run::(config)?) } diff --git a/substrate/bin/node/cli/src/command.rs b/substrate/bin/node/cli/src/command.rs index aca82c2de7943..2910002e5b274 100644 --- a/substrate/bin/node/cli/src/command.rs +++ b/substrate/bin/node/cli/src/command.rs @@ -141,6 +141,7 @@ pub fn run() -> Result<()> { inherent_benchmark_data()?, Vec::new(), &ext_builder, + false, ) }, BenchmarkCmd::Extrinsic(cmd) => { diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index e04e810db4f2e..81d15884674e8 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -389,8 +389,10 @@ impl OverheadCmd { match ext_builder_provider { Some(provider) => provider(metadata, genesis, runtime_version), - None => Box::new(SubstrateRemarkBuilder::new(metadata, genesis, runtime_version)) - as Box<_>, + None => { + let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); + Box::new(SubstrateRemarkBuilder::new(metadata, genesis, runtime_version)) + as Box<_>}, } }; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs index b5f2494474e4e..695e4fe2087bb 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs @@ -23,10 +23,10 @@ pub struct DynamicRemarkBuilder { offline_client: OfflineClient, } -impl DynamicRemarkBuilder { +impl> DynamicRemarkBuilder { pub fn new_from_client(client: Arc) -> sc_cli::Result where - Block: BlockT, + Block: BlockT, Client: UsageProvider + ProvideRuntimeApi, Client::Api: Metadata + Core, { @@ -47,6 +47,7 @@ impl DynamicRemarkBuilder { .ok_or("Unable to decode metadata".to_string())?; let metadata = subxt::Metadata::decode(&mut (*metadata).as_slice())?; + let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); Ok(Self { offline_client: OfflineClient::new(genesis, runtime_version, metadata) }) } } diff --git a/templates/solochain/node/src/command.rs b/templates/solochain/node/src/command.rs index 45a3ea7f9e0f9..c12a022f62d4f 100644 --- a/templates/solochain/node/src/command.rs +++ b/templates/solochain/node/src/command.rs @@ -149,6 +149,7 @@ pub fn run() -> sc_cli::Result<()> { inherent_benchmark_data()?, Vec::new(), &ext_builder, + false ) }, BenchmarkCmd::Extrinsic(cmd) => { From fbc607e82c3b61c5ab3ee526e515f05670ff5eba Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 15 Oct 2024 10:23:23 +0200 Subject: [PATCH 06/43] Remove account generation --- .../benchmarking-cli/src/overhead/cmd.rs | 97 +------------------ .../benchmarking-cli/src/pallet/command.rs | 3 +- .../src/shared/genesis_state.rs | 12 +-- 3 files changed, 5 insertions(+), 107 deletions(-) diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 81d15884674e8..5b58eeb4ccbdf 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -46,10 +46,9 @@ use sc_client_db::{BlocksPruning, DatabaseSettings, DatabaseSource}; use sc_executor::WasmExecutor; use sc_service::{new_client, new_db_backend, BasePath, ClientConfig, TFullClient, TaskManager}; use serde::Serialize; -use serde_json::{json, Value}; use sp_api::{ApiExt, CallApiAt, Core, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; -use sp_core::{crypto::AccountId32, H256}; +use sp_core::H256; use sp_inherents::{InherentData, InherentDataProvider}; use sp_runtime::{ generic, @@ -59,7 +58,6 @@ use sp_runtime::{ use sp_wasm_interface::HostFunctions; use std::{fmt::Debug, path::PathBuf, sync::Arc}; use subxt::{ext::futures, Metadata}; -use subxt_signer::{eth::Keypair as EthKeypair, DeriveJunction}; const DEFAULT_PARA_ID: u32 = 100; @@ -124,10 +122,6 @@ pub struct OverheadParams { #[arg(long, value_enum)] pub genesis_builder: Option, - /// Account type to generate. - #[arg(long)] - pub account_type: Option, - /// Inflate the genesis state by generating accounts. /// /// Can be used together with `--account_type` to specify the type of accounts to generate. @@ -140,15 +134,6 @@ pub struct OverheadParams { pub para_id: Option, } -/// Enum representing the type of account to generate. -#[derive(Debug, Clone, PartialEq, clap::ValueEnum, Serialize)] -pub enum AccountType { - /// Sr25519 account type. - Sr25519, - /// ECDSA account type. - ECDSA, -} - /// Type of a benchmark. #[derive(Serialize, Clone, PartialEq, Copy)] pub(crate) enum BenchmarkType { @@ -227,79 +212,6 @@ pub struct ParachainExtension { pub para_id: Option, } -fn generate_balances_sr25519(num_accounts: u64) -> Vec { - let alice_pair = subxt_signer::sr25519::dev::alice(); - (0..num_accounts) - .into_iter() - .map(|path| { - let derived = alice_pair.derive([DeriveJunction::hard(path.to_string())]); - json!((AccountId32::from(derived.public_key().0), 1u64 << 60,)) - }) - .collect() -} - -fn generate_balances_ecdsa(num_accounts: u64) -> Vec { - let alice_pair = subxt_signer::ecdsa::dev::alice(); - (0..num_accounts) - .into_iter() - .map(|path| { - let derived = alice_pair.derive([DeriveJunction::hard(path.to_string())]).unwrap(); - json!(( - "0x".to_string() + &hex::encode(EthKeypair::from(derived).account_id()), - 1u64 << 60, - )) - }) - .collect() -} - -/// Patch the genesis state. -/// -/// We perform two actions: -/// 1. Inflate the genesis state by generating accounts. -/// 2. Patch the parachain id into the genesis config. This is necessary since the inherents -/// also contain a parachain id and they need to match. -fn patch_genesis( - mut input_value: Value, - num_accounts: Option, - chain_type: ChainType, - generate_accounts: Option, -) -> Value { - // If we identified a parachain we should patch a parachain id into the genesis config. - // This ensures compatibility with the inherents that we provide to successfully build a - // block. - if let Parachain(para_id) = chain_type { - sc_chain_spec::json_patch::merge( - &mut input_value, - json!({ - "parachainInfo": { - "parachainId": para_id, - } - }), - ); - log::debug!("Genesis Config Json"); - log::debug!("{}", input_value); - } - - if let Some(num_accounts) = num_accounts { - // Attempt to patch balances - if let Some(balances) = input_value - .get_mut("balances") - .and_then(|info| info.get_mut("balances")) - .and_then(|balance| balance.as_array_mut()) - { - let generated = match &generate_accounts { - None => Default::default(), - Some(AccountType::Sr25519) => generate_balances_sr25519(num_accounts), - Some(AccountType::ECDSA) => generate_balances_ecdsa(num_accounts), - }; - balances.extend(generated); - } else { - log::warn!("No balances found."); - } - } - input_value -} - impl OverheadCmd { /// Make an educated guess what kind of chain we are dealing with. fn identify_chain(&self, metadata: &Metadata, para_id: Option) -> Result { @@ -425,19 +337,12 @@ impl OverheadCmd { }, })?; - //let storage = self.storage(&code_bytes, chain_spec, &chain_type)?; - let chain_type_for_closure = chain_type.clone(); - let num_accounts = self.params.generate_num_accounts; - let account_type = self.params.account_type.clone(); let storage = shared::genesis_state::genesis_storage::( self.params.genesis_builder, &self.params.runtime, Some(&code_bytes), &self.params.genesis_builder_preset, &chain_spec, - Some(Box::new(move |val| { - patch_genesis(val, num_accounts, chain_type_for_closure, account_type) - })), )?; let genesis_block_builder = GenesisBlockBuilder::new_with_storage( diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index 6e91226a0d3e1..c1476fd06bcf1 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -211,8 +211,7 @@ impl PalletCmd { &self.runtime, Some(&code_bytes), &self.genesis_builder_preset, - &chain_spec, - None + &chain_spec )?; let cache_size = Some(self.database_cache_size as usize); diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs index 308096895f2d3..33a4ec373a6c0 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -6,7 +6,6 @@ use crate::shared::GenesisBuilderPolicy; use sc_chain_spec::{ChainSpec, GenesisConfigBuilderRuntimeCaller}; use sc_cli::Result; -use serde_json::Value; use sp_storage::{well_known_keys::CODE, Storage}; use sp_wasm_interface::HostFunctions; use std::{fs, path::PathBuf}; @@ -64,7 +63,6 @@ pub fn genesis_storage( code_bytes: Option<&Vec>, genesis_builder_preset: &String, chain_spec: &Option>, - storage_patcher: Option Value + 'static>>, ) -> Result { Ok(match (genesis_builder, runtime) { (Some(GenesisBuilderPolicy::None), Some(_)) => return Err("Cannot use `--genesis-builder=none` with `--runtime` since the runtime would be ignored.".into()), @@ -90,7 +88,7 @@ pub fn genesis_storage( return Err("Can not build genesis from runtime. Please provide a runtime.".into()); }; - genesis_from_code::(code.as_slice(), genesis_builder_preset, storage_patcher)? + genesis_from_code::(code.as_slice(), genesis_builder_preset)? }, (Some(GenesisBuilderPolicy::Runtime), None) => return Err("Cannot use `--genesis-builder=runtime` without `--runtime`".into()), (Some(GenesisBuilderPolicy::Runtime), Some(_)) | (None, Some(_)) => { @@ -98,7 +96,7 @@ pub fn genesis_storage( return Err("Can not build genesis from runtime. Please provide a runtime.".into()); }; - genesis_from_code::(code.as_slice(), genesis_builder_preset, storage_patcher)? + genesis_from_code::(code.as_slice(), genesis_builder_preset)? } }) } @@ -106,7 +104,6 @@ pub fn genesis_storage( fn genesis_from_code( code: &[u8], genesis_builder_preset: &String, - storage_patcher: Option Value>>, ) -> Result { let genesis_config_caller = GenesisConfigBuilderRuntimeCaller::<( sp_io::SubstrateHostFunctions, @@ -114,11 +111,8 @@ fn genesis_from_code( EHF, )>::new(code); - let mut preset_json = + let preset_json = genesis_config_caller.get_named_preset(Some(&genesis_builder_preset.to_string()))?; - if let Some(patcher) = storage_patcher { - preset_json = patcher(preset_json); - } let mut storage = genesis_config_caller.get_storage_for_patch(preset_json).inspect_err(|e| { From b0327b192ca3d16caae4dd9f267c65c05858b267 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 17 Oct 2024 16:38:38 +0200 Subject: [PATCH 07/43] Fixes --- .../service/benches/transaction_throughput.rs | 6 +++--- cumulus/test/service/benches/validate_block.rs | 2 +- .../frame/benchmarking-cli/src/overhead/cmd.rs | 8 +++++++- .../src/overhead/remark_builders.rs | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/cumulus/test/service/benches/transaction_throughput.rs b/cumulus/test/service/benches/transaction_throughput.rs index 011eb4c7d50e3..bba624e36ad19 100644 --- a/cumulus/test/service/benches/transaction_throughput.rs +++ b/cumulus/test/service/benches/transaction_throughput.rs @@ -54,7 +54,7 @@ fn create_account_extrinsics(client: &Client, accounts: &[sr25519::Pair]) -> Vec SudoCall::sudo { call: Box::new( BalancesCall::force_set_balance { - who: AccountId::from(a.public()), + who: AccountId::from(a.public()).into(), new_free: 0, } .into(), @@ -69,7 +69,7 @@ fn create_account_extrinsics(client: &Client, accounts: &[sr25519::Pair]) -> Vec SudoCall::sudo { call: Box::new( BalancesCall::force_set_balance { - who: AccountId::from(a.public()), + who: AccountId::from(a.public()).into(), new_free: 1_000_000_000_000 * ExistentialDeposit::get(), } .into(), @@ -96,7 +96,7 @@ fn create_benchmark_extrinsics( construct_extrinsic( client, BalancesCall::transfer_allow_death { - dest: Bob.to_account_id(), + dest: Bob.to_account_id().into(), value: ExistentialDeposit::get(), }, account.clone(), diff --git a/cumulus/test/service/benches/validate_block.rs b/cumulus/test/service/benches/validate_block.rs index 34b09d99ce985..6ed8c305bb3cc 100644 --- a/cumulus/test/service/benches/validate_block.rs +++ b/cumulus/test/service/benches/validate_block.rs @@ -60,7 +60,7 @@ fn create_extrinsics( let extrinsic: UncheckedExtrinsic = generate_extrinsic_with_pair( client, src.clone(), - BalancesCall::transfer_keep_alive { dest: AccountId::from(dst.public()), value: 10000 }, + BalancesCall::transfer_keep_alive { dest: AccountId::from(dst.public()).into(), value: 10000 }, None, ); diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 5b58eeb4ccbdf..704424d1ffebd 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -40,7 +40,7 @@ use log::info; use polkadot_parachain_primitives::primitives::Id as ParaId; use sc_block_builder::BlockBuilderApi; use sc_chain_spec::{ChainSpec, ChainSpecExtension, GenericChainSpec, GenesisBlockBuilder}; -use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; +use sc_cli::{CliConfiguration, Database, ImportParams, Result, SharedParams}; use sc_client_api::{execution_extensions::ExecutionExtensions, UsageProvider}; use sc_client_db::{BlocksPruning, DatabaseSettings, DatabaseSource}; use sc_executor::WasmExecutor; @@ -327,6 +327,12 @@ impl OverheadCmd { ) -> Result>> { let extensions = ExecutionExtensions::new(None, Arc::new(executor.clone())); + let base_path = match &self.shared_params.base_path { + None => BasePath::new_temp_dir()?, + Some(path) => BasePath::from(path.clone()) + }; + + self.database_config(&base_path.path().to_path_buf(), self.database_cache_size()?.unwrap_or(1024), self.database()?.unwrap_or(Database::RocksDb))?; let backend = new_db_backend(DatabaseSettings { trie_cache_maximum_size: self.trie_cache_maximum_size()?, state_pruning: None, diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs index 695e4fe2087bb..5e2c81908176d 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use crate::extrinsic::ExtrinsicBuilder; use codec::{Decode, Encode}; use sc_client_api::UsageProvider; From dc2ab11e9a4de63652fa3f2393e59e3a8c645813 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 17 Oct 2024 16:51:32 +0200 Subject: [PATCH 08/43] Allow to specify runtime_name --- substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 704424d1ffebd..e03f3509bfc15 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -132,6 +132,10 @@ pub struct OverheadParams { /// a para-id and patch the state accordingly. #[arg(long)] pub para_id: Option, + + /// Runtime name to insert into the weight file template. + #[arg(long, default_value_t = Default::default())] + pub runtime_name: String, } /// Type of a benchmark. @@ -309,7 +313,7 @@ impl OverheadCmd { }; self.run( - "Overhead Benchmark".to_string(), + self.params.runtime_name.clone(), client, inherent_data, Default::default(), From 32ec53a471d3b10d4f8c4524223fef502a57eb1a Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 17 Oct 2024 17:15:47 +0200 Subject: [PATCH 09/43] PrDoc --- prdoc/pr_5891.prdoc | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 prdoc/pr_5891.prdoc diff --git a/prdoc/pr_5891.prdoc b/prdoc/pr_5891.prdoc new file mode 100644 index 0000000000000..95bfe3871cb77 --- /dev/null +++ b/prdoc/pr_5891.prdoc @@ -0,0 +1,12 @@ +# 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: Add benchmark overhead command to frame-omni-bencher + +doc: + - audience: Runtime Dev + description: | + This adds the benchmark overhead command to the `frame-omni-bencher` library. This allows + para- and relay chain teams to generate extrinsic and block base weights. + +crates: [ ] From 7b3046aadfc87b555fad60a44579613a7f3fd263 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 21 Oct 2024 08:10:15 +0200 Subject: [PATCH 10/43] Cleanup --- polkadot/cli/src/command.rs | 19 +++- polkadot/tests/benchmark_extrinsic.rs | 8 -- polkadot/tests/benchmark_overhead.rs | 8 -- .../utils/frame/benchmarking-cli/src/lib.rs | 3 +- .../benchmarking-cli/src/overhead/cmd.rs | 92 ++++++++++++------- .../src/overhead/remark_builders.rs | 75 +++++++-------- 6 files changed, 112 insertions(+), 93 deletions(-) diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index a37bb290d1a20..79999c195e269 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -391,10 +391,21 @@ pub fn run() -> Result<()> { cmd.run(client.clone()).map_err(Error::SubstrateCli) }), - BenchmarkCmd::Overhead(cmd) => cmd - .run_with_extrinsic_builder::(None) - .map_err(Error::SubstrateCli), - // These commands are very similar and can be handled in nearly the same way. + BenchmarkCmd::Overhead(cmd) => runner.sync_run(|config| { + if cmd.params.runtime.is_some() { + return Err(sc_cli::Error::Input( + "Polkadot binary does not support `--runtime` flag for `benchmark overhead`. Please provide a chain spec or use the omni-bencher." + .into(), + ) + .into()) + } + + cmd.run_with_extrinsic_builder_and_spec::( + None, + Some(config.chain_spec), + ) + .map_err(Error::SubstrateCli) + }), BenchmarkCmd::Extrinsic(cmd) => runner.sync_run(|mut config| { let (client, _, _, _) = polkadot_service::new_chain_ops(&mut config)?; let header = client.header(client.info().genesis_hash).unwrap().unwrap(); diff --git a/polkadot/tests/benchmark_extrinsic.rs b/polkadot/tests/benchmark_extrinsic.rs index 529eb29362d4d..7f1a37d38e3f6 100644 --- a/polkadot/tests/benchmark_extrinsic.rs +++ b/polkadot/tests/benchmark_extrinsic.rs @@ -32,14 +32,6 @@ fn benchmark_extrinsic_works() { } } -/// `benchmark extrinsic` rejects all non-dev runtimes. -#[test] -fn benchmark_extrinsic_rejects_non_dev_runtimes() { - for runtime in RUNTIMES { - assert!(benchmark_extrinsic(runtime, "system", "remark").is_err()); - } -} - fn benchmark_extrinsic(runtime: &str, pallet: &str, extrinsic: &str) -> Result<(), String> { let status = Command::new(cargo_bin("polkadot")) .args(["benchmark", "extrinsic", "--chain", runtime]) diff --git a/polkadot/tests/benchmark_overhead.rs b/polkadot/tests/benchmark_overhead.rs index b0912225347df..51f507450f382 100644 --- a/polkadot/tests/benchmark_overhead.rs +++ b/polkadot/tests/benchmark_overhead.rs @@ -29,14 +29,6 @@ fn benchmark_overhead_works() { } } -/// `benchmark overhead` rejects all non-dev runtimes. -#[test] -fn benchmark_overhead_rejects_non_dev_runtimes() { - for runtime in RUNTIMES.into_iter() { - assert!(benchmark_overhead(runtime).is_err()); - } -} - fn benchmark_overhead(runtime: &str) -> Result<(), String> { let tmp_dir = tempdir().expect("could not create a temp dir"); let base_path = tmp_dir.path(); diff --git a/substrate/utils/frame/benchmarking-cli/src/lib.rs b/substrate/utils/frame/benchmarking-cli/src/lib.rs index eb20c0ef3e593..8acbb03e726af 100644 --- a/substrate/utils/frame/benchmarking-cli/src/lib.rs +++ b/substrate/utils/frame/benchmarking-cli/src/lib.rs @@ -30,8 +30,7 @@ pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; pub use machine::{MachineCmd, SUBSTRATE_REFERENCE_HARDWARE}; pub use overhead::{ remark_builders::{ - fetch_latest_metadata_from_blob, fetch_relevant_runtime_data, fetch_version, - DynamicRemarkBuilder, SubstrateRemarkBuilder, + fetch_latest_metadata_from_blob, DynamicRemarkBuilder, SubstrateRemarkBuilder, }, OpaqueBlock, OverheadCmd, }; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index e03f3509bfc15..5ae62d83b5521 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -32,7 +32,7 @@ use crate::{ shared::{self, GenesisBuilderPolicy, HostInfoParams, WeightParams}, }; use clap::{Args, Parser}; -use codec::{Decode, Encode}; +use codec::Encode; use cumulus_client_parachain_inherent::MockValidationDataInherentDataProvider; use fake_runtime_api::RuntimeApi as FakeRuntimeApi; use frame_support::Deserialize; @@ -56,8 +56,12 @@ use sp_runtime::{ DigestItem, OpaqueExtrinsic, }; use sp_wasm_interface::HostFunctions; -use std::{fmt::Debug, path::PathBuf, sync::Arc}; -use subxt::{ext::futures, Metadata}; +use std::{ + fmt::{Debug, Display, Formatter}, + path::PathBuf, + sync::Arc, +}; +use subxt::{client::RuntimeVersion, ext::futures, Metadata}; const DEFAULT_PARA_ID: u32 = 100; @@ -223,21 +227,21 @@ impl OverheadCmd { let parachain_system_exists = metadata.pallet_by_name("ParachainSystem").is_some(); let para_inherent_exists = metadata.pallet_by_name("ParaInherent").is_some(); - log::info!("Identifying chain type based on metadata."); - log::info!("{} ParachainSystem", if parachain_system_exists { "✅" } else { "❌" }); - log::info!("{} ParachainInfo", if parachain_info_exists { "✅" } else { "❌" }); - log::info!("{} ParaInherent", if para_inherent_exists { "✅" } else { "❌" }); + log::debug!("{} ParachainSystem", if parachain_system_exists { "✅" } else { "❌" }); + log::debug!("{} ParachainInfo", if parachain_info_exists { "✅" } else { "❌" }); + log::debug!("{} ParaInherent", if para_inherent_exists { "✅" } else { "❌" }); - if parachain_system_exists && parachain_info_exists { - log::info!("Parachain Identified"); - Ok(Parachain(para_id.or(self.params.para_id).unwrap_or(DEFAULT_PARA_ID))) + let chain_type = if parachain_system_exists && parachain_info_exists { + Parachain(para_id.or(self.params.para_id).unwrap_or(DEFAULT_PARA_ID)) } else if para_inherent_exists { - log::info!("Relaychain Identified"); - Ok(Relaychain) + Relaychain } else { - log::info!("Found Custom chain"); - Ok(Unknown) - } + Unknown + }; + + log::info!("Identified Chain type from metadata: {}", chain_type); + + Ok(chain_type) } fn chain_spec_from_path( &self, @@ -258,32 +262,29 @@ impl OverheadCmd { } /// Run the benchmark overhead command. - pub fn run_with_extrinsic_builder( + pub fn run_with_extrinsic_builder_and_spec( &self, ext_builder_provider: Option< - Box< - dyn FnOnce( - subxt::Metadata, - H256, - subxt::client::RuntimeVersion, - ) -> Box, - >, + Box Box>, >, + chain_spec: Option>, ) -> Result<()> where Block: BlockT, ExtraHF: HostFunctions, { - let (chain_spec, para_id_from_chain_spec) = - self.chain_spec_from_path::<(ParachainHostFunctions, ExtraHF)>()?; + let (chain_spec, para_id_from_chain_spec) = match chain_spec { + spec @ Some(_) => (spec, None), + None => self.chain_spec_from_path::<(ParachainHostFunctions, ExtraHF)>()?, + }; + let code_bytes = shared::genesis_state::get_code_bytes(&chain_spec, &self.params.runtime)?; let executor = WasmExecutor::<(ParachainHostFunctions, ExtraHF)>::builder() .with_allow_missing_host_functions(true) .build(); - let opaque_metadata = fetch_latest_metadata_from_blob(&executor, &code_bytes)?; - let metadata = Metadata::decode(&mut (*opaque_metadata).as_slice())?; + let metadata = fetch_latest_metadata_from_blob(&executor, &code_bytes)?; let chain_type = self.identify_chain(&metadata, para_id_from_chain_spec)?; let client = self.build_client_components::( @@ -298,7 +299,7 @@ impl OverheadCmd { let ext_builder = { let genesis = client.usage_info().chain.best_hash; let version = client.runtime_api().version(genesis).unwrap(); - let runtime_version = subxt::client::RuntimeVersion { + let runtime_version = RuntimeVersion { spec_version: version.spec_version, transaction_version: version.transaction_version, }; @@ -308,7 +309,8 @@ impl OverheadCmd { None => { let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); Box::new(SubstrateRemarkBuilder::new(metadata, genesis, runtime_version)) - as Box<_>}, + as Box<_> + }, } }; @@ -322,6 +324,20 @@ impl OverheadCmd { ) } + /// Run the benchmark overhead command. + pub fn run_with_extrinsic_builder( + &self, + ext_builder_provider: Option< + Box Box>, + >, + ) -> Result<()> + where + Block: BlockT, + ExtraHF: HostFunctions, + { + self.run_with_extrinsic_builder_and_spec::(ext_builder_provider, None) + } + fn build_client_components( &self, chain_spec: Option>, @@ -333,10 +349,14 @@ impl OverheadCmd { let base_path = match &self.shared_params.base_path { None => BasePath::new_temp_dir()?, - Some(path) => BasePath::from(path.clone()) + Some(path) => BasePath::from(path.clone()), }; - self.database_config(&base_path.path().to_path_buf(), self.database_cache_size()?.unwrap_or(1024), self.database()?.unwrap_or(Database::RocksDb))?; + self.database_config( + &base_path.path().to_path_buf(), + self.database_cache_size()?.unwrap_or(1024), + self.database()?.unwrap_or(Database::RocksDb), + )?; let backend = new_db_backend(DatabaseSettings { trie_cache_maximum_size: self.trie_cache_maximum_size()?, state_pruning: None, @@ -478,6 +498,16 @@ enum ChainType { Unknown, } +impl Display for ChainType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + ChainType::Parachain(id) => write!(f, "Parachain(paraid = {})", id), + ChainType::Relaychain => write!(f, "Relaychain"), + ChainType::Unknown => write!(f, "Unknown"), + } + } +} + impl ChainType { fn requires_proof_recording(&self) -> bool { match self { diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs index 5e2c81908176d..834d4123aae3c 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs @@ -26,7 +26,6 @@ use sp_core::{ }; use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; use sp_state_machine::BasicExternalities; -use sp_version::RuntimeVersion; use sp_wasm_interface::HostFunctions; use std::{borrow::Cow, sync::Arc}; use subxt::{ @@ -49,19 +48,41 @@ impl> DynamicRemarkBuilder { { let genesis = client.usage_info().chain.best_hash; let api = client.runtime_api(); - let mut supported_metadata_versions = api.metadata_versions(genesis).unwrap(); - let latest = supported_metadata_versions - .pop() - .ok_or("No runtime version supported".to_string())?; + if let Ok(mut supported_metadata_versions) = api.metadata_versions(genesis) { + let latest = supported_metadata_versions + .pop() + .ok_or("No metadata version supported".to_string())?; + + let version = + api.version(genesis).map_err(|_| "No runtime version supported".to_string())?; + + let runtime_version = SubxtRuntimeVersion { + spec_version: version.spec_version, + transaction_version: version.transaction_version, + }; + let metadata = api + .metadata_at_version(genesis, latest) + .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? + .ok_or("Unable to decode metadata".to_string())?; + + let metadata = subxt::Metadata::decode(&mut (*metadata).as_slice())?; + + let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); + return Ok(Self { + offline_client: OfflineClient::new(genesis, runtime_version, metadata), + }) + } + + log::warn!("No metadata versions found, falling back to deprecated metadata runtime api."); + let metadata = api + .metadata(genesis) + .map_err(|e| format!("Unable to fetch metadata: {:?}", e))?; let version = api.version(genesis).unwrap(); let runtime_version = SubxtRuntimeVersion { spec_version: version.spec_version, transaction_version: version.transaction_version, }; - let metadata = api - .metadata_at_version(genesis, latest) - .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? - .ok_or("Unable to decode metadata".to_string())?; + let metadata = subxt::Metadata::decode(&mut (*metadata).as_slice())?; let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); @@ -122,37 +143,10 @@ impl<'a> BasicCodeFetcher<'a> { } } -pub fn fetch_relevant_runtime_data( - code_bytes: &Vec, -) -> Result<(SubxtRuntimeVersion, subxt::Metadata), String> { - let executor = WasmExecutor::::builder().with_allow_missing_host_functions(true).build(); - let version = fetch_version(&executor, code_bytes).unwrap(); - let opaque_metadata = fetch_latest_metadata_from_blob(&executor, code_bytes).unwrap(); - let metadata = subxt::Metadata::decode(&mut (*opaque_metadata).as_slice()).unwrap(); - Ok((version, metadata)) -} - -pub fn fetch_version( - executor: &WasmExecutor, - code_bytes: &Vec, -) -> sc_cli::Result { - let mut ext = BasicExternalities::default(); - let fetcher = BasicCodeFetcher(code_bytes.into()); - let version_result = executor - .call(&mut ext, &fetcher.runtime_code(), "Core_version", &[], CallContext::Offchain) - .0 - .map_err(|e| format!("Unable to fetch version from blob: {e}"))?; - let version = RuntimeVersion::decode(&mut version_result.as_slice())?; - Ok(SubxtRuntimeVersion { - spec_version: version.spec_version, - transaction_version: version.transaction_version, - }) -} - pub fn fetch_latest_metadata_from_blob( executor: &WasmExecutor, code_bytes: &Vec, -) -> sc_cli::Result { +) -> sc_cli::Result { let mut ext = BasicExternalities::default(); let fetcher = BasicCodeFetcher(code_bytes.into()); let version_result = executor @@ -165,7 +159,7 @@ pub fn fetch_latest_metadata_from_blob( ) .0; - let opaque_metadata: Option = match version_result { + let opaque_metadata: OpaqueMetadata = match version_result { Ok(supported_versions) => { let versions = Vec::::decode(&mut supported_versions.as_slice()) .map_err(|e| format!("Error {e}"))?; @@ -181,7 +175,8 @@ pub fn fetch_latest_metadata_from_blob( ) .0 .map_err(|e| format!("Unable to fetch metadata from blob: {e}"))?; - Decode::decode(&mut encoded.as_slice())? + let opaque: Option = Decode::decode(&mut encoded.as_slice())?; + opaque.ok_or_else(|| "Metadata not found".to_string())? }, Err(_) => { let encoded = executor @@ -198,5 +193,5 @@ pub fn fetch_latest_metadata_from_blob( }, }; - opaque_metadata.ok_or_else(|| "Metadata not found".into()) + Ok(subxt::Metadata::decode(&mut (*opaque_metadata).as_slice())?) } From bda1bd1d231bdf8ccc043555b53a0763c6fbc898 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 21 Oct 2024 11:37:56 +0200 Subject: [PATCH 11/43] Remove extrinsic_builder from omni-node-lib --- cumulus/polkadot-omni-node/lib/src/command.rs | 26 ++------------- .../lib/src/common/command.rs | 33 ++----------------- 2 files changed, 4 insertions(+), 55 deletions(-) diff --git a/cumulus/polkadot-omni-node/lib/src/command.rs b/cumulus/polkadot-omni-node/lib/src/command.rs index fc00bc155df0c..3c5a86ed5166b 100644 --- a/cumulus/polkadot-omni-node/lib/src/command.rs +++ b/cumulus/polkadot-omni-node/lib/src/command.rs @@ -32,11 +32,10 @@ use crate::{ #[cfg(feature = "runtime-benchmarks")] use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; use cumulus_primitives_core::ParaId; -use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicBuilder, SUBSTRATE_REFERENCE_HARDWARE}; +use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; use log::info; use sc_cli::{Result, SubstrateCli}; use sp_runtime::traits::AccountIdConversion; -use sp_core::H256; #[cfg(feature = "runtime-benchmarks")] use sp_runtime::traits::HashingFor; @@ -47,19 +46,6 @@ pub struct RunConfig { pub chain_spec_loader: Box, /// A custom runtime resolver. pub runtime_resolver: Box, - /// Extrinsic builder to use in benchmarks. - /// - /// Some benchmarks attempt to build blocks. This extrinsic builder - /// is used to populate these blocks with extrinsics. - pub extrinsic_builder: Option< - Box< - dyn FnOnce( - subxt::Metadata, - H256, - subxt::client::RuntimeVersion, - ) -> Box, - >, - >, } impl RunConfig { @@ -68,7 +54,7 @@ impl RunConfig { runtime_resolver: Box, chain_spec_loader: Box, ) -> Self { - RunConfig { chain_spec_loader, runtime_resolver, extrinsic_builder: None } + RunConfig { chain_spec_loader, runtime_resolver } } } @@ -221,14 +207,6 @@ pub fn run(cmd_config: RunConfig) -> Result<() }), BenchmarkCmd::Machine(cmd) => runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())), - BenchmarkCmd::Overhead(cmd) => runner.sync_run(|config| { - let node = new_node_spec( - &config, - &cmd_config.runtime_resolver, - &cli.node_extra_args(), - )?; - node.run_benchmark_overhead_cmd(cmd, cmd_config.extrinsic_builder) - }), #[allow(unreachable_patterns)] _ => Err("Benchmarking sub-command unsupported or compilation feature missing. \ Make sure to compile with --features=runtime-benchmarks \ diff --git a/cumulus/polkadot-omni-node/lib/src/common/command.rs b/cumulus/polkadot-omni-node/lib/src/common/command.rs index 6ca8903d84b4e..a60fc9232d911 100644 --- a/cumulus/polkadot-omni-node/lib/src/common/command.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/command.rs @@ -14,14 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::common::spec::{BaseNodeSpec}; +use crate::common::spec::BaseNodeSpec; use cumulus_client_cli::ExportGenesisHeadCommand; +use frame_benchmarking_cli::BlockCmd; #[cfg(any(feature = "runtime-benchmarks"))] use frame_benchmarking_cli::StorageCmd; -use frame_benchmarking_cli::{BlockCmd, ExtrinsicBuilder, OverheadCmd}; use sc_cli::{CheckBlockCmd, ExportBlocksCmd, ExportStateCmd, ImportBlocksCmd, RevertCmd}; use sc_service::{Configuration, TaskManager}; -use sp_core::H256; use std::{future::Future, pin::Pin}; type SyncCmdResult = sc_cli::Result<()>; @@ -78,19 +77,6 @@ pub trait NodeCommandRunner { config: Configuration, cmd: &StorageCmd, ) -> SyncCmdResult; - - fn run_benchmark_overhead_cmd( - self: Box, - cmd: &OverheadCmd, - ext_builder: Option< - Box< - dyn FnOnce( - subxt::Metadata, - H256, - subxt::client::RuntimeVersion, - ) -> Box, - >> - ) -> SyncCmdResult; } impl NodeCommandRunner for T @@ -172,19 +158,4 @@ where cmd.run(config, partial.client, db, storage) } - - fn run_benchmark_overhead_cmd( - self: Box, - cmd: &OverheadCmd, - ext_builder: Option< - Box< - dyn FnOnce( - subxt::Metadata, - H256, - subxt::client::RuntimeVersion, - ) -> Box, - >> - ) -> SyncCmdResult { - cmd.run_with_extrinsic_builder::<::Block, ()>(ext_builder) - } } From 77c6bc3f41881d62f21201aef5e34a88d071dd9c Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 21 Oct 2024 14:26:59 +0200 Subject: [PATCH 12/43] Add simple binary test --- substrate/utils/frame/omni-bencher/Cargo.toml | 6 +++ .../omni-bencher/tests/benchmark_works.rs | 52 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 substrate/utils/frame/omni-bencher/tests/benchmark_works.rs diff --git a/substrate/utils/frame/omni-bencher/Cargo.toml b/substrate/utils/frame/omni-bencher/Cargo.toml index e2ffca8b47146..6cebbd570b627 100644 --- a/substrate/utils/frame/omni-bencher/Cargo.toml +++ b/substrate/utils/frame/omni-bencher/Cargo.toml @@ -20,3 +20,9 @@ sp-runtime = { workspace = true, default-features = true } sp-statement-store = { workspace = true, default-features = true } tracing-subscriber = { workspace = true } log = { workspace = true } + +[dev-dependencies] +tempfile = { workspace = true } +assert_cmd = { workspace = true } +cumulus-test-runtime = { workspace = true } +sp-tracing = { workspace = true, default-features = true } diff --git a/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs b/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs new file mode 100644 index 0000000000000..9814e3e7b0d70 --- /dev/null +++ b/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs @@ -0,0 +1,52 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::fs; +#[test] +fn benchmark_overhead_works() -> std::result::Result<(), String> { + let tmp_dir = tempfile::tempdir().expect("could not create a temp dir"); + let base_path = tmp_dir.path(); + let wasm = cumulus_test_runtime::WASM_BINARY.ok_or("WASM binary not available".to_string())?; + let runtime_path = base_path.join("runtime.wasm"); + let _ = + fs::write(&runtime_path, wasm).map_err(|e| format!("Unable to write runtime file: {}", e)); + + let path = assert_cmd::cargo::cargo_bin("frame-omni-bencher"); + // Invoke `benchmark overhead` with all options to make sure that they are valid. + let status = std::process::Command::new(path) + .args(["v1", "benchmark", "overhead", "--runtime", runtime_path.to_str().unwrap()]) + .arg("-d") + .arg(base_path) + .arg("--weight-path") + .arg(base_path) + .args(["--warmup", "5", "--repeat", "5"]) + .args(["--add", "100", "--mul", "1.2", "--metric", "p75"]) + // Only put 5 extrinsics into the block otherwise it takes forever to build it + // especially for a non-release builds. + .args(["--max-ext-per-block", "5"]) + .status() + .map_err(|e| format!("command failed: {:?}", e))?; + + if !status.success() { + return Err("Command failed".into()) + } + + // Weight files have been created. + assert!(base_path.join("block_weights.rs").exists()); + assert!(base_path.join("extrinsic_weights.rs").exists()); + Ok(()) +} From 6d2067cfab27bf6535ace934075fa6c71114d242 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 21 Oct 2024 18:28:22 +0200 Subject: [PATCH 13/43] Add test to metadata fetching --- Cargo.lock | 5 +++++ .../utils/frame/benchmarking-cli/Cargo.toml | 3 +++ .../src/overhead/remark_builders.rs | 20 +++++++++++++++++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce34762dbdded..10b2ba6bf3c7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6235,6 +6235,7 @@ dependencies = [ "comfy-table", "cumulus-client-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", + "cumulus-test-runtime", "frame-benchmarking", "frame-support", "frame-system", @@ -6417,13 +6418,17 @@ dependencies = [ name = "frame-omni-bencher" version = "0.1.0" dependencies = [ + "assert_cmd", "clap 4.5.13", "cumulus-primitives-proof-size-hostfunction", + "cumulus-test-runtime", "frame-benchmarking-cli", "log", "sc-cli", "sp-runtime 31.0.1", "sp-statement-store", + "sp-tracing 16.0.0", + "tempfile", "tracing-subscriber 0.3.18", ] diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 900eb4b86c3b8..2186a00a848e4 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -71,6 +71,9 @@ polkadot-primitives = { workspace = true, default-features = true } gethostname = { workspace = true } hex = "0.4.3" +[dev-dependencies] +cumulus-test-runtime = { workspace = true, default-features = true } + [features] default = ["rocksdb"] runtime-benchmarks = [ diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs index 834d4123aae3c..e98e430db08a7 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs @@ -129,8 +129,8 @@ impl ExtrinsicBuilder for DynamicRemarkBuilder { struct BasicCodeFetcher<'a>(Cow<'a, [u8]>); impl<'a> FetchRuntimeCode for BasicCodeFetcher<'a> { - fn fetch_runtime_code(&self) -> Option> { - Some(self.0.clone()) + fn fetch_runtime_code(&self) -> Option> { + Some(self.0.as_ref().into()) } } impl<'a> BasicCodeFetcher<'a> { @@ -195,3 +195,19 @@ pub fn fetch_latest_metadata_from_blob( Ok(subxt::Metadata::decode(&mut (*opaque_metadata).as_slice())?) } + +#[cfg(test)] +mod tests { + use crate::overhead::cmd::ParachainHostFunctions; + use sc_executor::WasmExecutor; + + #[test] + fn test_fetch_latest_metadata_from_blob_fetches_metadata() { + let executor: WasmExecutor = WasmExecutor::builder().build(); + let code_bytes = cumulus_test_runtime::WASM_BINARY + .expect("To run this test, build the wasm binary of cumulus-test-runtime") + .to_vec(); + let metadata = super::fetch_latest_metadata_from_blob(&executor, &code_bytes).unwrap(); + assert!(metadata.pallet_by_name("ParachainInfo").is_some()); + } +} From 88d3b69e435c5027282bc45d78253f32d42b819a Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 21 Oct 2024 19:38:42 +0200 Subject: [PATCH 14/43] Clean up metadata fetching --- Cargo.lock | 1 + .../utils/frame/benchmarking-cli/Cargo.toml | 1 + .../utils/frame/benchmarking-cli/src/lib.rs | 2 +- .../benchmarking-cli/src/overhead/cmd.rs | 3 +- .../benchmarking-cli/src/overhead/mod.rs | 2 +- ...emark_builders.rs => runtime_utilities.rs} | 159 ++++++++++++------ .../src/shared/genesis_state.rs | 1 + 7 files changed, 111 insertions(+), 58 deletions(-) rename substrate/utils/frame/benchmarking-cli/src/overhead/{remark_builders.rs => runtime_utilities.rs} (61%) diff --git a/Cargo.lock b/Cargo.lock index 10b2ba6bf3c7e..e79d1638cf78f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6256,6 +6256,7 @@ dependencies = [ "sc-client-api", "sc-client-db", "sc-executor 0.32.0", + "sc-executor-common 0.29.0", "sc-service", "sc-sysinfo", "serde", diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 2186a00a848e4..14c7506ea991e 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -41,6 +41,7 @@ sc-cli = { workspace = true } sc-client-api = { workspace = true, default-features = true } sc-client-db = { workspace = true } sc-executor = { workspace = true, default-features = true } +sc-executor-common = { workspace = true } sc-service = { workspace = true } sc-sysinfo = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } diff --git a/substrate/utils/frame/benchmarking-cli/src/lib.rs b/substrate/utils/frame/benchmarking-cli/src/lib.rs index 8acbb03e726af..f1fc37214b7fe 100644 --- a/substrate/utils/frame/benchmarking-cli/src/lib.rs +++ b/substrate/utils/frame/benchmarking-cli/src/lib.rs @@ -29,7 +29,7 @@ pub use block::BlockCmd; pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; pub use machine::{MachineCmd, SUBSTRATE_REFERENCE_HARDWARE}; pub use overhead::{ - remark_builders::{ + runtime_utilities::{ fetch_latest_metadata_from_blob, DynamicRemarkBuilder, SubstrateRemarkBuilder, }, OpaqueBlock, OverheadCmd, diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 5ae62d83b5521..3d3b7904103ea 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -18,7 +18,7 @@ //! Contains the [`OverheadCmd`] as entry point for the CLI to execute //! the *overhead* benchmarks. -use super::remark_builders::*; +use super::runtime_utilities::*; use crate::{ extrinsic::{ bench::{Benchmark, BenchmarkParams as ExtrinsicBenchmarkParams}, @@ -243,6 +243,7 @@ impl OverheadCmd { Ok(chain_type) } + fn chain_spec_from_path( &self, ) -> Result<(Option>, Option)> { diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs index 1d8a78dc5bfbb..74f56c6437855 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs @@ -20,4 +20,4 @@ pub mod template; pub use cmd::{OpaqueBlock, OverheadCmd}; mod fake_runtime_api; -pub mod remark_builders; +pub mod runtime_utilities; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs similarity index 61% rename from substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs rename to substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs index e98e430db08a7..bfc2546706235 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builders.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs @@ -19,7 +19,7 @@ use crate::extrinsic::ExtrinsicBuilder; use codec::{Decode, Encode}; use sc_client_api::UsageProvider; use sc_executor::WasmExecutor; -use sp_api::{Core, Metadata, ProvideRuntimeApi}; +use sp_api::{ApiExt, Core, Metadata, ProvideRuntimeApi}; use sp_core::{ traits::{CallContext, CodeExecutor, FetchRuntimeCode, RuntimeCode}, OpaqueMetadata, @@ -35,11 +35,17 @@ use subxt::{ pub type SubstrateRemarkBuilder = DynamicRemarkBuilder; +/// Remark builder that can be used to build simple extrinsics for +/// FRAME-based runtimes. pub struct DynamicRemarkBuilder { offline_client: OfflineClient, } impl> DynamicRemarkBuilder { + /// Initializes a new remark builder from a client. + /// + /// This will first fetch metadata and runtime version from the runtime and then + /// construct an offline client that provides the extrinsics. pub fn new_from_client(client: Arc) -> sc_cli::Result where Block: BlockT, @@ -48,7 +54,16 @@ impl> DynamicRemarkBuilder { { let genesis = client.usage_info().chain.best_hash; let api = client.runtime_api(); - if let Ok(mut supported_metadata_versions) = api.metadata_versions(genesis) { + + let Ok(Some(metadata_api_version)) = api.api_version::>(genesis) else { + return Err("Unable to fetch metadata runtime API version.".to_string().into()); + }; + + if metadata_api_version > 1 { + let Ok(mut supported_metadata_versions) = api.metadata_versions(genesis) else { + return Err("Unable to fetch metadata versions".to_string().into()); + }; + let latest = supported_metadata_versions .pop() .ok_or("No metadata version supported".to_string())?; @@ -60,6 +75,7 @@ impl> DynamicRemarkBuilder { spec_version: version.spec_version, transaction_version: version.transaction_version, }; + let metadata = api .metadata_at_version(genesis, latest) .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? @@ -68,12 +84,15 @@ impl> DynamicRemarkBuilder { let metadata = subxt::Metadata::decode(&mut (*metadata).as_slice())?; let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); + return Ok(Self { offline_client: OfflineClient::new(genesis, runtime_version, metadata), }) } - log::warn!("No metadata versions found, falling back to deprecated metadata runtime api."); + log::debug!("Found metadata version {}.", metadata_api_version); + + // Fall back to using the non-versioned metadata API. let metadata = api .metadata(genesis) .map_err(|e| format!("Unable to fetch metadata: {:?}", e))?; @@ -91,6 +110,7 @@ impl> DynamicRemarkBuilder { } impl DynamicRemarkBuilder { + /// Constructs a new remark builder. pub fn new( metadata: subxt::Metadata, genesis_hash: C::Hash, @@ -127,79 +147,94 @@ impl ExtrinsicBuilder for DynamicRemarkBuilder { } } -struct BasicCodeFetcher<'a>(Cow<'a, [u8]>); +/// Fetches the latest metadata from the given runtime blob. +pub fn fetch_latest_metadata_from_blob( + executor: &WasmExecutor, + code_bytes: &Vec, +) -> sc_cli::Result { + let runtime_caller = RuntimeCaller::new(executor, code_bytes.into()); + let version_result = runtime_caller.call("Metadata_metadata_versions", ()); + + let opaque_metadata: OpaqueMetadata = match version_result { + Ok(supported_versions) => { + let latest_version = Vec::::decode(&mut supported_versions.as_slice()) + .map_err(|e| format!("Unable to decode version list: {e}"))? + .pop() + .ok_or("No metadata versions supported".to_string())?; + + let encoded = runtime_caller + .call("Metadata_metadata_at_version", latest_version) + .map_err(|_| "Unable to fetch metadata from blob".to_string())?; + Option::::decode(&mut encoded.as_slice())? + .ok_or_else(|| "Metadata not found".to_string())? + }, + Err(_) => { + let encoded = runtime_caller + .call("Metadata_metadata", ()) + .map_err(|_| "Unable to fetch metadata from blob".to_string())?; + Decode::decode(&mut encoded.as_slice())? + }, + }; + + Ok(subxt::Metadata::decode(&mut (*opaque_metadata).as_slice())?) +} + +struct BasicCodeFetcher<'a> { + code: Cow<'a, [u8]>, + hash: Vec, +} + impl<'a> FetchRuntimeCode for BasicCodeFetcher<'a> { fn fetch_runtime_code(&self) -> Option> { - Some(self.0.as_ref().into()) + Some(self.code.as_ref().into()) } } + impl<'a> BasicCodeFetcher<'a> { + pub fn new(code: Cow<'a, [u8]>) -> Self { + Self { hash: sp_crypto_hashing::blake2_256(&code).to_vec(), code } + } + pub fn runtime_code(&'a self) -> RuntimeCode<'a> { RuntimeCode { code_fetcher: self as &'a dyn FetchRuntimeCode, heap_pages: None, - hash: sp_crypto_hashing::blake2_256(&self.0).to_vec(), + hash: self.hash.clone(), } } } -pub fn fetch_latest_metadata_from_blob( - executor: &WasmExecutor, - code_bytes: &Vec, -) -> sc_cli::Result { - let mut ext = BasicExternalities::default(); - let fetcher = BasicCodeFetcher(code_bytes.into()); - let version_result = executor - .call( - &mut ext, - &fetcher.runtime_code(), - "Metadata_metadata_versions", - &[], - CallContext::Offchain, - ) - .0; +/// Simple utility that is used to call into the runtime. +struct RuntimeCaller<'a, 'b, HF: HostFunctions> { + executor: &'b WasmExecutor, + code_fetcher: BasicCodeFetcher<'a>, +} - let opaque_metadata: OpaqueMetadata = match version_result { - Ok(supported_versions) => { - let versions = Vec::::decode(&mut supported_versions.as_slice()) - .map_err(|e| format!("Error {e}"))?; - let version_to_use = versions.last().ok_or("No versions available.")?; - let parameters = (*version_to_use).encode(); - let encoded = executor - .call( - &mut ext, - &fetcher.runtime_code(), - "Metadata_metadata_at_version", - ¶meters, - CallContext::Offchain, - ) - .0 - .map_err(|e| format!("Unable to fetch metadata from blob: {e}"))?; - let opaque: Option = Decode::decode(&mut encoded.as_slice())?; - opaque.ok_or_else(|| "Metadata not found".to_string())? - }, - Err(_) => { - let encoded = executor - .call( - &mut ext, - &fetcher.runtime_code(), - "Metadata_metadata", - &[], - CallContext::Offchain, - ) - .0 - .map_err(|e| format!("Unable to fetch metadata from blob: {e}"))?; - Decode::decode(&mut encoded.as_slice())? - }, - }; +impl<'a, 'b, HF: HostFunctions> RuntimeCaller<'a, 'b, HF> { + pub fn new(executor: &'b WasmExecutor, code_bytes: Cow<'a, [u8]>) -> Self { + Self { executor, code_fetcher: BasicCodeFetcher::new(code_bytes) } + } - Ok(subxt::Metadata::decode(&mut (*opaque_metadata).as_slice())?) + fn call(&self, method: &str, data: impl Encode) -> sc_executor_common::error::Result> { + let mut ext = BasicExternalities::default(); + self.executor + .call( + &mut ext, + &self.code_fetcher.runtime_code(), + method, + &data.encode(), + CallContext::Offchain, + ) + .0 + } } #[cfg(test)] mod tests { use crate::overhead::cmd::ParachainHostFunctions; + use codec::Decode; use sc_executor::WasmExecutor; + use sp_version::RuntimeVersion; #[test] fn test_fetch_latest_metadata_from_blob_fetches_metadata() { @@ -210,4 +245,18 @@ mod tests { let metadata = super::fetch_latest_metadata_from_blob(&executor, &code_bytes).unwrap(); assert!(metadata.pallet_by_name("ParachainInfo").is_some()); } + + #[test] + fn test_runtime_caller_can_call_into_runtime() { + let executor: WasmExecutor = WasmExecutor::builder().build(); + let code_bytes = cumulus_test_runtime::WASM_BINARY + .expect("To run this test, build the wasm binary of cumulus-test-runtime") + .to_vec(); + let runtime_caller = super::RuntimeCaller::new(&executor, code_bytes.into()); + let runtime_version = runtime_caller + .call("Core_version", ()) + .expect("Should be able to call runtime_version"); + let runtime_version: RuntimeVersion = Decode::decode(&mut runtime_version.as_slice()) + .expect("Should be able to decode runtime version"); + } } diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs index 33a4ec373a6c0..1975bd189504b 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -21,6 +21,7 @@ use std::{fs, path::PathBuf}; // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + /// Build the genesis storage by either the Genesis Builder API, chain spec or nothing. /// /// Behaviour can be controlled by the `genesis_builder` parameter. From 9b1886d10d9f8f66f39168213af17be3dc230aeb Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 22 Oct 2024 09:30:18 +0200 Subject: [PATCH 15/43] Add some more tests --- Cargo.lock | 1 + .../utils/frame/benchmarking-cli/Cargo.toml | 1 + .../benchmarking-cli/src/extrinsic/bench.rs | 2 +- .../benchmarking-cli/src/overhead/cmd.rs | 89 +++++++++++++------ 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e79d1638cf78f..4b54b64cabca4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6280,6 +6280,7 @@ dependencies = [ "sp-trie 29.0.0", "sp-version 29.0.0", "sp-wasm-interface 20.0.0", + "substrate-test-runtime", "subxt", "subxt-signer", "thiserror", diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 14c7506ea991e..c6fec14ffa6a4 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -74,6 +74,7 @@ hex = "0.4.3" [dev-dependencies] cumulus-test-runtime = { workspace = true, default-features = true } +substrate-test-runtime = { workspace = true, default-features = true } [features] default = ["rocksdb"] diff --git a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index dcd8d1530aef1..7b8130edaa4f6 100644 --- a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -140,7 +140,7 @@ where .on_parent_block(chain.best_hash) .with_parent_block_number(chain.best_number) .with_inherent_digests(Digest { logs: self.digest_items.clone() }) - .enable_proof_recording() + .with_proof_recording(self.record_proof) .build()?; // Create and insert the inherents. diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 3d3b7904103ea..7fe03a25aa9fb 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -121,9 +121,10 @@ pub struct OverheadParams { /// How to construct the genesis state. /// - /// Uses `GenesisBuilderPolicy::Spec` by default and `GenesisBuilderPolicy::Runtime` if - /// `runtime` is set. - #[arg(long, value_enum)] + /// Can be used together with `--chain` to determine whether the + /// genesis state should be initialized with the values from the + /// provided chain spec or a runtime-provided genesis preset. + #[arg(long, value_enum, conflicts_with = "runtime")] pub genesis_builder: Option, /// Inflate the genesis state by generating accounts. @@ -214,6 +215,32 @@ fn create_inherent_data + HeaderBackend, Blo inherent_data } +/// Identifies what kind of chain we are dealing with. +/// +/// Chains containing the `ParachainSystem` and `ParachainInfo` pallet are considered parachains. +/// Chains containing the `ParaInherent` pallet are considered relay chains. +fn identify_chain(metadata: &Metadata, para_id: Option) -> ChainType { + let parachain_info_exists = metadata.pallet_by_name("ParachainInfo").is_some(); + let parachain_system_exists = metadata.pallet_by_name("ParachainSystem").is_some(); + let para_inherent_exists = metadata.pallet_by_name("ParaInherent").is_some(); + + log::debug!("{} ParachainSystem", if parachain_system_exists { "✅" } else { "❌" }); + log::debug!("{} ParachainInfo", if parachain_info_exists { "✅" } else { "❌" }); + log::debug!("{} ParaInherent", if para_inherent_exists { "✅" } else { "❌" }); + + let chain_type = if parachain_system_exists && parachain_info_exists { + Parachain(para_id.unwrap_or(DEFAULT_PARA_ID)) + } else if para_inherent_exists { + Relaychain + } else { + Unknown + }; + + log::info!("Identified Chain type from metadata: {}", chain_type); + + chain_type +} + #[derive(Deserialize, Serialize, Clone, ChainSpecExtension)] pub struct ParachainExtension { /// The id of the Parachain. @@ -221,29 +248,6 @@ pub struct ParachainExtension { } impl OverheadCmd { - /// Make an educated guess what kind of chain we are dealing with. - fn identify_chain(&self, metadata: &Metadata, para_id: Option) -> Result { - let parachain_info_exists = metadata.pallet_by_name("ParachainInfo").is_some(); - let parachain_system_exists = metadata.pallet_by_name("ParachainSystem").is_some(); - let para_inherent_exists = metadata.pallet_by_name("ParaInherent").is_some(); - - log::debug!("{} ParachainSystem", if parachain_system_exists { "✅" } else { "❌" }); - log::debug!("{} ParachainInfo", if parachain_info_exists { "✅" } else { "❌" }); - log::debug!("{} ParaInherent", if para_inherent_exists { "✅" } else { "❌" }); - - let chain_type = if parachain_system_exists && parachain_info_exists { - Parachain(para_id.or(self.params.para_id).unwrap_or(DEFAULT_PARA_ID)) - } else if para_inherent_exists { - Relaychain - } else { - Unknown - }; - - log::info!("Identified Chain type from metadata: {}", chain_type); - - Ok(chain_type) - } - fn chain_spec_from_path( &self, ) -> Result<(Option>, Option)> { @@ -286,7 +290,7 @@ impl OverheadCmd { .build(); let metadata = fetch_latest_metadata_from_blob(&executor, &code_bytes)?; - let chain_type = self.identify_chain(&metadata, para_id_from_chain_spec)?; + let chain_type = identify_chain(&metadata, para_id_from_chain_spec.or(self.params.para_id)); let client = self.build_client_components::( chain_spec, @@ -492,7 +496,7 @@ impl BenchmarkType { } } -#[derive(Clone)] +#[derive(Clone, PartialEq, Debug)] enum ChainType { Parachain(u32), Relaychain, @@ -541,3 +545,32 @@ impl CliConfiguration for OverheadCmd { Ok(Some(BasePath::new_temp_dir()?)) } } + +#[cfg(test)] +mod tests { + use crate::overhead::cmd::{ + identify_chain, ChainType, ParachainHostFunctions, DEFAULT_PARA_ID, + }; + use sc_executor::WasmExecutor; + + #[test] + fn test_chain_type_parachain() { + let executor: WasmExecutor = WasmExecutor::builder().build(); + let code_bytes = cumulus_test_runtime::WASM_BINARY + .expect("To run this test, build the wasm binary of cumulus-test-runtime") + .to_vec(); + let metadata = super::fetch_latest_metadata_from_blob(&executor, &code_bytes).unwrap(); + assert_eq!(identify_chain(&metadata, Some(100)), ChainType::Parachain(100)); + assert_eq!(identify_chain(&metadata, None), ChainType::Parachain(DEFAULT_PARA_ID)); + } + + #[test] + fn test_chain_type_custom() { + let executor: WasmExecutor = WasmExecutor::builder().build(); + let code_bytes = substrate_test_runtime::WASM_BINARY + .expect("To run this test, build the wasm binary of cumulus-test-runtime") + .to_vec(); + let metadata = super::fetch_latest_metadata_from_blob(&executor, &code_bytes).unwrap(); + assert_eq!(identify_chain(&metadata, Some(100)), ChainType::Unknown); + } +} From 8188eb910e2678a48c19ed7dc6d712a93b6ab718 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 22 Oct 2024 13:44:06 +0200 Subject: [PATCH 16/43] Use correct proof size --- substrate/client/block-builder/src/lib.rs | 8 +++++++ .../benchmarking-cli/src/extrinsic/bench.rs | 22 +++++++++++++++---- .../benchmarking-cli/src/overhead/cmd.rs | 16 ++++---------- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/substrate/client/block-builder/src/lib.rs b/substrate/client/block-builder/src/lib.rs index d02d0e3218051..f65a7dbd5f549 100644 --- a/substrate/client/block-builder/src/lib.rs +++ b/substrate/client/block-builder/src/lib.rs @@ -357,6 +357,14 @@ where .map_err(|e| Error::Application(Box::new(e))) } + /// Get the current proof size of the internal recorder. + /// + /// This is a lot more expensive than the provided size estimation functions and should + /// be used with care. + pub fn current_proof_size(&self) -> Option { + self.api.proof_recorder().map(|pr| pr.to_storage_proof().encoded_size()) + } + /// Estimate the size of the block in the current state. /// /// If `include_proof` is `true`, the estimated size of the storage proof will be added diff --git a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index 7b8130edaa4f6..c4870f9bb7ea1 100644 --- a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -153,8 +153,15 @@ where let ext_builder = if let Some(ext_builder) = ext_builder { ext_builder } else { - let proof_size = builder.estimate_block_size(true) - builder.estimate_block_size(false); - return Ok((builder.build()?.block, None, proof_size as u64)) + let proof_size = builder.current_proof_size(); + return Ok(( + builder.build()?.block, + None, + proof_size + .unwrap_or(0) + .try_into() + .map_err(|_| "Proof size is too large".to_string())?, + )) }; // Put as many extrinsics into the block as possible and count them. @@ -175,10 +182,17 @@ where return Err("A Block must hold at least one extrinsic".into()) } info!("Extrinsics per block: {}", num_ext); - let proof_size = builder.estimate_block_size(true) - builder.estimate_block_size(false); + let proof_size = builder.current_proof_size(); let block = builder.build()?.block; - Ok((block, Some(num_ext), proof_size as u64)) + Ok(( + block, + Some(num_ext), + proof_size + .unwrap_or(0) + .try_into() + .map_err(|_| "Proof size is too large".to_string())?, + )) } /// Measures the time that it take to execute a block or an extrinsic. diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 7fe03a25aa9fb..6001aca1f3f5c 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -42,7 +42,7 @@ use sc_block_builder::BlockBuilderApi; use sc_chain_spec::{ChainSpec, ChainSpecExtension, GenericChainSpec, GenesisBlockBuilder}; use sc_cli::{CliConfiguration, Database, ImportParams, Result, SharedParams}; use sc_client_api::{execution_extensions::ExecutionExtensions, UsageProvider}; -use sc_client_db::{BlocksPruning, DatabaseSettings, DatabaseSource}; +use sc_client_db::{BlocksPruning, DatabaseSettings}; use sc_executor::WasmExecutor; use sc_service::{new_client, new_db_backend, BasePath, ClientConfig, TFullClient, TaskManager}; use serde::Serialize; @@ -127,12 +127,6 @@ pub struct OverheadParams { #[arg(long, value_enum, conflicts_with = "runtime")] pub genesis_builder: Option, - /// Inflate the genesis state by generating accounts. - /// - /// Can be used together with `--account_type` to specify the type of accounts to generate. - #[arg(long)] - pub generate_num_accounts: Option, - /// Parachain Id to use for parachains. If not specified, the benchmark code will choose /// a para-id and patch the state accordingly. #[arg(long)] @@ -357,19 +351,17 @@ impl OverheadCmd { Some(path) => BasePath::from(path.clone()), }; - self.database_config( + let database_source = self.database_config( &base_path.path().to_path_buf(), self.database_cache_size()?.unwrap_or(1024), self.database()?.unwrap_or(Database::RocksDb), )?; + let backend = new_db_backend(DatabaseSettings { trie_cache_maximum_size: self.trie_cache_maximum_size()?, state_pruning: None, blocks_pruning: BlocksPruning::KeepAll, - source: DatabaseSource::RocksDb { - cache_size: self.database_cache_size()?.unwrap_or(1024), - path: BasePath::new_temp_dir()?.path().into(), - }, + source: database_source, })?; let storage = shared::genesis_state::genesis_storage::( From 170235e09729b5a7313fbda1e0d2063f6ae55507 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 22 Oct 2024 17:34:49 +0200 Subject: [PATCH 17/43] Fmt --- cumulus/polkadot-parachain/src/main.rs | 5 ++- .../test/service/benches/validate_block.rs | 5 ++- .../benchmarking-cli/src/pallet/command.rs | 37 +++++++++---------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/cumulus/polkadot-parachain/src/main.rs b/cumulus/polkadot-parachain/src/main.rs index 0d742e1c421d9..61764636a0600 100644 --- a/cumulus/polkadot-parachain/src/main.rs +++ b/cumulus/polkadot-parachain/src/main.rs @@ -46,6 +46,9 @@ impl CliConfigT for CliConfig { fn main() -> color_eyre::eyre::Result<()> { color_eyre::install()?; - let config = RunConfig::new(Box::new(chain_spec::RuntimeResolver), Box::new(chain_spec::ChainSpecLoader)); + let config = RunConfig::new( + Box::new(chain_spec::RuntimeResolver), + Box::new(chain_spec::ChainSpecLoader), + ); Ok(run::(config)?) } diff --git a/cumulus/test/service/benches/validate_block.rs b/cumulus/test/service/benches/validate_block.rs index 6ed8c305bb3cc..ca20de338f3c1 100644 --- a/cumulus/test/service/benches/validate_block.rs +++ b/cumulus/test/service/benches/validate_block.rs @@ -60,7 +60,10 @@ fn create_extrinsics( let extrinsic: UncheckedExtrinsic = generate_extrinsic_with_pair( client, src.clone(), - BalancesCall::transfer_keep_alive { dest: AccountId::from(dst.public()).into(), value: 10000 }, + BalancesCall::transfer_keep_alive { + dest: AccountId::from(dst.public()).into(), + value: 10000, + }, None, ); diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index c1476fd06bcf1..32b4ea5336e8b 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -59,11 +59,8 @@ use std::{ /// Logging target const LOG_TARGET: &'static str = "polkadot_sdk_frame::benchmark::pallet"; -type SubstrateAndExtraHF = ( - sp_io::SubstrateHostFunctions, - frame_benchmarking::benchmarking::HostFunctions, - T, -); +type SubstrateAndExtraHF = + (sp_io::SubstrateHostFunctions, frame_benchmarking::benchmarking::HostFunctions, T); /// How the PoV size of a storage item should be estimated. #[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy)] pub enum PovEstimationMode { @@ -211,7 +208,7 @@ impl PalletCmd { &self.runtime, Some(&code_bytes), &self.genesis_builder_preset, - &chain_spec + &chain_spec, )?; let cache_size = Some(self.database_cache_size as usize); @@ -242,13 +239,13 @@ impl PalletCmd { let alloc_strategy = self.alloc_strategy(runtime_code.heap_pages); let executor = WasmExecutor::>::builder() - .with_execution_method(method) - .with_allow_missing_host_functions(self.allow_missing_host_functions) - .with_onchain_heap_alloc_strategy(alloc_strategy) - .with_offchain_heap_alloc_strategy(alloc_strategy) - .with_max_runtime_instances(2) - .with_runtime_cache_size(2) - .build(); + .with_execution_method(method) + .with_allow_missing_host_functions(self.allow_missing_host_functions) + .with_onchain_heap_alloc_strategy(alloc_strategy) + .with_offchain_heap_alloc_strategy(alloc_strategy) + .with_max_runtime_instances(2) + .with_runtime_cache_size(2) + .build(); let (list, storage_info): (Vec, Vec) = Self::exec_state_machine( @@ -551,15 +548,15 @@ impl PalletCmd { Ok(benchmarks_to_run) } - /// Whether this pallet should be run. - fn pallet_selected(&self, pallet: &Vec) -> bool { - let include = self.pallet.clone().unwrap_or_default(); + /// Whether this pallet should be run. + fn pallet_selected(&self, pallet: &Vec) -> bool { + let include = self.pallet.clone().unwrap_or_default(); - let included = include.is_empty() || include == "*" || include.as_bytes() == pallet; - let excluded = self.exclude_pallets.iter().any(|p| p.as_bytes() == pallet); + let included = include.is_empty() || include == "*" || include.as_bytes() == pallet; + let excluded = self.exclude_pallets.iter().any(|p| p.as_bytes() == pallet); - included && !excluded - } + included && !excluded + } /// Execute a state machine and decode its return value as `R`. fn exec_state_machine( From 878c1569b4288b3fdc54d8119c6b2815df5b96fe Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 23 Oct 2024 11:38:11 +0200 Subject: [PATCH 18/43] Apply suggestions from code review Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> --- cumulus/test/runtime/src/genesis_config_presets.rs | 2 +- cumulus/test/service/src/chain_spec.rs | 2 +- substrate/client/chain-spec/src/genesis_block.rs | 1 + substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs | 4 ++-- .../utils/frame/benchmarking-cli/src/overhead/weights.hbs | 2 +- substrate/utils/frame/benchmarking-cli/src/shared/mod.rs | 2 +- substrate/utils/frame/omni-bencher/src/command.rs | 1 - 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cumulus/test/runtime/src/genesis_config_presets.rs b/cumulus/test/runtime/src/genesis_config_presets.rs index 327e8437f258d..0a39fab1c06d1 100644 --- a/cumulus/test/runtime/src/genesis_config_presets.rs +++ b/cumulus/test/runtime/src/genesis_config_presets.rs @@ -50,7 +50,7 @@ fn cumulus_test_runtime( serde_json::to_value(config).expect("Could not build genesis config.") } -pub fn testnet_genesis_with_default_endowed(self_para_id: ParaId) -> serde_json::Value { +fn testnet_genesis_with_default_endowed(self_para_id: ParaId) -> serde_json::Value { let endowed = Sr25519Keyring::iter().map(|x| x.to_account_id()).collect::>(); let invulnerables = vec![ diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index b55c8a025c4ca..23d4310ce27c9 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -82,7 +82,7 @@ pub fn get_chain_spec_with_extra_endowed( .with_name("Local Testnet") .with_id(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) .with_chain_type(ChainType::Local) - .with_genesis_config(development_preset) + .with_genesis_patch(development_preset) .build() } diff --git a/substrate/client/chain-spec/src/genesis_block.rs b/substrate/client/chain-spec/src/genesis_block.rs index d41211cd6206d..3c5bf47c3fe8b 100644 --- a/substrate/client/chain-spec/src/genesis_block.rs +++ b/substrate/client/chain-spec/src/genesis_block.rs @@ -111,6 +111,7 @@ impl, E: RuntimeVersionOf> GenesisBlockBuilder< Self::new_with_storage(genesis_storage, commit_genesis_state, backend, executor) } + /// Constructs a new instance of [`GenesisBlockBuilder`] using provided storage. pub fn new_with_storage( genesis_storage: Storage, commit_genesis_state: bool, diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 6001aca1f3f5c..7a56d66024e89 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -154,7 +154,7 @@ pub type ParachainHostFunctions = ( pub type BlockNumber = u32; -/// Typical block type using `OpaqueExtrinsic`. +/// Typical block header.`. pub type Header = generic::Header; /// Typical block type using `OpaqueExtrinsic`. @@ -273,7 +273,7 @@ impl OverheadCmd { ExtraHF: HostFunctions, { let (chain_spec, para_id_from_chain_spec) = match chain_spec { - spec @ Some(_) => (spec, None), + Some(_) => (chain_spec, None), None => self.chain_spec_from_path::<(ParachainHostFunctions, ExtraHF)>()?, }; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/substrate/utils/frame/benchmarking-cli/src/overhead/weights.hbs index 8c48baaf79c0f..1596bb57a41a1 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -18,7 +18,7 @@ use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; parameter_types! { {{#if (eq short_name "block")}} - /// Weight fo executing an empty block. + /// Weight of executing an empty block. {{else}} /// Weight of executing a NO-OP extrinsic, for example `System::remark`. {{/if}} diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs b/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs index d727e89c3dc94..961cf2cd5398e 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs @@ -134,7 +134,7 @@ impl HostInfoParams { } } -/// How the genesis state for benchmarking should be build. +/// How the genesis state for benchmarking should be built. #[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy, Serialize)] #[clap(rename_all = "kebab-case")] pub enum GenesisBuilderPolicy { diff --git a/substrate/utils/frame/omni-bencher/src/command.rs b/substrate/utils/frame/omni-bencher/src/command.rs index 51fd79668b0d7..efabadc1ecc0e 100644 --- a/substrate/utils/frame/omni-bencher/src/command.rs +++ b/substrate/utils/frame/omni-bencher/src/command.rs @@ -129,7 +129,6 @@ impl Command { } } } -// impl V1SubCommand { pub fn run(self) -> Result<()> { match self { From e3deba75f0d60d0f9c385b2c975227f52a15ce55 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 23 Oct 2024 16:53:57 +0200 Subject: [PATCH 19/43] Reintroduce genesis state patching --- .../runtime/src/genesis_config_presets.rs | 3 +++ .../benchmarking-cli/src/overhead/cmd.rs | 26 +++++++++++++++++++ .../benchmarking-cli/src/pallet/command.rs | 1 + .../src/shared/genesis_state.rs | 12 ++++++--- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/cumulus/test/runtime/src/genesis_config_presets.rs b/cumulus/test/runtime/src/genesis_config_presets.rs index 0a39fab1c06d1..66d8c50d3496f 100644 --- a/cumulus/test/runtime/src/genesis_config_presets.rs +++ b/cumulus/test/runtime/src/genesis_config_presets.rs @@ -67,12 +67,15 @@ fn testnet_genesis_with_default_endowed(self_para_id: ParaId) -> serde_json::Val cumulus_test_runtime(invulnerables, endowed, self_para_id) } +/// List of supported presets. pub fn preset_names() -> Vec { vec![ PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET), PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET), ] } + +/// Provides the JSON representation of predefined genesis config for given `id`. pub fn get_preset(id: &PresetId) -> Option> { let patch = match id.try_into() { Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) | diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 7a56d66024e89..73e2968eaa7dc 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -46,6 +46,7 @@ use sc_client_db::{BlocksPruning, DatabaseSettings}; use sc_executor::WasmExecutor; use sc_service::{new_client, new_db_backend, BasePath, ClientConfig, TFullClient, TaskManager}; use serde::Serialize; +use serde_json::{json, Value}; use sp_api::{ApiExt, CallApiAt, Core, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::H256; @@ -209,6 +210,27 @@ fn create_inherent_data + HeaderBackend, Blo inherent_data } +/// Patch the parachain id into the genesis config. This is necessary since the inherents +/// also contain a parachain id and they need to match. +fn patch_genesis(mut input_value: Value, chain_type: ChainType) -> Value { + // If we identified a parachain we should patch a parachain id into the genesis config. + // This ensures compatibility with the inherents that we provide to successfully build a + // block. + if let Parachain(para_id) = chain_type { + sc_chain_spec::json_patch::merge( + &mut input_value, + json!({ + "parachainInfo": { + "parachainId": para_id, + } + }), + ); + log::debug!("Genesis Config Json"); + log::debug!("{}", input_value); + } + input_value +} + /// Identifies what kind of chain we are dealing with. /// /// Chains containing the `ParachainSystem` and `ParachainInfo` pallet are considered parachains. @@ -370,6 +392,10 @@ impl OverheadCmd { Some(&code_bytes), &self.params.genesis_builder_preset, &chain_spec, + { + let chain_type = chain_type.clone(); + Some(Box::new(move |value| patch_genesis(value, chain_type))) + }, )?; let genesis_block_builder = GenesisBlockBuilder::new_with_storage( diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index 32b4ea5336e8b..016a624102b8b 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -209,6 +209,7 @@ impl PalletCmd { Some(&code_bytes), &self.genesis_builder_preset, &chain_spec, + None, )?; let cache_size = Some(self.database_cache_size as usize); diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs index 1975bd189504b..fce14b70900db 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -6,6 +6,7 @@ use crate::shared::GenesisBuilderPolicy; use sc_chain_spec::{ChainSpec, GenesisConfigBuilderRuntimeCaller}; use sc_cli::Result; +use serde_json::Value; use sp_storage::{well_known_keys::CODE, Storage}; use sp_wasm_interface::HostFunctions; use std::{fs, path::PathBuf}; @@ -64,6 +65,7 @@ pub fn genesis_storage( code_bytes: Option<&Vec>, genesis_builder_preset: &String, chain_spec: &Option>, + storage_patcher: Option Value + 'static>>, ) -> Result { Ok(match (genesis_builder, runtime) { (Some(GenesisBuilderPolicy::None), Some(_)) => return Err("Cannot use `--genesis-builder=none` with `--runtime` since the runtime would be ignored.".into()), @@ -89,7 +91,7 @@ pub fn genesis_storage( return Err("Can not build genesis from runtime. Please provide a runtime.".into()); }; - genesis_from_code::(code.as_slice(), genesis_builder_preset)? + genesis_from_code::(code.as_slice(), genesis_builder_preset, storage_patcher)? }, (Some(GenesisBuilderPolicy::Runtime), None) => return Err("Cannot use `--genesis-builder=runtime` without `--runtime`".into()), (Some(GenesisBuilderPolicy::Runtime), Some(_)) | (None, Some(_)) => { @@ -97,7 +99,7 @@ pub fn genesis_storage( return Err("Can not build genesis from runtime. Please provide a runtime.".into()); }; - genesis_from_code::(code.as_slice(), genesis_builder_preset)? + genesis_from_code::(code.as_slice(), genesis_builder_preset, storage_patcher)? } }) } @@ -105,6 +107,7 @@ pub fn genesis_storage( fn genesis_from_code( code: &[u8], genesis_builder_preset: &String, + storage_patcher: Option Value>>, ) -> Result { let genesis_config_caller = GenesisConfigBuilderRuntimeCaller::<( sp_io::SubstrateHostFunctions, @@ -112,8 +115,11 @@ fn genesis_from_code( EHF, )>::new(code); - let preset_json = + let mut preset_json = genesis_config_caller.get_named_preset(Some(&genesis_builder_preset.to_string()))?; + if let Some(patcher) = storage_patcher { + preset_json = patcher(preset_json); + } let mut storage = genesis_config_caller.get_storage_for_patch(preset_json).inspect_err(|e| { From 2bae75704ea3d17625c6d9f6cbf72bea9aefdf83 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 23 Oct 2024 18:41:27 +0200 Subject: [PATCH 20/43] Intermediate state with state handler --- .../benchmarking-cli/src/overhead/cmd.rs | 159 ++++++++++-------- .../src/overhead/runtime_utilities.rs | 6 +- .../benchmarking-cli/src/pallet/command.rs | 68 +++++++- .../src/shared/genesis_state.rs | 132 ++++++++------- 4 files changed, 221 insertions(+), 144 deletions(-) diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 73e2968eaa7dc..7d4f15a87ec64 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -29,7 +29,11 @@ use crate::{ fake_runtime_api, template::TemplateData, }, - shared::{self, GenesisBuilderPolicy, HostInfoParams, WeightParams}, + shared::{ + genesis_state, + genesis_state::{GenesisSource, GenesisStateHandler}, + GenesisBuilderPolicy, HostInfoParams, WeightParams, + }, }; use clap::{Args, Parser}; use codec::Encode; @@ -39,14 +43,13 @@ use frame_support::Deserialize; use log::info; use polkadot_parachain_primitives::primitives::Id as ParaId; use sc_block_builder::BlockBuilderApi; -use sc_chain_spec::{ChainSpec, ChainSpecExtension, GenericChainSpec, GenesisBlockBuilder}; +use sc_chain_spec::{ChainSpec, ChainSpecExtension, GenesisBlockBuilder}; use sc_cli::{CliConfiguration, Database, ImportParams, Result, SharedParams}; use sc_client_api::{execution_extensions::ExecutionExtensions, UsageProvider}; use sc_client_db::{BlocksPruning, DatabaseSettings}; use sc_executor::WasmExecutor; use sc_service::{new_client, new_db_backend, BasePath, ClientConfig, TFullClient, TaskManager}; use serde::Serialize; -use serde_json::{json, Value}; use sp_api::{ApiExt, CallApiAt, Core, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::H256; @@ -59,10 +62,13 @@ use sp_runtime::{ use sp_wasm_interface::HostFunctions; use std::{ fmt::{Debug, Display, Formatter}, + fs, path::PathBuf, sync::Arc, }; +use serde_json::{json, Value}; use subxt::{client::RuntimeVersion, ext::futures, Metadata}; +use sp_storage::Storage; const DEFAULT_PARA_ID: u32 = 100; @@ -125,7 +131,7 @@ pub struct OverheadParams { /// Can be used together with `--chain` to determine whether the /// genesis state should be initialized with the values from the /// provided chain spec or a runtime-provided genesis preset. - #[arg(long, value_enum, conflicts_with = "runtime")] + #[arg(long, value_enum, conflicts_with = "runtime", alias = "genesis-builder-policy")] pub genesis_builder: Option, /// Parachain Id to use for parachains. If not specified, the benchmark code will choose @@ -210,27 +216,6 @@ fn create_inherent_data + HeaderBackend, Blo inherent_data } -/// Patch the parachain id into the genesis config. This is necessary since the inherents -/// also contain a parachain id and they need to match. -fn patch_genesis(mut input_value: Value, chain_type: ChainType) -> Value { - // If we identified a parachain we should patch a parachain id into the genesis config. - // This ensures compatibility with the inherents that we provide to successfully build a - // block. - if let Parachain(para_id) = chain_type { - sc_chain_spec::json_patch::merge( - &mut input_value, - json!({ - "parachainInfo": { - "parachainId": para_id, - } - }), - ); - log::debug!("Genesis Config Json"); - log::debug!("{}", input_value); - } - input_value -} - /// Identifies what kind of chain we are dealing with. /// /// Chains containing the `ParachainSystem` and `ParachainInfo` pallet are considered parachains. @@ -264,22 +249,58 @@ pub struct ParachainExtension { } impl OverheadCmd { - fn chain_spec_from_path( + fn state_handler_from_cli( &self, - ) -> Result<(Option>, Option)> { - let chain_spec = self - .shared_params - .chain - .clone() - .map(|path| { - GenericChainSpec::::from_json_file(path.into()) - .map_err(|e| format!("Unable to load chain spec: {:?}", e)) - }) - .transpose()?; - - let para_id_from_chain_spec = - chain_spec.as_ref().and_then(|spec| spec.extensions().para_id); - Ok((chain_spec.map(|c| Box::new(c) as Box<_>), para_id_from_chain_spec)) + chain_spec_from_api: Option>, + ) -> Result<(GenesisStateHandler, Option)> { + let genesis_builder_to_source = || match self.params.genesis_builder { + Some(GenesisBuilderPolicy::Runtime) | Some(GenesisBuilderPolicy::SpecRuntime) => + GenesisSource::Runtime(self.params.genesis_builder_preset.clone()), + Some( + GenesisBuilderPolicy::Spec | + GenesisBuilderPolicy::SpecGenesis | + GenesisBuilderPolicy::None + ) | None => GenesisSource::Raw, + }; + + // First handle chain-spec passed in via API parameter. + if let Some(chain_spec) = chain_spec_from_api { + log::debug!( + "Initializing state handler with chain-spec from API: {:?}", + chain_spec + ); + + let source = genesis_builder_to_source(); + return Ok((GenesisStateHandler::ChainSpec(chain_spec, source), self.params.para_id)) + }; + + // Handle chain-spec passed in via CLI. + if let Some(chain_spec_path) = &self.shared_params.chain { + log::debug!( + "Initializing state handler with chain-spec from path: {:?}", + chain_spec_path + ); + let (chain_spec, para_id_from_chain_spec) = + genesis_state::chain_spec_from_path::(chain_spec_path.to_string().into())?; + + let source = genesis_builder_to_source(); + + return Ok((GenesisStateHandler::ChainSpec(chain_spec, source), self.params.para_id.or(para_id_from_chain_spec))) + }; + + // Check for runtimes. In general, we make sure that `--runtime` and `--chain` are + // incompatible on the CLI level. + if let Some(runtime_path) = &self.params.runtime { + log::debug!("Initializing state handler with runtime from path: {:?}", runtime_path); + + let runtime_blob = fs::read(runtime_path)?; + return Ok((GenesisStateHandler::Runtime( + runtime_blob, + self.params.genesis_builder_preset.clone() + ), self.params.para_id)) + }; + + Err("Neither a runtime nor a chain-spec were specified".to_string().into()) } /// Run the benchmark overhead command. @@ -294,23 +315,19 @@ impl OverheadCmd { Block: BlockT, ExtraHF: HostFunctions, { - let (chain_spec, para_id_from_chain_spec) = match chain_spec { - Some(_) => (chain_spec, None), - None => self.chain_spec_from_path::<(ParachainHostFunctions, ExtraHF)>()?, - }; - - let code_bytes = shared::genesis_state::get_code_bytes(&chain_spec, &self.params.runtime)?; + let (state_handler, para_id) = self.state_handler_from_cli::<(ParachainHostFunctions, ExtraHF)>(chain_spec)?; let executor = WasmExecutor::<(ParachainHostFunctions, ExtraHF)>::builder() .with_allow_missing_host_functions(true) .build(); - let metadata = fetch_latest_metadata_from_blob(&executor, &code_bytes)?; - let chain_type = identify_chain(&metadata, para_id_from_chain_spec.or(self.params.para_id)); + let metadata = fetch_latest_metadata_from_blob(&executor, state_handler.get_code_bytes()?)?; + + // At this point we know what kind of chain we are dealing with. + let chain_type = identify_chain(&metadata, para_id); let client = self.build_client_components::( - chain_spec, - &code_bytes, + state_handler.build_storage::<(ParachainHostFunctions, ExtraHF)>(Some(Box::new(move |value| patch_genesis(value, para_id))))?, executor, &chain_type, )?; @@ -361,8 +378,7 @@ impl OverheadCmd { fn build_client_components( &self, - chain_spec: Option>, - code_bytes: &Vec, + genesis_storage: Storage, executor: WasmExecutor, chain_type: &ChainType, ) -> Result>> { @@ -386,20 +402,8 @@ impl OverheadCmd { source: database_source, })?; - let storage = shared::genesis_state::genesis_storage::( - self.params.genesis_builder, - &self.params.runtime, - Some(&code_bytes), - &self.params.genesis_builder_preset, - &chain_spec, - { - let chain_type = chain_type.clone(); - Some(Box::new(move |value| patch_genesis(value, chain_type))) - }, - )?; - let genesis_block_builder = GenesisBlockBuilder::new_with_storage( - storage, + genesis_storage, true, backend.clone(), executor.clone(), @@ -541,6 +545,27 @@ impl ChainType { } } +/// Patch the parachain id into the genesis config. This is necessary since the inherents +/// also contain a parachain id and they need to match. +fn patch_genesis(mut input_value: Value, para_id: Option) -> Value { + // If we identified a parachain we should patch a parachain id into the genesis config. + // This ensures compatibility with the inherents that we provide to successfully build a + // block. + if let Some(para_id) = para_id { + sc_chain_spec::json_patch::merge( + &mut input_value, + json!({ + "parachainInfo": { + "parachainId": para_id, + } + }), + ); + log::debug!("Genesis Config Json"); + log::debug!("{}", input_value); + } + input_value +} + // Boilerplate impl CliConfiguration for OverheadCmd { fn shared_params(&self) -> &SharedParams { @@ -577,7 +602,7 @@ mod tests { let code_bytes = cumulus_test_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of cumulus-test-runtime") .to_vec(); - let metadata = super::fetch_latest_metadata_from_blob(&executor, &code_bytes).unwrap(); + let metadata = super::fetch_latest_metadata_from_blob(&executor, code_bytes.into()).unwrap(); assert_eq!(identify_chain(&metadata, Some(100)), ChainType::Parachain(100)); assert_eq!(identify_chain(&metadata, None), ChainType::Parachain(DEFAULT_PARA_ID)); } @@ -588,7 +613,7 @@ mod tests { let code_bytes = substrate_test_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of cumulus-test-runtime") .to_vec(); - let metadata = super::fetch_latest_metadata_from_blob(&executor, &code_bytes).unwrap(); + let metadata = super::fetch_latest_metadata_from_blob(&executor, code_bytes.into()).unwrap(); assert_eq!(identify_chain(&metadata, Some(100)), ChainType::Unknown); } } diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs index bfc2546706235..a19c8a2826b39 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs @@ -150,9 +150,9 @@ impl ExtrinsicBuilder for DynamicRemarkBuilder { /// Fetches the latest metadata from the given runtime blob. pub fn fetch_latest_metadata_from_blob( executor: &WasmExecutor, - code_bytes: &Vec, + code_bytes: Cow<[u8]>, ) -> sc_cli::Result { - let runtime_caller = RuntimeCaller::new(executor, code_bytes.into()); + let runtime_caller = RuntimeCaller::new(executor, code_bytes); let version_result = runtime_caller.call("Metadata_metadata_versions", ()); let opaque_metadata: OpaqueMetadata = match version_result { @@ -242,7 +242,7 @@ mod tests { let code_bytes = cumulus_test_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of cumulus-test-runtime") .to_vec(); - let metadata = super::fetch_latest_metadata_from_blob(&executor, &code_bytes).unwrap(); + let metadata = super::fetch_latest_metadata_from_blob(&executor, code_bytes.into()).unwrap(); assert!(metadata.pallet_by_name("ParachainInfo").is_some()); } diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index 016a624102b8b..50543497f54b6 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -21,7 +21,6 @@ use super::{ }; use crate::{ pallet::types::FetchedCode, - shared::genesis_state::{genesis_storage, get_code_bytes}, }; use codec::{Decode, Encode}; use frame_benchmarking::{ @@ -55,6 +54,8 @@ use std::{ str::FromStr, time, }; +use crate::shared::genesis_state::{GenesisSource, GenesisStateHandler}; +use crate::shared::{genesis_state, GenesisBuilderPolicy}; /// Logging target const LOG_TARGET: &'static str = "polkadot_sdk_frame::benchmark::pallet"; @@ -168,6 +169,60 @@ impl PalletCmd { self.run_with_spec::(Some(config.chain_spec)) } + fn state_handler_from_cli( + &self, + chain_spec_from_api: Option>, + ) -> Result { + let genesis_builder_to_source = || match self.genesis_builder { + Some(GenesisBuilderPolicy::Runtime) | Some(GenesisBuilderPolicy::SpecRuntime) => + GenesisSource::Runtime(self.genesis_builder_preset.clone()), + Some( + GenesisBuilderPolicy::Spec | + GenesisBuilderPolicy::SpecGenesis | + GenesisBuilderPolicy::None + ) | None => GenesisSource::Raw, + }; + + // First handle chain-spec passed in via API parameter. + if let Some(chain_spec) = chain_spec_from_api { + log::debug!( + "Initializing state handler with chain-spec from API: {:?}", + chain_spec + ); + + let source = genesis_builder_to_source(); + return Ok(GenesisStateHandler::ChainSpec(chain_spec, source)) + }; + + // Handle chain-spec passed in via CLI. + if let Some(chain_spec_path) = &self.shared_params.chain { + log::debug!( + "Initializing state handler with chain-spec from path: {:?}", + chain_spec_path + ); + let (chain_spec, _) = + genesis_state::chain_spec_from_path::(chain_spec_path.to_string().into())?; + + let source = genesis_builder_to_source(); + + return Ok(GenesisStateHandler::ChainSpec(chain_spec, source)) + }; + + // Check for runtimes. In general, we make sure that `--runtime` and `--chain` are + // incompatible on the CLI level. + if let Some(runtime_path) = &self.runtime { + log::debug!("Initializing state handler with runtime from path: {:?}", runtime_path); + + let runtime_blob = fs::read(runtime_path)?; + return Ok(GenesisStateHandler::Runtime( + runtime_blob, + self.genesis_builder_preset.clone() + )) + }; + + Err("Neither a runtime nor a chain-spec were specified".to_string().into()) + } + /// Runs the pallet benchmarking command. pub fn run_with_spec( &self, @@ -202,15 +257,10 @@ impl PalletCmd { return self.output_from_results(&batches) } - let code_bytes = get_code_bytes(&chain_spec, &self.runtime)?; - let genesis_storage = genesis_storage::>( - self.genesis_builder, - &self.runtime, - Some(&code_bytes), - &self.genesis_builder_preset, - &chain_spec, - None, + let state_handler = self.state_handler_from_cli::>( + chain_spec, )?; + let genesis_storage = state_handler.build_storage::>(None)?; let cache_size = Some(self.database_cache_size as usize); let state_with_tracking = BenchmarkingState::::new( diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs index fce14b70900db..c56ea7d107daa 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -3,14 +3,16 @@ // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 -use crate::shared::GenesisBuilderPolicy; -use sc_chain_spec::{ChainSpec, GenesisConfigBuilderRuntimeCaller}; +use crate::{overhead::cmd::ParachainExtension}; +use sc_chain_spec::{ChainSpec, GenericChainSpec, GenesisConfigBuilderRuntimeCaller}; use sc_cli::Result; use serde_json::Value; use sp_storage::{well_known_keys::CODE, Storage}; use sp_wasm_interface::HostFunctions; -use std::{fs, path::PathBuf}; - +use std::{ + path::{PathBuf}, +}; +use std::borrow::Cow; // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -39,69 +41,69 @@ generate the genesis state is deprecated. Please remove the `--chain`/`--dev`/`- point `--runtime` to your runtime blob and set `--genesis-builder=runtime`. This warning may \ become a hard error any time after December 2024."; -pub fn get_code_bytes( - chain_spec: &Option>, - runtime: &Option, -) -> Result> { - match (chain_spec, runtime) { - (None, Some(runtime_code_path)) => Ok(fs::read(runtime_code_path)?), - // Get the code blob from the chain spec. - // First transform the chain_spec to storage, then extract the code. - (Some(chain_spec), None) => { - let mut storage = chain_spec - .as_storage_builder() - .build_storage() - .map_err(|e| format!("Can not transform chain-spec to storage {}", e))?; - Ok(storage.top.remove(CODE).ok_or("chain spec genesis does not contain code")?) - }, - (Some(_), Some(_)) => - Err("Both runtime and chain spec provided, please only provide one of both.".into()), - (_, _) => Err("Please provide either a runtime or a chain spec.".into()), +pub enum GenesisSource { + Runtime(String), + Raw, + None, +} + +pub enum GenesisStateHandler { + ChainSpec(Box, GenesisSource), + Runtime(Vec, String), +} + +impl GenesisStateHandler { + /// Populate the genesis storage. + /// + /// If the raw storage is derived from a named preset, `json_patcher` is can be used to inject values into the preset. + pub fn build_storage(&self, json_patcher: Option Value + 'static>>) -> Result { + match self { + GenesisStateHandler::ChainSpec(chain_spec, source) => { + match source { + GenesisSource::Runtime(preset) => { + let mut storage = chain_spec + .build_storage()?; + let code_bytes = storage.top.remove(CODE).ok_or("chain spec genesis does not contain code")?; + genesis_from_code::(code_bytes.as_slice(), preset, json_patcher) + } + GenesisSource::Raw => { + chain_spec + .build_storage() + .map_err(|e| format!("{ERROR_CANNOT_BUILD_GENESIS}\nError: {e}").into()) + } + GenesisSource::None => { + Ok(Storage::default()) + } + } + }, + GenesisStateHandler::Runtime(code_bytes, preset) => { + genesis_from_code::(code_bytes.as_slice(), preset, json_patcher) + } + } + } + + pub fn get_code_bytes(&self) -> Result> { + match self { + GenesisStateHandler::ChainSpec(chain_spec, _) => { + let mut storage = chain_spec + .build_storage()?; + storage.top.remove(CODE).map(|code| Cow::from(code)).ok_or("chain spec genesis does not contain code".into()) + } + GenesisStateHandler::Runtime(code_bytes, _) => { + Ok(code_bytes.into()) + } + } } } -pub fn genesis_storage( - genesis_builder: Option, - runtime: &Option, - code_bytes: Option<&Vec>, - genesis_builder_preset: &String, - chain_spec: &Option>, - storage_patcher: Option Value + 'static>>, -) -> Result { - Ok(match (genesis_builder, runtime) { - (Some(GenesisBuilderPolicy::None), Some(_)) => return Err("Cannot use `--genesis-builder=none` with `--runtime` since the runtime would be ignored.".into()), - (Some(GenesisBuilderPolicy::None), None) => Storage::default(), - (Some(GenesisBuilderPolicy::SpecGenesis | GenesisBuilderPolicy::Spec), Some(_)) => - return Err("Cannot use `--genesis-builder=spec-genesis` with `--runtime` since the runtime would be ignored.".into()), - (Some(GenesisBuilderPolicy::SpecGenesis | GenesisBuilderPolicy::Spec), None) | (None, None) => { - log::warn!("{WARN_SPEC_GENESIS_CTOR}"); - let Some(chain_spec) = chain_spec else { - return Err("No chain spec specified to generate the genesis state".into()); - }; - - let storage = chain_spec - .build_storage() - .map_err(|e| format!("{ERROR_CANNOT_BUILD_GENESIS}\nError: {e}"))?; - - storage - }, - (Some(GenesisBuilderPolicy::SpecRuntime), Some(_)) => - return Err("Cannot use `--genesis-builder=spec` with `--runtime` since the runtime would be ignored.".into()), - (Some(GenesisBuilderPolicy::SpecRuntime), None) => { - let Some(code) = code_bytes else { - return Err("Can not build genesis from runtime. Please provide a runtime.".into()); - }; - - genesis_from_code::(code.as_slice(), genesis_builder_preset, storage_patcher)? - }, - (Some(GenesisBuilderPolicy::Runtime), None) => return Err("Cannot use `--genesis-builder=runtime` without `--runtime`".into()), - (Some(GenesisBuilderPolicy::Runtime), Some(_)) | (None, Some(_)) => { - let Some(code) = code_bytes else { - return Err("Can not build genesis from runtime. Please provide a runtime.".into()); - }; - - genesis_from_code::(code.as_slice(), genesis_builder_preset, storage_patcher)? - } - }) + +pub fn chain_spec_from_path( + chain: PathBuf, +) -> Result<(Box, Option)> { + let spec = GenericChainSpec::::from_json_file(chain) + .map_err(|e| format!("Unable to load chain spec: {:?}", e))?; + + let para_id_from_chain_spec = spec.extensions().para_id; + Ok((Box::new(spec), para_id_from_chain_spec)) } fn genesis_from_code( From 272341f141d258c9dd6d27a1628aadb867166f83 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 25 Oct 2024 14:41:51 +0200 Subject: [PATCH 21/43] Review comments --- cumulus/test/service/src/chain_spec.rs | 2 +- polkadot/cli/src/command.rs | 2 +- .../utils/frame/benchmarking-cli/src/lib.rs | 2 +- .../frame/benchmarking-cli/src/overhead/cmd.rs | 17 +++++++++-------- .../src/overhead/runtime_utilities.rs | 4 ++-- .../frame/benchmarking-cli/src/shared/mod.rs | 1 + .../utils/frame/omni-bencher/src/command.rs | 2 +- 7 files changed, 16 insertions(+), 14 deletions(-) diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index 23d4310ce27c9..0e8b3dc1e0988 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -82,7 +82,7 @@ pub fn get_chain_spec_with_extra_endowed( .with_name("Local Testnet") .with_id(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) .with_chain_type(ChainType::Local) - .with_genesis_patch(development_preset) + .with_genesis_config_patch(development_preset) .build() } diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index 79999c195e269..e920682e7817a 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -394,7 +394,7 @@ pub fn run() -> Result<()> { BenchmarkCmd::Overhead(cmd) => runner.sync_run(|config| { if cmd.params.runtime.is_some() { return Err(sc_cli::Error::Input( - "Polkadot binary does not support `--runtime` flag for `benchmark overhead`. Please provide a chain spec or use the omni-bencher." + "Polkadot binary does not support `--runtime` flag for `benchmark overhead`. Please provide a chain spec or use the `frame-omni-bencher`." .into(), ) .into()) diff --git a/substrate/utils/frame/benchmarking-cli/src/lib.rs b/substrate/utils/frame/benchmarking-cli/src/lib.rs index f1fc37214b7fe..02832a48c6f54 100644 --- a/substrate/utils/frame/benchmarking-cli/src/lib.rs +++ b/substrate/utils/frame/benchmarking-cli/src/lib.rs @@ -30,7 +30,7 @@ pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; pub use machine::{MachineCmd, SUBSTRATE_REFERENCE_HARDWARE}; pub use overhead::{ runtime_utilities::{ - fetch_latest_metadata_from_blob, DynamicRemarkBuilder, SubstrateRemarkBuilder, + fetch_latest_metadata_from_code_blob, DynamicRemarkBuilder, SubstrateRemarkBuilder, }, OpaqueBlock, OverheadCmd, }; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 7d4f15a87ec64..2dc41ba01e710 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -321,7 +321,7 @@ impl OverheadCmd { .with_allow_missing_host_functions(true) .build(); - let metadata = fetch_latest_metadata_from_blob(&executor, state_handler.get_code_bytes()?)?; + let metadata = fetch_latest_metadata_from_code_blob(&executor, state_handler.get_code_bytes()?)?; // At this point we know what kind of chain we are dealing with. let chain_type = identify_chain(&metadata, para_id); @@ -334,26 +334,27 @@ impl OverheadCmd { let inherent_data = create_inherent_data(&client, &chain_type); - let ext_builder = { + let (ext_builder, runtime_name) = { let genesis = client.usage_info().chain.best_hash; let version = client.runtime_api().version(genesis).unwrap(); + let runtime_name = version.spec_name; let runtime_version = RuntimeVersion { spec_version: version.spec_version, transaction_version: version.transaction_version, }; match ext_builder_provider { - Some(provider) => provider(metadata, genesis, runtime_version), + Some(provider) => (provider(metadata, genesis, runtime_version), runtime_name), None => { let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); - Box::new(SubstrateRemarkBuilder::new(metadata, genesis, runtime_version)) - as Box<_> + (Box::new(SubstrateRemarkBuilder::new(metadata, genesis, runtime_version)) + as Box<_>, runtime_name) }, } }; self.run( - self.params.runtime_name.clone(), + runtime_name.to_string(), client, inherent_data, Default::default(), @@ -602,7 +603,7 @@ mod tests { let code_bytes = cumulus_test_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of cumulus-test-runtime") .to_vec(); - let metadata = super::fetch_latest_metadata_from_blob(&executor, code_bytes.into()).unwrap(); + let metadata = super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); assert_eq!(identify_chain(&metadata, Some(100)), ChainType::Parachain(100)); assert_eq!(identify_chain(&metadata, None), ChainType::Parachain(DEFAULT_PARA_ID)); } @@ -613,7 +614,7 @@ mod tests { let code_bytes = substrate_test_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of cumulus-test-runtime") .to_vec(); - let metadata = super::fetch_latest_metadata_from_blob(&executor, code_bytes.into()).unwrap(); + let metadata = super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); assert_eq!(identify_chain(&metadata, Some(100)), ChainType::Unknown); } } diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs index a19c8a2826b39..061f1f3deadf2 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs @@ -148,7 +148,7 @@ impl ExtrinsicBuilder for DynamicRemarkBuilder { } /// Fetches the latest metadata from the given runtime blob. -pub fn fetch_latest_metadata_from_blob( +pub fn fetch_latest_metadata_from_code_blob( executor: &WasmExecutor, code_bytes: Cow<[u8]>, ) -> sc_cli::Result { @@ -242,7 +242,7 @@ mod tests { let code_bytes = cumulus_test_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of cumulus-test-runtime") .to_vec(); - let metadata = super::fetch_latest_metadata_from_blob(&executor, code_bytes.into()).unwrap(); + let metadata = super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); assert!(metadata.pallet_by_name("ParachainInfo").is_some()); } diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs b/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs index 961cf2cd5398e..5acd346f10a10 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs @@ -144,6 +144,7 @@ pub enum GenesisBuilderPolicy { /// state. However, to keep backwards compatibility, this is not the default. None, /// Let the runtime build the genesis state through its `BuildGenesisConfig` runtime API. + /// This will use the `development` preset by default. Runtime, /// Use the runtime from the Spec file to build the genesis state. SpecRuntime, diff --git a/substrate/utils/frame/omni-bencher/src/command.rs b/substrate/utils/frame/omni-bencher/src/command.rs index efabadc1ecc0e..fddbd9ffa8570 100644 --- a/substrate/utils/frame/omni-bencher/src/command.rs +++ b/substrate/utils/frame/omni-bencher/src/command.rs @@ -148,7 +148,7 @@ impl V1SubCommand { overhead_cmd.run_with_extrinsic_builder::(None), _ => return Err( - "Only the `v1 benchmark pallet` command is currently supported".into() + "Only the `v1 benchmark pallet` and `v1 benchmark overhead` command is currently supported".into() ), }, } From a375b685b6076b07fca98e15edbc009d127203ae Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 25 Oct 2024 17:47:59 +0200 Subject: [PATCH 22/43] Review comments --- Cargo.lock | 1 - cumulus/polkadot-omni-node/lib/Cargo.toml | 35 ++++++----- .../runtime/src/genesis_config_presets.rs | 16 ++--- .../benchmarking-cli/src/extrinsic/bench.rs | 56 ++++++++--------- .../benchmarking-cli/src/overhead/cmd.rs | 61 +++++++++++-------- .../src/overhead/runtime_utilities.rs | 46 +++++--------- .../src/shared/genesis_state.rs | 26 ++++---- 7 files changed, 108 insertions(+), 133 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 78fbc767d81b1..ccd97bccba239 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14994,7 +14994,6 @@ dependencies = [ "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-state-trie-migration-rpc", - "subxt", "tokio", "wait-timeout", ] diff --git a/cumulus/polkadot-omni-node/lib/Cargo.toml b/cumulus/polkadot-omni-node/lib/Cargo.toml index 88dc31c2249c7..a690229f16959 100644 --- a/cumulus/polkadot-omni-node/lib/Cargo.toml +++ b/cumulus/polkadot-omni-node/lib/Cargo.toml @@ -22,7 +22,6 @@ log = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } docify = { workspace = true } -subxt = { workspace = true } # Local jsonrpsee = { features = ["server"], workspace = true } @@ -96,28 +95,28 @@ wait-timeout = { workspace = true } [features] default = [] rococo-native = [ - "polkadot-cli/rococo-native", + "polkadot-cli/rococo-native", ] westend-native = [ - "polkadot-cli/westend-native", + "polkadot-cli/westend-native", ] runtime-benchmarks = [ - "cumulus-primitives-core/runtime-benchmarks", - "frame-benchmarking-cli/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "frame-benchmarking-cli/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "parachains-common/runtime-benchmarks", - "polkadot-cli/runtime-benchmarks", - "polkadot-primitives/runtime-benchmarks", - "sc-client-db/runtime-benchmarks", - "sc-service/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", + "polkadot-cli/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks", + "sc-client-db/runtime-benchmarks", + "sc-service/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] try-runtime = [ - "frame-support/try-runtime", - "frame-try-runtime/try-runtime", - "pallet-transaction-payment/try-runtime", - "polkadot-cli/try-runtime", - "sp-runtime/try-runtime", + "frame-support/try-runtime", + "frame-try-runtime/try-runtime", + "pallet-transaction-payment/try-runtime", + "polkadot-cli/try-runtime", + "sp-runtime/try-runtime", ] diff --git a/cumulus/test/runtime/src/genesis_config_presets.rs b/cumulus/test/runtime/src/genesis_config_presets.rs index 66d8c50d3496f..b322d6afbcaf1 100644 --- a/cumulus/test/runtime/src/genesis_config_presets.rs +++ b/cumulus/test/runtime/src/genesis_config_presets.rs @@ -22,6 +22,7 @@ use super::{ use alloc::{vec, vec::Vec}; use cumulus_primitives_core::ParaId; +use frame_support::build_struct_json_patch; use sp_genesis_builder::PresetId; use sp_keyring::Sr25519Keyring; @@ -30,23 +31,14 @@ fn cumulus_test_runtime( endowed_accounts: Vec, id: ParaId, ) -> serde_json::Value { - let config = RuntimeGenesisConfig { - system: Default::default(), + let config = build_struct_json_patch!( RuntimeGenesisConfig { balances: BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), }, sudo: SudoConfig { key: Some(Sr25519Keyring::Alice.public().into()) }, - transaction_payment: Default::default(), - test_pallet: Default::default(), - parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, - // no need to pass anything to aura, in fact it will panic if we do. Session will take care - // of this. `aura: Default::default()` + parachain_info: ParachainInfoConfig { parachain_id: id }, aura: AuraConfig { authorities: invulnerables }, - aura_ext: Default::default(), - parachain_system: Default::default(), - glutton: Default::default(), - }; - + }); serde_json::to_value(config).expect("Could not build genesis config.") } diff --git a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index c4870f9bb7ea1..ae14f1bc5cbad 100644 --- a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -149,45 +149,37 @@ where builder.push(inherent)?; } - // Return early if `ext_builder` is `None`. - let ext_builder = if let Some(ext_builder) = ext_builder { - ext_builder - } else { - let proof_size = builder.current_proof_size(); - return Ok(( - builder.build()?.block, - None, - proof_size - .unwrap_or(0) - .try_into() - .map_err(|_| "Proof size is too large".to_string())?, - )) + let num_ext = match ext_builder { + Some(ext_builder) => { + // Put as many extrinsics into the block as possible and count them. + info!("Building block, this takes some time..."); + let mut num_ext = 0; + for nonce in 0..self.max_ext_per_block() { + let ext = ext_builder.build(nonce)?; + match builder.push(ext.clone()) { + Ok(()) => {}, + Err(ApplyExtrinsicFailed(Validity(TransactionValidityError::Invalid( + InvalidTransaction::ExhaustsResources, + )))) => break, // Block is full + Err(e) => return Err(Error::Client(e)), + } + num_ext += 1; + } + if num_ext == 0 { + return Err("A Block must hold at least one extrinsic".into()) + } + info!("Extrinsics per block: {}", num_ext); + Some(num_ext) + }, + None => None, }; - // Put as many extrinsics into the block as possible and count them. - info!("Building block, this takes some time..."); - let mut num_ext = 0; - for nonce in 0..self.max_ext_per_block() { - let ext = ext_builder.build(nonce)?; - match builder.push(ext.clone()) { - Ok(()) => {}, - Err(ApplyExtrinsicFailed(Validity(TransactionValidityError::Invalid( - InvalidTransaction::ExhaustsResources, - )))) => break, // Block is full - Err(e) => return Err(Error::Client(e)), - } - num_ext += 1; - } - if num_ext == 0 { - return Err("A Block must hold at least one extrinsic".into()) - } - info!("Extrinsics per block: {}", num_ext); let proof_size = builder.current_proof_size(); let block = builder.build()?.block; Ok(( block, - Some(num_ext), + num_ext, proof_size .unwrap_or(0) .try_into() diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 2dc41ba01e710..2c82a688a98b4 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -50,6 +50,7 @@ use sc_client_db::{BlocksPruning, DatabaseSettings}; use sc_executor::WasmExecutor; use sc_service::{new_client, new_db_backend, BasePath, ClientConfig, TFullClient, TaskManager}; use serde::Serialize; +use serde_json::{json, Value}; use sp_api::{ApiExt, CallApiAt, Core, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::H256; @@ -59,6 +60,7 @@ use sp_runtime::{ traits::{BlakeTwo256, Block as BlockT}, DigestItem, OpaqueExtrinsic, }; +use sp_storage::Storage; use sp_wasm_interface::HostFunctions; use std::{ fmt::{Debug, Display, Formatter}, @@ -66,9 +68,7 @@ use std::{ path::PathBuf, sync::Arc, }; -use serde_json::{json, Value}; use subxt::{client::RuntimeVersion, ext::futures, Metadata}; -use sp_storage::Storage; const DEFAULT_PARA_ID: u32 = 100; @@ -161,7 +161,7 @@ pub type ParachainHostFunctions = ( pub type BlockNumber = u32; -/// Typical block header.`. +/// Typical block header. pub type Header = generic::Header; /// Typical block type using `OpaqueExtrinsic`. @@ -259,16 +259,14 @@ impl OverheadCmd { Some( GenesisBuilderPolicy::Spec | GenesisBuilderPolicy::SpecGenesis | - GenesisBuilderPolicy::None - ) | None => GenesisSource::Raw, + GenesisBuilderPolicy::None, + ) | + None => GenesisSource::Raw, }; // First handle chain-spec passed in via API parameter. if let Some(chain_spec) = chain_spec_from_api { - log::debug!( - "Initializing state handler with chain-spec from API: {:?}", - chain_spec - ); + log::debug!("Initializing state handler with chain-spec from API: {:?}", chain_spec); let source = genesis_builder_to_source(); return Ok((GenesisStateHandler::ChainSpec(chain_spec, source), self.params.para_id)) @@ -277,15 +275,18 @@ impl OverheadCmd { // Handle chain-spec passed in via CLI. if let Some(chain_spec_path) = &self.shared_params.chain { log::debug!( - "Initializing state handler with chain-spec from path: {:?}", - chain_spec_path - ); + "Initializing state handler with chain-spec from path: {:?}", + chain_spec_path + ); let (chain_spec, para_id_from_chain_spec) = genesis_state::chain_spec_from_path::(chain_spec_path.to_string().into())?; let source = genesis_builder_to_source(); - return Ok((GenesisStateHandler::ChainSpec(chain_spec, source), self.params.para_id.or(para_id_from_chain_spec))) + return Ok(( + GenesisStateHandler::ChainSpec(chain_spec, source), + self.params.para_id.or(para_id_from_chain_spec), + )) }; // Check for runtimes. In general, we make sure that `--runtime` and `--chain` are @@ -294,10 +295,13 @@ impl OverheadCmd { log::debug!("Initializing state handler with runtime from path: {:?}", runtime_path); let runtime_blob = fs::read(runtime_path)?; - return Ok((GenesisStateHandler::Runtime( - runtime_blob, - self.params.genesis_builder_preset.clone() - ), self.params.para_id)) + return Ok(( + GenesisStateHandler::Runtime( + runtime_blob, + self.params.genesis_builder_preset.clone(), + ), + self.params.para_id, + )) }; Err("Neither a runtime nor a chain-spec were specified".to_string().into()) @@ -315,19 +319,23 @@ impl OverheadCmd { Block: BlockT, ExtraHF: HostFunctions, { - let (state_handler, para_id) = self.state_handler_from_cli::<(ParachainHostFunctions, ExtraHF)>(chain_spec)?; + let (state_handler, para_id) = + self.state_handler_from_cli::<(ParachainHostFunctions, ExtraHF)>(chain_spec)?; let executor = WasmExecutor::<(ParachainHostFunctions, ExtraHF)>::builder() .with_allow_missing_host_functions(true) .build(); - let metadata = fetch_latest_metadata_from_code_blob(&executor, state_handler.get_code_bytes()?)?; + let metadata = + fetch_latest_metadata_from_code_blob(&executor, state_handler.get_code_bytes()?)?; // At this point we know what kind of chain we are dealing with. let chain_type = identify_chain(&metadata, para_id); let client = self.build_client_components::( - state_handler.build_storage::<(ParachainHostFunctions, ExtraHF)>(Some(Box::new(move |value| patch_genesis(value, para_id))))?, + state_handler.build_storage::<(ParachainHostFunctions, ExtraHF)>(Some(Box::new( + move |value| patch_genesis(value, para_id), + )))?, executor, &chain_type, )?; @@ -347,8 +355,11 @@ impl OverheadCmd { Some(provider) => (provider(metadata, genesis, runtime_version), runtime_name), None => { let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); - (Box::new(SubstrateRemarkBuilder::new(metadata, genesis, runtime_version)) - as Box<_>, runtime_name) + ( + Box::new(SubstrateRemarkBuilder::new(metadata, genesis, runtime_version)) + as Box<_>, + runtime_name, + ) }, } }; @@ -603,7 +614,8 @@ mod tests { let code_bytes = cumulus_test_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of cumulus-test-runtime") .to_vec(); - let metadata = super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); + let metadata = + super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); assert_eq!(identify_chain(&metadata, Some(100)), ChainType::Parachain(100)); assert_eq!(identify_chain(&metadata, None), ChainType::Parachain(DEFAULT_PARA_ID)); } @@ -614,7 +626,8 @@ mod tests { let code_bytes = substrate_test_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of cumulus-test-runtime") .to_vec(); - let metadata = super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); + let metadata = + super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); assert_eq!(identify_chain(&metadata, Some(100)), ChainType::Unknown); } } diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs index 061f1f3deadf2..3d3a719c9497b 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs @@ -59,7 +59,8 @@ impl> DynamicRemarkBuilder { return Err("Unable to fetch metadata runtime API version.".to_string().into()); }; - if metadata_api_version > 1 { + log::debug!("Found metadata API version {}.", metadata_api_version); + let opaque_metadata = if metadata_api_version > 1 { let Ok(mut supported_metadata_versions) = api.metadata_versions(genesis) else { return Err("Unable to fetch metadata versions".to_string().into()); }; @@ -68,43 +69,23 @@ impl> DynamicRemarkBuilder { .pop() .ok_or("No metadata version supported".to_string())?; - let version = - api.version(genesis).map_err(|_| "No runtime version supported".to_string())?; - - let runtime_version = SubxtRuntimeVersion { - spec_version: version.spec_version, - transaction_version: version.transaction_version, - }; - - let metadata = api - .metadata_at_version(genesis, latest) + api.metadata_at_version(genesis, latest) .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? - .ok_or("Unable to decode metadata".to_string())?; - - let metadata = subxt::Metadata::decode(&mut (*metadata).as_slice())?; - - let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); - - return Ok(Self { - offline_client: OfflineClient::new(genesis, runtime_version, metadata), - }) - } - - log::debug!("Found metadata version {}.", metadata_api_version); + .ok_or("Unable to decode metadata".to_string())? + } else { + // Fall back to using the non-versioned metadata API. + api.metadata(genesis) + .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? + }; - // Fall back to using the non-versioned metadata API. - let metadata = api - .metadata(genesis) - .map_err(|e| format!("Unable to fetch metadata: {:?}", e))?; let version = api.version(genesis).unwrap(); let runtime_version = SubxtRuntimeVersion { spec_version: version.spec_version, transaction_version: version.transaction_version, }; - - let metadata = subxt::Metadata::decode(&mut (*metadata).as_slice())?; - + let metadata = subxt::Metadata::decode(&mut (*opaque_metadata).as_slice())?; let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); + Ok(Self { offline_client: OfflineClient::new(genesis, runtime_version, metadata) }) } } @@ -242,7 +223,8 @@ mod tests { let code_bytes = cumulus_test_runtime::WASM_BINARY .expect("To run this test, build the wasm binary of cumulus-test-runtime") .to_vec(); - let metadata = super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); + let metadata = + super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); assert!(metadata.pallet_by_name("ParachainInfo").is_some()); } @@ -256,7 +238,7 @@ mod tests { let runtime_version = runtime_caller .call("Core_version", ()) .expect("Should be able to call runtime_version"); - let runtime_version: RuntimeVersion = Decode::decode(&mut runtime_version.as_slice()) + let _runtime_version: RuntimeVersion = Decode::decode(&mut runtime_version.as_slice()) .expect("Should be able to decode runtime version"); } } diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs index c56ea7d107daa..3b2ab8bf3c3d6 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -3,31 +3,29 @@ // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 -use crate::{overhead::cmd::ParachainExtension}; -use sc_chain_spec::{ChainSpec, GenericChainSpec, GenesisConfigBuilderRuntimeCaller}; -use sc_cli::Result; -use serde_json::Value; -use sp_storage::{well_known_keys::CODE, Storage}; -use sp_wasm_interface::HostFunctions; -use std::{ - path::{PathBuf}, -}; -use std::borrow::Cow; // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// limitations under the License. -/// Build the genesis storage by either the Genesis Builder API, chain spec or nothing. -/// -/// Behaviour can be controlled by the `genesis_builder` parameter. +use crate::{overhead::cmd::ParachainExtension}; +use sc_chain_spec::{ChainSpec, GenericChainSpec, GenesisConfigBuilderRuntimeCaller}; +use sc_cli::Result; +use serde_json::Value; +use sp_storage::{well_known_keys::CODE, Storage}; +use sp_wasm_interface::HostFunctions; +use std::{ + path::{PathBuf}, +}; +use std::borrow::Cow; /// When the runtime could not build the genesis storage. const ERROR_CANNOT_BUILD_GENESIS: &str = "The runtime returned \ From f8f0df4a63ac6f2ff1f961d5e32b4200db978679 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 25 Oct 2024 19:57:48 +0200 Subject: [PATCH 23/43] Improve logging --- .../benchmarking-cli/src/overhead/cmd.rs | 35 ++++----- .../benchmarking-cli/src/pallet/command.rs | 40 +++++----- .../frame/benchmarking-cli/src/pallet/mod.rs | 5 +- .../src/shared/genesis_state.rs | 74 +++++++++---------- 4 files changed, 76 insertions(+), 78 deletions(-) diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 2c82a688a98b4..6ea8b5c81ce74 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -31,7 +31,7 @@ use crate::{ }, shared::{ genesis_state, - genesis_state::{GenesisSource, GenesisStateHandler}, + genesis_state::{GenesisStateHandler, SpecGenesisSource}, GenesisBuilderPolicy, HostInfoParams, WeightParams, }, }; @@ -40,6 +40,7 @@ use codec::Encode; use cumulus_client_parachain_inherent::MockValidationDataInherentDataProvider; use fake_runtime_api::RuntimeApi as FakeRuntimeApi; use frame_support::Deserialize; +use genesis_state::WARN_SPEC_GENESIS_CTOR; use log::info; use polkadot_parachain_primitives::primitives::Id as ParaId; use sc_block_builder::BlockBuilderApi; @@ -71,6 +72,7 @@ use std::{ use subxt::{client::RuntimeVersion, ext::futures, Metadata}; const DEFAULT_PARA_ID: u32 = 100; +const LOG_TARGET: &'static str = "polkadot_sdk_frame::benchmark::overhead"; /// Benchmark the execution overhead per-block and per-extrinsic. #[derive(Debug, Parser)] @@ -116,7 +118,7 @@ pub struct OverheadParams { pub enable_trie_cache: bool, /// Optional runtime blob to use instead of the one from the genesis config. - #[arg(long, value_name = "PATH")] + #[arg(long, value_name = "PATH", conflicts_with = "chain")] pub runtime: Option, /// The preset that we expect to find in the GenesisBuilder runtime API. @@ -237,7 +239,7 @@ fn identify_chain(metadata: &Metadata, para_id: Option) -> ChainType { Unknown }; - log::info!("Identified Chain type from metadata: {}", chain_type); + log::info!(target: LOG_TARGET, "Identified Chain type from metadata: {}", chain_type); chain_type } @@ -255,18 +257,17 @@ impl OverheadCmd { ) -> Result<(GenesisStateHandler, Option)> { let genesis_builder_to_source = || match self.params.genesis_builder { Some(GenesisBuilderPolicy::Runtime) | Some(GenesisBuilderPolicy::SpecRuntime) => - GenesisSource::Runtime(self.params.genesis_builder_preset.clone()), - Some( - GenesisBuilderPolicy::Spec | - GenesisBuilderPolicy::SpecGenesis | - GenesisBuilderPolicy::None, - ) | - None => GenesisSource::Raw, + SpecGenesisSource::Runtime(self.params.genesis_builder_preset.clone()), + Some(GenesisBuilderPolicy::Spec | GenesisBuilderPolicy::SpecGenesis) | None => { + log::warn!(target: LOG_TARGET, "{WARN_SPEC_GENESIS_CTOR}"); + SpecGenesisSource::SpecJson + }, + Some(GenesisBuilderPolicy::None) => SpecGenesisSource::None, }; // First handle chain-spec passed in via API parameter. if let Some(chain_spec) = chain_spec_from_api { - log::debug!("Initializing state handler with chain-spec from API: {:?}", chain_spec); + log::debug!(target: LOG_TARGET, "Initializing state handler with chain-spec from API: {:?}", chain_spec); let source = genesis_builder_to_source(); return Ok((GenesisStateHandler::ChainSpec(chain_spec, source), self.params.para_id)) @@ -274,7 +275,7 @@ impl OverheadCmd { // Handle chain-spec passed in via CLI. if let Some(chain_spec_path) = &self.shared_params.chain { - log::debug!( + log::debug!(target: LOG_TARGET, "Initializing state handler with chain-spec from path: {:?}", chain_spec_path ); @@ -292,7 +293,7 @@ impl OverheadCmd { // Check for runtimes. In general, we make sure that `--runtime` and `--chain` are // incompatible on the CLI level. if let Some(runtime_path) = &self.params.runtime { - log::debug!("Initializing state handler with runtime from path: {:?}", runtime_path); + log::debug!(target: LOG_TARGET, "Initializing state handler with runtime from path: {:?}", runtime_path); let runtime_blob = fs::read(runtime_path)?; return Ok(( @@ -484,7 +485,7 @@ impl OverheadCmd { // per-block execution overhead { let (stats, proof_size) = bench.bench_block()?; - info!("Per-block execution overhead [ns]:\n{:?}", stats); + info!(target: LOG_TARGET, "Per-block execution overhead [ns]:\n{:?}", stats); let template = TemplateData::new( BenchmarkType::Block, &chain_name, @@ -497,7 +498,7 @@ impl OverheadCmd { // per-extrinsic execution overhead { let (stats, proof_size) = bench.bench_extrinsic(ext_builder)?; - info!("Per-extrinsic execution overhead [ns]:\n{:?}", stats); + info!(target: LOG_TARGET, "Per-extrinsic execution overhead [ns]:\n{:?}", stats); let template = TemplateData::new( BenchmarkType::Extrinsic, &chain_name, @@ -572,8 +573,8 @@ fn patch_genesis(mut input_value: Value, para_id: Option) -> Value { } }), ); - log::debug!("Genesis Config Json"); - log::debug!("{}", input_value); + log::debug!(target: LOG_TARGET, "Genesis Config Json"); + log::debug!(target: LOG_TARGET, "{}", input_value); } input_value } diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index 50543497f54b6..aa9582d09d44c 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -21,6 +21,11 @@ use super::{ }; use crate::{ pallet::types::FetchedCode, + shared::{ + genesis_state, + genesis_state::{GenesisStateHandler, SpecGenesisSource, WARN_SPEC_GENESIS_CTOR}, + GenesisBuilderPolicy, + }, }; use codec::{Decode, Encode}; use frame_benchmarking::{ @@ -54,8 +59,6 @@ use std::{ str::FromStr, time, }; -use crate::shared::genesis_state::{GenesisSource, GenesisStateHandler}; -use crate::shared::{genesis_state, GenesisBuilderPolicy}; /// Logging target const LOG_TARGET: &'static str = "polkadot_sdk_frame::benchmark::pallet"; @@ -175,20 +178,17 @@ impl PalletCmd { ) -> Result { let genesis_builder_to_source = || match self.genesis_builder { Some(GenesisBuilderPolicy::Runtime) | Some(GenesisBuilderPolicy::SpecRuntime) => - GenesisSource::Runtime(self.genesis_builder_preset.clone()), - Some( - GenesisBuilderPolicy::Spec | - GenesisBuilderPolicy::SpecGenesis | - GenesisBuilderPolicy::None - ) | None => GenesisSource::Raw, + SpecGenesisSource::Runtime(self.genesis_builder_preset.clone()), + Some(GenesisBuilderPolicy::Spec | GenesisBuilderPolicy::SpecGenesis) | None => { + log::warn!(target: LOG_TARGET, "{WARN_SPEC_GENESIS_CTOR}"); + SpecGenesisSource::SpecJson + }, + Some(GenesisBuilderPolicy::None) => SpecGenesisSource::None, }; // First handle chain-spec passed in via API parameter. if let Some(chain_spec) = chain_spec_from_api { - log::debug!( - "Initializing state handler with chain-spec from API: {:?}", - chain_spec - ); + log::debug!("Initializing state handler with chain-spec from API: {:?}", chain_spec); let source = genesis_builder_to_source(); return Ok(GenesisStateHandler::ChainSpec(chain_spec, source)) @@ -197,9 +197,9 @@ impl PalletCmd { // Handle chain-spec passed in via CLI. if let Some(chain_spec_path) = &self.shared_params.chain { log::debug!( - "Initializing state handler with chain-spec from path: {:?}", - chain_spec_path - ); + "Initializing state handler with chain-spec from path: {:?}", + chain_spec_path + ); let (chain_spec, _) = genesis_state::chain_spec_from_path::(chain_spec_path.to_string().into())?; @@ -216,7 +216,7 @@ impl PalletCmd { let runtime_blob = fs::read(runtime_path)?; return Ok(GenesisStateHandler::Runtime( runtime_blob, - self.genesis_builder_preset.clone() + self.genesis_builder_preset.clone(), )) }; @@ -257,10 +257,10 @@ impl PalletCmd { return self.output_from_results(&batches) } - let state_handler = self.state_handler_from_cli::>( - chain_spec, - )?; - let genesis_storage = state_handler.build_storage::>(None)?; + let state_handler = + self.state_handler_from_cli::>(chain_spec)?; + let genesis_storage = + state_handler.build_storage::>(None)?; let cache_size = Some(self.database_cache_size as usize); let state_with_tracking = BenchmarkingState::::new( diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs index 2ee4eaa7211a1..13d501b403dbb 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -181,9 +181,8 @@ pub struct PalletCmd { /// How to construct the genesis state. /// - /// Uses `GenesisBuilderPolicy::Spec` by default and `GenesisBuilderPolicy::Runtime` if - /// `runtime` is set. - #[arg(long, value_enum, alias = "genesis-builder-policy")] + /// Uses `GenesisBuilderPolicy::Spec` by default. + #[arg(long, value_enum, alias = "genesis-builder-policy", conflicts_with = "runtime")] pub genesis_builder: Option, /// The preset that we expect to find in the GenesisBuilder runtime API. diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs index 3b2ab8bf3c3d6..379c25f7d7e58 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -16,16 +16,13 @@ // limitations under the License. // limitations under the License. -use crate::{overhead::cmd::ParachainExtension}; +use crate::overhead::cmd::ParachainExtension; use sc_chain_spec::{ChainSpec, GenericChainSpec, GenesisConfigBuilderRuntimeCaller}; use sc_cli::Result; use serde_json::Value; use sp_storage::{well_known_keys::CODE, Storage}; use sp_wasm_interface::HostFunctions; -use std::{ - path::{PathBuf}, -}; -use std::borrow::Cow; +use std::{borrow::Cow, path::PathBuf}; /// When the runtime could not build the genesis storage. const ERROR_CANNOT_BUILD_GENESIS: &str = "The runtime returned \ @@ -34,62 +31,63 @@ define a genesis config that can be built. This can be tested with: \ https://github.com/paritytech/polkadot-sdk/pull/3412"; /// Warn when using the chain spec to generate the genesis state. -const WARN_SPEC_GENESIS_CTOR: &'static str = "Using the chain spec instead of the runtime to \ +pub const WARN_SPEC_GENESIS_CTOR: &'static str = "Using the chain spec instead of the runtime to \ generate the genesis state is deprecated. Please remove the `--chain`/`--dev`/`--local` argument, \ point `--runtime` to your runtime blob and set `--genesis-builder=runtime`. This warning may \ become a hard error any time after December 2024."; -pub enum GenesisSource { +pub enum SpecGenesisSource { Runtime(String), - Raw, + SpecJson, None, } pub enum GenesisStateHandler { - ChainSpec(Box, GenesisSource), + ChainSpec(Box, SpecGenesisSource), Runtime(Vec, String), } impl GenesisStateHandler { /// Populate the genesis storage. /// - /// If the raw storage is derived from a named preset, `json_patcher` is can be used to inject values into the preset. - pub fn build_storage(&self, json_patcher: Option Value + 'static>>) -> Result { + /// If the raw storage is derived from a named genesis preset, `json_patcher` is can be used to + /// inject values into the preset. + pub fn build_storage( + &self, + json_patcher: Option Value + 'static>>, + ) -> Result { match self { - GenesisStateHandler::ChainSpec(chain_spec, source) => { - match source { - GenesisSource::Runtime(preset) => { - let mut storage = chain_spec - .build_storage()?; - let code_bytes = storage.top.remove(CODE).ok_or("chain spec genesis does not contain code")?; - genesis_from_code::(code_bytes.as_slice(), preset, json_patcher) - } - GenesisSource::Raw => { - chain_spec - .build_storage() - .map_err(|e| format!("{ERROR_CANNOT_BUILD_GENESIS}\nError: {e}").into()) - } - GenesisSource::None => { - Ok(Storage::default()) - } - } + GenesisStateHandler::ChainSpec(chain_spec, source) => match source { + SpecGenesisSource::Runtime(preset) => { + let mut storage = chain_spec.build_storage()?; + let code_bytes = storage + .top + .remove(CODE) + .ok_or("chain spec genesis does not contain code")?; + genesis_from_code::(code_bytes.as_slice(), preset, json_patcher) + }, + SpecGenesisSource::SpecJson => chain_spec + .build_storage() + .map_err(|e| format!("{ERROR_CANNOT_BUILD_GENESIS}\nError: {e}").into()), + SpecGenesisSource::None => Ok(Storage::default()), }, - GenesisStateHandler::Runtime(code_bytes, preset) => { - genesis_from_code::(code_bytes.as_slice(), preset, json_patcher) - } + GenesisStateHandler::Runtime(code_bytes, preset) => + genesis_from_code::(code_bytes.as_slice(), preset, json_patcher), } } + /// Get the runtime code blob. pub fn get_code_bytes(&self) -> Result> { match self { GenesisStateHandler::ChainSpec(chain_spec, _) => { - let mut storage = chain_spec - .build_storage()?; - storage.top.remove(CODE).map(|code| Cow::from(code)).ok_or("chain spec genesis does not contain code".into()) - } - GenesisStateHandler::Runtime(code_bytes, _) => { - Ok(code_bytes.into()) - } + let mut storage = chain_spec.build_storage()?; + storage + .top + .remove(CODE) + .map(|code| Cow::from(code)) + .ok_or("chain spec genesis does not contain code".into()) + }, + GenesisStateHandler::Runtime(code_bytes, _) => Ok(code_bytes.into()), } } } From 0b7c3eaf7bfbebe4c394da233c652292e52d13fb Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 25 Oct 2024 21:28:38 +0200 Subject: [PATCH 24/43] Fix genesis patching, improve logs, improve tests --- Cargo.lock | 1 + .../utils/frame/benchmarking-cli/Cargo.toml | 1 + .../benchmarking-cli/src/overhead/cmd.rs | 43 ++++++++++++++----- .../utils/frame/omni-bencher/src/main.rs | 11 ++++- .../omni-bencher/tests/benchmark_works.rs | 1 + 5 files changed, 46 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ccd97bccba239..36802e71dcade 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6289,6 +6289,7 @@ dependencies = [ "subxt-signer", "thiserror", "thousands", + "westend-runtime", ] [[package]] diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index c6fec14ffa6a4..bf4c13fa726cf 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -75,6 +75,7 @@ hex = "0.4.3" [dev-dependencies] cumulus-test-runtime = { workspace = true, default-features = true } substrate-test-runtime = { workspace = true, default-features = true } +westend-runtime = { workspace = true, default-features = true } [features] default = ["rocksdb"] diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 6ea8b5c81ce74..3d93a377f8179 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -333,10 +333,16 @@ impl OverheadCmd { // At this point we know what kind of chain we are dealing with. let chain_type = identify_chain(&metadata, para_id); + // If we are dealing with a parachain, make sure that the para id in genesis will + // match what we expect. + let genesis_patcher = match chain_type { + Parachain(para_id) => + Some(Box::new(move |value| patch_genesis(value, Some(para_id))) as Box<_>), + _ => None, + }; + let client = self.build_client_components::( - state_handler.build_storage::<(ParachainHostFunctions, ExtraHF)>(Some(Box::new( - move |value| patch_genesis(value, para_id), - )))?, + state_handler.build_storage::<(ParachainHostFunctions, ExtraHF)>(genesis_patcher)?, executor, &chain_type, )?; @@ -589,6 +595,10 @@ impl CliConfiguration for OverheadCmd { Some(&self.import_params) } + fn base_path(&self) -> Result> { + Ok(Some(BasePath::new_temp_dir()?)) + } + fn trie_cache_maximum_size(&self) -> Result> { if self.params.enable_trie_cache { Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default()) @@ -596,10 +606,6 @@ impl CliConfiguration for OverheadCmd { Ok(None) } } - - fn base_path(&self) -> Result> { - Ok(Some(BasePath::new_temp_dir()?)) - } } #[cfg(test)] @@ -609,6 +615,19 @@ mod tests { }; use sc_executor::WasmExecutor; + #[test] + fn test_chain_type_relaychain() { + let executor: WasmExecutor = WasmExecutor::builder().build(); + let code_bytes = westend_runtime::WASM_BINARY + .expect("To run this test, build the wasm binary of westend-runtime") + .to_vec(); + let metadata = + super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); + let chain_type = identify_chain(&metadata, None); + assert_eq!(chain_type, ChainType::Relaychain); + assert_eq!(chain_type.requires_proof_recording(), false); + } + #[test] fn test_chain_type_parachain() { let executor: WasmExecutor = WasmExecutor::builder().build(); @@ -617,7 +636,9 @@ mod tests { .to_vec(); let metadata = super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); - assert_eq!(identify_chain(&metadata, Some(100)), ChainType::Parachain(100)); + let chain_type = identify_chain(&metadata, Some(100)); + assert_eq!(chain_type, ChainType::Parachain(100)); + assert!(chain_type.requires_proof_recording()); assert_eq!(identify_chain(&metadata, None), ChainType::Parachain(DEFAULT_PARA_ID)); } @@ -625,10 +646,12 @@ mod tests { fn test_chain_type_custom() { let executor: WasmExecutor = WasmExecutor::builder().build(); let code_bytes = substrate_test_runtime::WASM_BINARY - .expect("To run this test, build the wasm binary of cumulus-test-runtime") + .expect("To run this test, build the wasm binary of substrate-test-runtime") .to_vec(); let metadata = super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); - assert_eq!(identify_chain(&metadata, Some(100)), ChainType::Unknown); + let chain_type = identify_chain(&metadata, None); + assert_eq!(chain_type, ChainType::Unknown); + assert_eq!(chain_type.requires_proof_recording(), false); } } diff --git a/substrate/utils/frame/omni-bencher/src/main.rs b/substrate/utils/frame/omni-bencher/src/main.rs index ef3450add8e40..7d8aa891dc4a0 100644 --- a/substrate/utils/frame/omni-bencher/src/main.rs +++ b/substrate/utils/frame/omni-bencher/src/main.rs @@ -31,7 +31,16 @@ fn main() -> Result<()> { /// Setup logging with `info` as default level. Can be set via `RUST_LOG` env. fn setup_logger() { - let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); + // Disable these log targets because they are spammy. + let unwanted_targets = + &["cranelift_codegen", "wasm_cranelift", "wasmtime_jit", "wasmtime_cranelift", "wasm_jit"]; + + let mut env_filter = + EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); + + for target in unwanted_targets { + env_filter = env_filter.add_directive(format!("{}=off", target).parse().unwrap()); + } tracing_subscriber::fmt() .with_env_filter(env_filter) diff --git a/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs b/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs index 9814e3e7b0d70..2a0709926158c 100644 --- a/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs +++ b/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs @@ -34,6 +34,7 @@ fn benchmark_overhead_works() -> std::result::Result<(), String> { .arg("--weight-path") .arg(base_path) .args(["--warmup", "5", "--repeat", "5"]) + .args(["--para-id", "666"]) .args(["--add", "100", "--mul", "1.2", "--metric", "p75"]) // Only put 5 extrinsics into the block otherwise it takes forever to build it // especially for a non-release builds. From 0b96826a8a3210e3c0fe7f2cc99cb99c693585d3 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Sat, 26 Oct 2024 00:05:16 +0200 Subject: [PATCH 25/43] PRDOC --- prdoc/pr_5891.prdoc | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/prdoc/pr_5891.prdoc b/prdoc/pr_5891.prdoc index 95bfe3871cb77..84c30ac2a80b1 100644 --- a/prdoc/pr_5891.prdoc +++ b/prdoc/pr_5891.prdoc @@ -9,4 +9,27 @@ doc: This adds the benchmark overhead command to the `frame-omni-bencher` library. This allows para- and relay chain teams to generate extrinsic and block base weights. -crates: [ ] +crates: + - name: sc-block-builder + bump: minor + - name: sc-chain-spec + bump: none + - name: polkadot-service + bump: none + - name: frame-benchmarking-cli + bump: minor + - name: cumulus-client-parachain-inherent: + bump: patch + - name: polkadot-cli: + bump: none + - name: polkadot-omni-node-lib: + bump: none + - name: polkadot-omni-node: + bump: none + - name: polkadot-parachain-bin: + bump: none + - name: polkadot: + bump: none + - name: frame-omni-bencher: + bump: minor + From a4b989d4ccab98d727eb9a700293650b8a0dbe46 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Sat, 26 Oct 2024 00:18:29 +0200 Subject: [PATCH 26/43] Add more integration tests --- Cargo.lock | 2 + .../utils/frame/benchmarking-cli/src/lib.rs | 2 +- substrate/utils/frame/omni-bencher/Cargo.toml | 2 + .../omni-bencher/tests/benchmark_works.rs | 112 +++++++++++++++++- 4 files changed, 111 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36802e71dcade..418ee2cf4e667 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6432,7 +6432,9 @@ dependencies = [ "cumulus-test-runtime", "frame-benchmarking-cli", "log", + "sc-chain-spec", "sc-cli", + "sp-genesis-builder", "sp-runtime 31.0.1", "sp-statement-store", "sp-tracing 16.0.0", diff --git a/substrate/utils/frame/benchmarking-cli/src/lib.rs b/substrate/utils/frame/benchmarking-cli/src/lib.rs index 02832a48c6f54..09b12d8716adf 100644 --- a/substrate/utils/frame/benchmarking-cli/src/lib.rs +++ b/substrate/utils/frame/benchmarking-cli/src/lib.rs @@ -30,7 +30,7 @@ pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; pub use machine::{MachineCmd, SUBSTRATE_REFERENCE_HARDWARE}; pub use overhead::{ runtime_utilities::{ - fetch_latest_metadata_from_code_blob, DynamicRemarkBuilder, SubstrateRemarkBuilder, + fetch_latest_metadata_from_code_blob, DynamicRemarkBuilder, SubstrateRemarkBuilder, }, OpaqueBlock, OverheadCmd, }; diff --git a/substrate/utils/frame/omni-bencher/Cargo.toml b/substrate/utils/frame/omni-bencher/Cargo.toml index 6cebbd570b627..6e54c117ba7cd 100644 --- a/substrate/utils/frame/omni-bencher/Cargo.toml +++ b/substrate/utils/frame/omni-bencher/Cargo.toml @@ -26,3 +26,5 @@ tempfile = { workspace = true } assert_cmd = { workspace = true } cumulus-test-runtime = { workspace = true } sp-tracing = { workspace = true, default-features = true } +sp-genesis-builder = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true } \ No newline at end of file diff --git a/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs b/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs index 2a0709926158c..1cc9d73bd4de6 100644 --- a/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs +++ b/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs @@ -15,25 +15,31 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::fs; +use assert_cmd::cargo::cargo_bin; +use std::{ + fs, + path::{Path, PathBuf}, + process::{Command, ExitStatus}, +}; + #[test] -fn benchmark_overhead_works() -> std::result::Result<(), String> { - let tmp_dir = tempfile::tempdir().expect("could not create a temp dir"); +fn benchmark_overhead_runtime_works() -> std::result::Result<(), String> { + let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); let base_path = tmp_dir.path(); let wasm = cumulus_test_runtime::WASM_BINARY.ok_or("WASM binary not available".to_string())?; let runtime_path = base_path.join("runtime.wasm"); let _ = fs::write(&runtime_path, wasm).map_err(|e| format!("Unable to write runtime file: {}", e)); - let path = assert_cmd::cargo::cargo_bin("frame-omni-bencher"); // Invoke `benchmark overhead` with all options to make sure that they are valid. - let status = std::process::Command::new(path) + let status = std::process::Command::new(cargo_bin("frame-omni-bencher")) .args(["v1", "benchmark", "overhead", "--runtime", runtime_path.to_str().unwrap()]) .arg("-d") .arg(base_path) .arg("--weight-path") .arg(base_path) .args(["--warmup", "5", "--repeat", "5"]) + // Exotic para id to see that we are actually patching. .args(["--para-id", "666"]) .args(["--add", "100", "--mul", "1.2", "--metric", "p75"]) // Only put 5 extrinsics into the block otherwise it takes forever to build it @@ -42,11 +48,105 @@ fn benchmark_overhead_works() -> std::result::Result<(), String> { .status() .map_err(|e| format!("command failed: {:?}", e))?; + assert_benchmark_success(status, base_path) +} +#[test] +fn benchmark_overhead_chain_spec_works() -> std::result::Result<(), String> { + let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); + let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path())?; + + let status = create_benchmark_spec_command(&base_path, &chain_spec_path) + .args(["--genesis-builder-policy", "runtime"]) + .args(["--para-id", "666"]) + .status() + .map_err(|e| format!("command failed: {:?}", e))?; + + assert_benchmark_success(status, &base_path) +} + +#[test] +fn benchmark_overhead_chain_spec_works_raw() -> std::result::Result<(), String> { + let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); + let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path())?; + + let status = create_benchmark_spec_command(&base_path, &chain_spec_path) + .args(["--genesis-builder-policy", "spec"]) + .args(["--para-id", "100"]) + .status() + .map_err(|e| format!("command failed: {:?}", e))?; + + assert_benchmark_success(status, &base_path) +} + +#[test] +fn benchmark_overhead_chain_spec_fails_wrong_para_id() -> std::result::Result<(), String> { + let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); + let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path())?; + + let status = create_benchmark_spec_command(&base_path, &chain_spec_path) + .args(["--genesis-builder-policy", "spec"]) + .args(["--para-id", "666"]) + .status() + .map_err(|e| format!("command failed: {:?}", e))?; + + if status.success() { + return Err("Command should have failed!".into()) + } + + // Weight files should not have been created + assert!(!base_path.join("block_weights.rs").exists()); + assert!(!base_path.join("extrinsic_weights.rs").exists()); + Ok(()) +} + +/// Sets up a temporary directory and creates a chain spec file +fn setup_chain_spec(tmp_dir: &Path) -> Result<(PathBuf, PathBuf), String> { + let base_path = tmp_dir.to_path_buf(); + let chain_spec_path = base_path.join("chain_spec.json"); + + let wasm = cumulus_test_runtime::WASM_BINARY.ok_or("WASM binary not available".to_string())?; + + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("tokenSymbol".into(), "UNIT".into()); + properties.insert("tokenDecimals".into(), 12.into()); + + let chain_spec = sc_chain_spec::GenericChainSpec::<()>::builder(wasm, Default::default()) + .with_name("some-chain") + .with_id("some-id") + .with_properties(properties) + .with_chain_type(sc_chain_spec::ChainType::Development) + .with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) + .build(); + + let json = chain_spec.as_json(false).unwrap(); + fs::write(&chain_spec_path, json) + .map_err(|e| format!("Unable to write chain-spec file: {}", e))?; + + Ok((base_path, chain_spec_path)) +} + +/// Creates a Command for the benchmark with common arguments +fn create_benchmark_spec_command(base_path: &Path, chain_spec_path: &Path) -> Command { + let mut cmd = Command::new(cargo_bin("frame-omni-bencher")); + cmd.args(["v1", "benchmark", "overhead", "--chain", chain_spec_path.to_str().unwrap()]) + .arg("-d") + .arg(base_path) + .arg("--weight-path") + .arg(base_path) + .args(["--warmup", "5", "--repeat", "5"]) + .args(["--add", "100", "--mul", "1.2", "--metric", "p75"]) + // Only put 5 extrinsics into the block otherwise it takes forever to build it + .args(["--max-ext-per-block", "5"]); + cmd +} + +/// Checks if the benchmark completed successfully and created weight files +fn assert_benchmark_success(status: ExitStatus, base_path: &Path) -> Result<(), String> { if !status.success() { return Err("Command failed".into()) } - // Weight files have been created. + // Weight files have been created assert!(base_path.join("block_weights.rs").exists()); assert!(base_path.join("extrinsic_weights.rs").exists()); Ok(()) From 0cc2e856698ab3539adfbcd50fead74711334292 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Sun, 27 Oct 2024 12:02:49 +0100 Subject: [PATCH 27/43] Review comments --- .../test/runtime/src/genesis_config_presets.rs | 17 ++++------------- substrate/client/block-builder/src/lib.rs | 8 -------- .../benchmarking-cli/src/extrinsic/bench.rs | 9 +++++---- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/cumulus/test/runtime/src/genesis_config_presets.rs b/cumulus/test/runtime/src/genesis_config_presets.rs index b322d6afbcaf1..89bf53f01c81e 100644 --- a/cumulus/test/runtime/src/genesis_config_presets.rs +++ b/cumulus/test/runtime/src/genesis_config_presets.rs @@ -31,7 +31,7 @@ fn cumulus_test_runtime( endowed_accounts: Vec, id: ParaId, ) -> serde_json::Value { - let config = build_struct_json_patch!( RuntimeGenesisConfig { + let config = build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), }, @@ -43,19 +43,10 @@ fn cumulus_test_runtime( } fn testnet_genesis_with_default_endowed(self_para_id: ParaId) -> serde_json::Value { - let endowed = Sr25519Keyring::iter().map(|x| x.to_account_id()).collect::>(); + let endowed = Sr25519Keyring::well_known().map(|x| x.to_account_id()).collect::>(); - let invulnerables = vec![ - Sr25519Keyring::Alice, - Sr25519Keyring::Bob, - Sr25519Keyring::Charlie, - Sr25519Keyring::Dave, - Sr25519Keyring::Eve, - Sr25519Keyring::Ferdie, - ] - .into_iter() - .map(|x| x.public().into()) - .collect::>(); + let invulnerables = + Sr25519Keyring::invulnerable().map(|x| x.public().into()).collect::>(); cumulus_test_runtime(invulnerables, endowed, self_para_id) } diff --git a/substrate/client/block-builder/src/lib.rs b/substrate/client/block-builder/src/lib.rs index f65a7dbd5f549..d02d0e3218051 100644 --- a/substrate/client/block-builder/src/lib.rs +++ b/substrate/client/block-builder/src/lib.rs @@ -357,14 +357,6 @@ where .map_err(|e| Error::Application(Box::new(e))) } - /// Get the current proof size of the internal recorder. - /// - /// This is a lot more expensive than the provided size estimation functions and should - /// be used with care. - pub fn current_proof_size(&self) -> Option { - self.api.proof_recorder().map(|pr| pr.to_storage_proof().encoded_size()) - } - /// Estimate the size of the block in the current state. /// /// If `include_proof` is `true`, the estimated size of the storage proof will be added diff --git a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index ae14f1bc5cbad..0a44522167a1f 100644 --- a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -17,7 +17,7 @@ //! Contains the core benchmarking logic. -use sc_block_builder::{BlockBuilderApi, BlockBuilderBuilder}; +use sc_block_builder::{BlockBuilderApi, BlockBuilderBuilder, BuiltBlock}; use sc_cli::{Error, Result}; use sc_client_api::UsageProvider; use sp_api::{ApiExt, CallApiAt, Core, ProvideRuntimeApi}; @@ -34,6 +34,7 @@ use sp_runtime::{ use super::ExtrinsicBuilder; use crate::shared::{StatSelect, Stats}; use clap::Args; +use codec::Encode; use log::info; use serde::Serialize; use sp_trie::proof_size_extension::ProofSizeExt; @@ -174,13 +175,13 @@ where None => None, }; - let proof_size = builder.current_proof_size(); - let block = builder.build()?.block; + let BuiltBlock { block, proof, .. } = builder.build()?; Ok(( block, num_ext, - proof_size + proof + .map(|p| p.encoded_size()) .unwrap_or(0) .try_into() .map_err(|_| "Proof size is too large".to_string())?, From 65ae2b2a85f82ccb80d46c3053706e525c5edc38 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Sun, 27 Oct 2024 12:07:55 +0100 Subject: [PATCH 28/43] Reinstate test --- polkadot/tests/benchmark_extrinsic.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/polkadot/tests/benchmark_extrinsic.rs b/polkadot/tests/benchmark_extrinsic.rs index 7f1a37d38e3f6..529eb29362d4d 100644 --- a/polkadot/tests/benchmark_extrinsic.rs +++ b/polkadot/tests/benchmark_extrinsic.rs @@ -32,6 +32,14 @@ fn benchmark_extrinsic_works() { } } +/// `benchmark extrinsic` rejects all non-dev runtimes. +#[test] +fn benchmark_extrinsic_rejects_non_dev_runtimes() { + for runtime in RUNTIMES { + assert!(benchmark_extrinsic(runtime, "system", "remark").is_err()); + } +} + fn benchmark_extrinsic(runtime: &str, pallet: &str, extrinsic: &str) -> Result<(), String> { let status = Command::new(cargo_bin("polkadot")) .args(["benchmark", "extrinsic", "--chain", runtime]) From a2286d8ee9c02ad10275dc8accf8c70e4fbd8ac4 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Sun, 27 Oct 2024 13:03:46 +0100 Subject: [PATCH 29/43] Fix license issue --- .../runtime/src/genesis_config_presets.rs | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/cumulus/test/runtime/src/genesis_config_presets.rs b/cumulus/test/runtime/src/genesis_config_presets.rs index 89bf53f01c81e..26745fadf5011 100644 --- a/cumulus/test/runtime/src/genesis_config_presets.rs +++ b/cumulus/test/runtime/src/genesis_config_presets.rs @@ -1,19 +1,18 @@ -// This file is part of Substrate. - // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . use super::{ AccountId, AuraConfig, AuraId, BalancesConfig, ParachainInfoConfig, RuntimeGenesisConfig, From 88812f4cc673ebda5ac899fdf9ffda0eba54ac8a Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Sun, 27 Oct 2024 13:03:57 +0100 Subject: [PATCH 30/43] Clap improvements --- .../benchmarking-cli/src/overhead/cmd.rs | 101 +++++++-- .../benchmarking-cli/src/pallet/command.rs | 17 +- .../frame/benchmarking-cli/src/pallet/mod.rs | 195 +++++++++++++++++- .../src/shared/genesis_state.rs | 5 +- .../frame/benchmarking-cli/src/shared/mod.rs | 20 -- .../omni-bencher/tests/benchmark_works.rs | 2 +- 6 files changed, 294 insertions(+), 46 deletions(-) diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 3d93a377f8179..0583538676bf2 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -32,10 +32,10 @@ use crate::{ shared::{ genesis_state, genesis_state::{GenesisStateHandler, SpecGenesisSource}, - GenesisBuilderPolicy, HostInfoParams, WeightParams, + HostInfoParams, WeightParams, }, }; -use clap::{Args, Parser}; +use clap::{ArgGroup, Args, Parser}; use codec::Encode; use cumulus_client_parachain_inherent::MockValidationDataInherentDataProvider; use fake_runtime_api::RuntimeApi as FakeRuntimeApi; @@ -76,6 +76,15 @@ const LOG_TARGET: &'static str = "polkadot_sdk_frame::benchmark::overhead"; /// Benchmark the execution overhead per-block and per-extrinsic. #[derive(Debug, Parser)] +#[clap(group( + ArgGroup::new("genesis_source") + .args(["chain", "runtime"]) + .required(true) +), group( + ArgGroup::new("chain_source") + .args(["chain"]) + ) +)] pub struct OverheadCmd { #[allow(missing_docs)] #[clap(flatten)] @@ -118,7 +127,12 @@ pub struct OverheadParams { pub enable_trie_cache: bool, /// Optional runtime blob to use instead of the one from the genesis config. - #[arg(long, value_name = "PATH", conflicts_with = "chain")] + #[arg( + long, + value_name = "PATH", + conflicts_with = "chain", + required_if_eq("genesis_builder", "runtime") + )] pub runtime: Option, /// The preset that we expect to find in the GenesisBuilder runtime API. @@ -133,17 +147,35 @@ pub struct OverheadParams { /// Can be used together with `--chain` to determine whether the /// genesis state should be initialized with the values from the /// provided chain spec or a runtime-provided genesis preset. - #[arg(long, value_enum, conflicts_with = "runtime", alias = "genesis-builder-policy")] + #[arg( + long, + value_enum, + alias = "genesis-builder-policy", + requires_ifs([ + ("spec", "chain_source"), + ("spec-runtime", "chain_source"), + ("spec-genesis", "chain_source"), + ]))] pub genesis_builder: Option, /// Parachain Id to use for parachains. If not specified, the benchmark code will choose /// a para-id and patch the state accordingly. #[arg(long)] pub para_id: Option, +} - /// Runtime name to insert into the weight file template. - #[arg(long, default_value_t = Default::default())] - pub runtime_name: String, +/// How the genesis state for benchmarking should be built. +#[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy, Serialize)] +#[clap(rename_all = "kebab-case")] +pub enum GenesisBuilderPolicy { + /// Let the runtime build the genesis state through its `BuildGenesisConfig` runtime API. + /// This will use the `development` preset by default. + Runtime, + /// Use the runtime from the Spec file to build the genesis state. + SpecRuntime, + /// Use the spec file to build the genesis state. This fails when there is no spec. + #[value(alias = "spec")] + SpecGenesis, } /// Type of a benchmark. @@ -258,11 +290,10 @@ impl OverheadCmd { let genesis_builder_to_source = || match self.params.genesis_builder { Some(GenesisBuilderPolicy::Runtime) | Some(GenesisBuilderPolicy::SpecRuntime) => SpecGenesisSource::Runtime(self.params.genesis_builder_preset.clone()), - Some(GenesisBuilderPolicy::Spec | GenesisBuilderPolicy::SpecGenesis) | None => { + Some(GenesisBuilderPolicy::SpecGenesis) | None => { log::warn!(target: LOG_TARGET, "{WARN_SPEC_GENESIS_CTOR}"); SpecGenesisSource::SpecJson }, - Some(GenesisBuilderPolicy::None) => SpecGenesisSource::None, }; // First handle chain-spec passed in via API parameter. @@ -299,7 +330,7 @@ impl OverheadCmd { return Ok(( GenesisStateHandler::Runtime( runtime_blob, - self.params.genesis_builder_preset.clone(), + Some(self.params.genesis_builder_preset.clone()), ), self.params.para_id, )) @@ -610,9 +641,11 @@ impl CliConfiguration for OverheadCmd { #[cfg(test)] mod tests { - use crate::overhead::cmd::{ - identify_chain, ChainType, ParachainHostFunctions, DEFAULT_PARA_ID, + use crate::{ + overhead::cmd::{identify_chain, ChainType, ParachainHostFunctions, DEFAULT_PARA_ID}, + OverheadCmd, }; + use clap::Parser; use sc_executor::WasmExecutor; #[test] @@ -654,4 +687,48 @@ mod tests { assert_eq!(chain_type, ChainType::Unknown); assert_eq!(chain_type.requires_proof_recording(), false); } + + fn cli_succeed(args: &[&str]) -> Result<(), clap::Error> { + OverheadCmd::try_parse_from(args)?; + Ok(()) + } + + fn cli_fail(args: &[&str]) { + assert!(OverheadCmd::try_parse_from(args).is_err()); + } + + #[test] + fn test_cli_conflicts() -> Result<(), clap::Error> { + // Runtime tests + cli_succeed(&["test", "--runtime", "path/to/runtime", "--genesis-builder", "runtime"])?; + cli_succeed(&["test", "--runtime", "path/to/runtime"])?; + cli_succeed(&[ + "test", + "--runtime", + "path/to/runtime", + "--genesis-builder-preset", + "preset", + ])?; + cli_fail(&["test", "--runtime", "path/to/spec", "--genesis-builder", "spec"]); + cli_fail(&["test", "--runtime", "path/to/spec", "--genesis-builder", "spec-genesis"]); + cli_fail(&["test", "--runtime", "path/to/spec", "--genesis-builder", "spec-runtime"]); + + // Spec tests + cli_succeed(&["test", "--chain", "path/to/spec"])?; + cli_succeed(&["test", "--chain", "path/to/spec", "--genesis-builder", "spec"])?; + cli_succeed(&["test", "--chain", "path/to/spec", "--genesis-builder", "spec-genesis"])?; + cli_succeed(&["test", "--chain", "path/to/spec", "--genesis-builder", "spec-runtime"])?; + cli_fail(&["test", "--chain", "path/to/spec", "--genesis-builder", "none"]); + cli_fail(&["test", "--chain", "path/to/spec", "--genesis-builder", "runtime"]); + cli_fail(&[ + "test", + "--chain", + "path/to/spec", + "--genesis-builder", + "runtime", + "--genesis-builder-preset", + "preset", + ]); + Ok(()) + } } diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index aa9582d09d44c..d3950e0342d7f 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -20,11 +20,10 @@ use super::{ writer, ListOutput, PalletCmd, }; use crate::{ - pallet::types::FetchedCode, + pallet::{types::FetchedCode, GenesisBuilderPolicy}, shared::{ genesis_state, genesis_state::{GenesisStateHandler, SpecGenesisSource, WARN_SPEC_GENESIS_CTOR}, - GenesisBuilderPolicy, }, }; use codec::{Decode, Encode}; @@ -179,7 +178,7 @@ impl PalletCmd { let genesis_builder_to_source = || match self.genesis_builder { Some(GenesisBuilderPolicy::Runtime) | Some(GenesisBuilderPolicy::SpecRuntime) => SpecGenesisSource::Runtime(self.genesis_builder_preset.clone()), - Some(GenesisBuilderPolicy::Spec | GenesisBuilderPolicy::SpecGenesis) | None => { + Some(GenesisBuilderPolicy::SpecGenesis) | None => { log::warn!(target: LOG_TARGET, "{WARN_SPEC_GENESIS_CTOR}"); SpecGenesisSource::SpecJson }, @@ -214,10 +213,14 @@ impl PalletCmd { log::debug!("Initializing state handler with runtime from path: {:?}", runtime_path); let runtime_blob = fs::read(runtime_path)?; - return Ok(GenesisStateHandler::Runtime( - runtime_blob, - self.genesis_builder_preset.clone(), - )) + return if let Some(GenesisBuilderPolicy::None) = self.genesis_builder { + Ok(GenesisStateHandler::Runtime(runtime_blob, None)) + } else { + Ok(GenesisStateHandler::Runtime( + runtime_blob, + Some(self.genesis_builder_preset.clone()), + )) + } }; Err("Neither a runtime nor a chain-spec were specified".to_string().into()) diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs index 13d501b403dbb..4b0ebc81e472f 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -19,8 +19,9 @@ mod command; mod types; mod writer; -use crate::shared::{GenesisBuilderPolicy, HostInfoParams}; -use clap::ValueEnum; +use crate::shared::HostInfoParams; +use clap::{ArgGroup, ValueEnum}; +use frame_support::Serialize; use sc_cli::{ WasmExecutionMethod, WasmtimeInstantiationStrategy, DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, DEFAULT_WASM_EXECUTION_METHOD, @@ -44,6 +45,15 @@ pub enum ListOutput { /// Benchmark the extrinsic weight of FRAME Pallets. #[derive(Debug, clap::Parser)] +#[clap(group( + ArgGroup::new("genesis_source") + .args(["chain", "runtime"]) + .required(true) +), group( + ArgGroup::new("chain_source") + .args(["chain"]) +) +)] pub struct PalletCmd { /// Select a FRAME Pallet to benchmark, or `*` for all (in which case `extrinsic` must be `*`). #[arg(short, long, value_parser = parse_pallet_name, required_unless_present_any = ["list", "json_input", "all"], default_value_if("all", "true", Some("*".into())))] @@ -172,7 +182,7 @@ pub struct PalletCmd { pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, /// Optional runtime blob to use instead of the one from the genesis config. - #[arg(long, conflicts_with = "chain")] + #[arg(long, conflicts_with = "chain", required_if_eq("genesis_builder", "runtime"))] pub runtime: Option, /// Do not fail if there are unknown but also unused host functions in the runtime. @@ -182,7 +192,16 @@ pub struct PalletCmd { /// How to construct the genesis state. /// /// Uses `GenesisBuilderPolicy::Spec` by default. - #[arg(long, value_enum, alias = "genesis-builder-policy", conflicts_with = "runtime")] + #[arg( + long, + value_enum, + alias = "genesis-builder-policy", + requires_ifs([ + ("spec", "chain_source"), + ("spec-runtime", "chain_source"), + ("spec-genesis", "chain_source"), + ]) + )] pub genesis_builder: Option, /// The preset that we expect to find in the GenesisBuilder runtime API. @@ -264,3 +283,171 @@ pub struct PalletCmd { #[arg(long)] disable_proof_recording: bool, } + +/// How the genesis state for benchmarking should be built. +#[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy, Serialize)] +#[clap(rename_all = "kebab-case")] +pub enum GenesisBuilderPolicy { + /// Do not provide any genesis state. + /// + /// Benchmarks are advised to function with this, since they should setup their own required + /// state. However, to keep backwards compatibility, this is not the default. + None, + /// Let the runtime build the genesis state through its `BuildGenesisConfig` runtime API. + /// This will use the `development` preset by default. + Runtime, + /// Use the runtime from the Spec file to build the genesis state. + SpecRuntime, + /// Use the spec file to build the genesis state. This fails when there is no spec. + #[value(alias = "spec")] + SpecGenesis, +} + +#[cfg(test)] +mod tests { + use crate::pallet::PalletCmd; + use clap::Parser; + + fn cli_succeed(args: &[&str]) -> Result<(), clap::Error> { + PalletCmd::try_parse_from(args)?; + Ok(()) + } + + fn cli_fail(args: &[&str]) { + assert!(PalletCmd::try_parse_from(args).is_err()); + } + + #[test] + fn test_cli_conflicts() -> Result<(), clap::Error> { + // Runtime tests + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/runtime", + "--genesis-builder", + "runtime", + ])?; + cli_succeed(&["test", "--extrinsic", "", "--pallet", "", "--runtime", "path/to/runtime"])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/runtime", + "--genesis-builder-preset", + "preset", + ])?; + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/spec", + "--genesis-builder", + "spec", + ]); + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/spec", + "--genesis-builder", + "spec-genesis", + ]); + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/spec", + "--genesis-builder", + "spec-runtime", + ]); + cli_fail(&["test", "--runtime", "path/to/spec", "--genesis-builder", "spec-genesis"]); + + // Spec tests + cli_succeed(&["test", "--extrinsic", "", "--pallet", "", "--chain", "path/to/spec"])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "spec", + ])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "spec-genesis", + ])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "spec-runtime", + ])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "none", + ])?; + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "runtime", + ]); + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "runtime", + "--genesis-builder-preset", + "preset", + ]); + Ok(()) + } +} diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs index 379c25f7d7e58..1c93d102d1657 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -44,7 +44,7 @@ pub enum SpecGenesisSource { pub enum GenesisStateHandler { ChainSpec(Box, SpecGenesisSource), - Runtime(Vec, String), + Runtime(Vec, Option), } impl GenesisStateHandler { @@ -71,8 +71,9 @@ impl GenesisStateHandler { .map_err(|e| format!("{ERROR_CANNOT_BUILD_GENESIS}\nError: {e}").into()), SpecGenesisSource::None => Ok(Storage::default()), }, - GenesisStateHandler::Runtime(code_bytes, preset) => + GenesisStateHandler::Runtime(code_bytes, Some(preset)) => genesis_from_code::(code_bytes.as_slice(), preset, json_patcher), + GenesisStateHandler::Runtime(_, None) => Ok(Storage::default()), } } diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs b/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs index 5acd346f10a10..6c9c74e0312c9 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs @@ -133,23 +133,3 @@ impl HostInfoParams { gather_sysinfo().cpu.unwrap_or(self.cpuname_fallback.clone()) } } - -/// How the genesis state for benchmarking should be built. -#[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy, Serialize)] -#[clap(rename_all = "kebab-case")] -pub enum GenesisBuilderPolicy { - /// Do not provide any genesis state. - /// - /// Benchmarks are advised to function with this, since they should setup their own required - /// state. However, to keep backwards compatibility, this is not the default. - None, - /// Let the runtime build the genesis state through its `BuildGenesisConfig` runtime API. - /// This will use the `development` preset by default. - Runtime, - /// Use the runtime from the Spec file to build the genesis state. - SpecRuntime, - /// Use the spec file to build the genesis state. This fails when there is no spec. - SpecGenesis, - /// Same as `SpecGenesis` - only here for backwards compatibility. - Spec, -} diff --git a/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs b/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs index 1cc9d73bd4de6..fd02e27f00476 100644 --- a/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs +++ b/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs @@ -56,7 +56,7 @@ fn benchmark_overhead_chain_spec_works() -> std::result::Result<(), String> { let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path())?; let status = create_benchmark_spec_command(&base_path, &chain_spec_path) - .args(["--genesis-builder-policy", "runtime"]) + .args(["--genesis-builder-policy", "spec-runtime"]) .args(["--para-id", "666"]) .status() .map_err(|e| format!("command failed: {:?}", e))?; From 2a4726e80d5dfed19112a3536b72c13507a99441 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Sun, 27 Oct 2024 16:03:51 +0100 Subject: [PATCH 31/43] Fix all balances merge in cumulus-test-runtime --- cumulus/test/service/src/chain_spec.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index 0e8b3dc1e0988..3d4e4dca5f8df 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -50,9 +50,26 @@ pub fn get_chain_spec_with_extra_endowed( extra_endowed_accounts: Vec, code: &[u8], ) -> ChainSpec { + let runtime_caller = GenesisConfigBuilderRuntimeCaller::::new(code); + let mut development_preset = runtime_caller + .get_named_preset(Some(&sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET.to_string())) + .expect("development preset is available on test runtime; qed"); + + // Extract existing balances + let existing_balances = development_preset + .get("balances") + .and_then(|b| b.get("balances")) + .and_then(|b| b.as_array()) + .cloned() + .unwrap_or_default(); + + // Create new balances by combining existing and extra accounts + let mut all_balances = existing_balances; + all_balances.extend(extra_endowed_accounts.into_iter().map(|a| json!([a, 1u64 << 60]))); + let mut patch_json = json!({ "balances": { - "balances": extra_endowed_accounts.into_iter().map(|a| (a, 1u64 << 60)).collect::>(), + "balances": all_balances, } }); @@ -68,11 +85,6 @@ pub fn get_chain_spec_with_extra_endowed( ); }; - let runtime_caller = GenesisConfigBuilderRuntimeCaller::::new(code); - let mut development_preset = runtime_caller - .get_named_preset(Some(&sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET.to_string())) - .expect("development preset is available on test runtime; qed"); - sc_chain_spec::json_merge(&mut development_preset, patch_json.into()); ChainSpec::builder( From 3aeef25dcf365ec27a79473703fc14d4f720591a Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Sun, 27 Oct 2024 16:04:54 +0100 Subject: [PATCH 32/43] fmt --- templates/solochain/node/src/command.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/solochain/node/src/command.rs b/templates/solochain/node/src/command.rs index c12a022f62d4f..1c23e395ede93 100644 --- a/templates/solochain/node/src/command.rs +++ b/templates/solochain/node/src/command.rs @@ -149,7 +149,7 @@ pub fn run() -> sc_cli::Result<()> { inherent_benchmark_data()?, Vec::new(), &ext_builder, - false + false, ) }, BenchmarkCmd::Extrinsic(cmd) => { From 420a105997768dc651e0d27bcecb820a17880b53 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Sun, 27 Oct 2024 23:08:12 +0100 Subject: [PATCH 33/43] Taplo & Zepter --- cumulus/test/runtime/Cargo.toml | 4 +-- .../cli/tests/benchmark_overhead_works.rs | 2 +- .../utils/frame/benchmarking-cli/Cargo.toml | 7 +++-- .../src/overhead/fake_runtime_api.rs | 29 ++++++++++--------- .../src/shared/genesis_state.rs | 1 - substrate/utils/frame/omni-bencher/Cargo.toml | 2 +- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index f6a95bf16010f..8117e6e697096 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -78,6 +78,7 @@ std = [ "pallet-transaction-payment/std", "parachain-info/std", "scale-info/std", + "serde_json/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", @@ -85,14 +86,13 @@ std = [ "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", - "serde_json/std", - "sp-keyring/std" ] increment-spec-version = [] elastic-scaling = [] diff --git a/substrate/bin/node/cli/tests/benchmark_overhead_works.rs b/substrate/bin/node/cli/tests/benchmark_overhead_works.rs index b246167f2c447..248d513dcdd4f 100644 --- a/substrate/bin/node/cli/tests/benchmark_overhead_works.rs +++ b/substrate/bin/node/cli/tests/benchmark_overhead_works.rs @@ -29,7 +29,7 @@ fn benchmark_overhead_works() { // Only put 10 extrinsics into the block otherwise it takes forever to build it // especially for a non-release build. let status = Command::new(cargo_bin("substrate-node")) - .args(&["benchmark", "overhead", "--dev", "-d"]) + .args(&["benchmark", "overhead", "--chain", "dev", "-d"]) .arg(base_path) .arg("--weight-path") .arg(base_path) diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index bf4c13fa726cf..d8613d760bb4f 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -63,7 +63,7 @@ sp-version = { workspace = true, default-features = true } sp-timestamp = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } sp-wasm-interface = { workspace = true, default-features = true } -subxt = { workspace = true, features = ["substrate-compat", "native"] } +subxt = { workspace = true, features = ["native", "substrate-compat"] } subxt-signer = { workspace = true, features = ["unstable-eth"] } cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } cumulus-client-parachain-inherent = { workspace = true, default-features = true } @@ -83,10 +83,11 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks", "sc-client-db/runtime-benchmarks", "sc-service/runtime-benchmarks", "sp-runtime/runtime-benchmarks", - "polkadot-parachain-primitives/runtime-benchmarks", - "polkadot-primitives/runtime-benchmarks" + "westend-runtime/runtime-benchmarks", ] rocksdb = ["sc-cli/rocksdb", "sc-client-db/rocksdb"] diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/fake_runtime_api.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/fake_runtime_api.rs index 10187383d9722..653908a5a205f 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/fake_runtime_api.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/fake_runtime_api.rs @@ -1,18 +1,19 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// This file is part of Substrate. -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! A fake runtime struct that allows us to instantiate a client. //! Has all the required runtime APIs implemented to satisfy trait bounds, diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs index 1c93d102d1657..274d415cfcb80 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -14,7 +14,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -// limitations under the License. use crate::overhead::cmd::ParachainExtension; use sc_chain_spec::{ChainSpec, GenericChainSpec, GenesisConfigBuilderRuntimeCaller}; diff --git a/substrate/utils/frame/omni-bencher/Cargo.toml b/substrate/utils/frame/omni-bencher/Cargo.toml index 6e54c117ba7cd..345a7288d45bf 100644 --- a/substrate/utils/frame/omni-bencher/Cargo.toml +++ b/substrate/utils/frame/omni-bencher/Cargo.toml @@ -27,4 +27,4 @@ assert_cmd = { workspace = true } cumulus-test-runtime = { workspace = true } sp-tracing = { workspace = true, default-features = true } sp-genesis-builder = { workspace = true, default-features = true } -sc-chain-spec = { workspace = true } \ No newline at end of file +sc-chain-spec = { workspace = true } From e3afe94e7947952ae5f42e41b7ca819f37792b80 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 28 Oct 2024 10:14:44 +0100 Subject: [PATCH 34/43] Bring back `--dev`. --- .../cli/tests/benchmark_overhead_works.rs | 2 +- .../benchmarking-cli/src/overhead/cmd.rs | 22 +++++++--- .../benchmarking-cli/src/pallet/command.rs | 44 +++++++++++++------ .../frame/benchmarking-cli/src/pallet/mod.rs | 7 +-- 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/substrate/bin/node/cli/tests/benchmark_overhead_works.rs b/substrate/bin/node/cli/tests/benchmark_overhead_works.rs index 248d513dcdd4f..b246167f2c447 100644 --- a/substrate/bin/node/cli/tests/benchmark_overhead_works.rs +++ b/substrate/bin/node/cli/tests/benchmark_overhead_works.rs @@ -29,7 +29,7 @@ fn benchmark_overhead_works() { // Only put 10 extrinsics into the block otherwise it takes forever to build it // especially for a non-release build. let status = Command::new(cargo_bin("substrate-node")) - .args(&["benchmark", "overhead", "--chain", "dev", "-d"]) + .args(&["benchmark", "overhead", "--dev", "-d"]) .arg(base_path) .arg("--weight-path") .arg(base_path) diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 0583538676bf2..5737c9ddefc03 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -35,7 +35,7 @@ use crate::{ HostInfoParams, WeightParams, }, }; -use clap::{ArgGroup, Args, Parser}; +use clap::{error::ErrorKind, ArgGroup, Args, CommandFactory, Parser}; use codec::Encode; use cumulus_client_parachain_inherent::MockValidationDataInherentDataProvider; use fake_runtime_api::RuntimeApi as FakeRuntimeApi; @@ -77,10 +77,6 @@ const LOG_TARGET: &'static str = "polkadot_sdk_frame::benchmark::overhead"; /// Benchmark the execution overhead per-block and per-extrinsic. #[derive(Debug, Parser)] #[clap(group( - ArgGroup::new("genesis_source") - .args(["chain", "runtime"]) - .required(true) -), group( ArgGroup::new("chain_source") .args(["chain"]) ) @@ -339,6 +335,20 @@ impl OverheadCmd { Err("Neither a runtime nor a chain-spec were specified".to_string().into()) } + pub fn check_args(&self, chain_spec: &Option>) { + if chain_spec.is_none() && + self.params.runtime.is_none() && + self.shared_params.chain.is_none() + { + let mut cmd = OverheadCmd::command(); + cmd.error( + ErrorKind::MissingRequiredArgument, + "Provide either a runtime via `--runtime` or a chain spec via `--chain`", + ) + .exit(); + } + } + /// Run the benchmark overhead command. pub fn run_with_extrinsic_builder_and_spec( &self, @@ -351,6 +361,8 @@ impl OverheadCmd { Block: BlockT, ExtraHF: HostFunctions, { + self.check_args(&chain_spec); + let (state_handler, para_id) = self.state_handler_from_cli::<(ParachainHostFunctions, ExtraHF)>(chain_spec)?; diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index d3950e0342d7f..2ceedc6dbdde8 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -26,6 +26,7 @@ use crate::{ genesis_state::{GenesisStateHandler, SpecGenesisSource, WARN_SPEC_GENESIS_CTOR}, }, }; +use clap::{error::ErrorKind, CommandFactory}; use codec::{Decode, Encode}; use frame_benchmarking::{ Analysis, BenchmarkBatch, BenchmarkBatchSplitResults, BenchmarkList, BenchmarkParameter, @@ -235,7 +236,8 @@ impl PalletCmd { Hasher: Hash, ExtraHostFunctions: HostFunctions, { - self.check_args()?; + self.check_args(&chain_spec); + let _d = self.execution.as_ref().map(|exec| { // We print the error at the end, since there is often A LOT of output. sp_core::defer::DeferGuard::new(move || { @@ -905,36 +907,52 @@ impl PalletCmd { } /// Sanity check the CLI arguments. - fn check_args(&self) -> Result<()> { + fn check_args(&self, chain_spec: &Option>) { if self.runtime.is_some() && self.shared_params.chain.is_some() { unreachable!("Clap should not allow both `--runtime` and `--chain` to be provided.") } + let abort_with_error = |error_kind: ErrorKind, msg: String| { + let mut cmd = PalletCmd::command(); + cmd.error(error_kind, msg).exit(); + }; + + if chain_spec.is_none() && self.runtime.is_none() && self.shared_params.chain.is_none() { + abort_with_error( + ErrorKind::MissingRequiredArgument, + "Provide either a runtime via `--runtime` or a chain spec via `--chain`" + .to_string(), + ) + } + if let Some(output_path) = &self.output { if !output_path.is_dir() && output_path.file_name().is_none() { - return Err(format!( - "Output path is neither a directory nor a file: {output_path:?}" - ) - .into()) + abort_with_error( + ErrorKind::InvalidValue, + format!("Output path is neither a directory nor a file: {output_path:?}"), + ); } } if let Some(header_file) = &self.header { if !header_file.is_file() { - return Err(format!("Header file could not be found: {header_file:?}").into()) + abort_with_error( + ErrorKind::InvalidValue, + format!("Header file could not be found: {header_file:?}"), + ); }; } if let Some(handlebars_template_file) = &self.template { if !handlebars_template_file.is_file() { - return Err(format!( - "Handlebars template file could not be found: {handlebars_template_file:?}" - ) - .into()) + abort_with_error( + ErrorKind::InvalidValue, + format!( + "Handlebars template file could not be found: {handlebars_template_file:?}" + ), + ); }; } - - Ok(()) } } diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs index 4b0ebc81e472f..b7924c0c6f0c0 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -46,14 +46,9 @@ pub enum ListOutput { /// Benchmark the extrinsic weight of FRAME Pallets. #[derive(Debug, clap::Parser)] #[clap(group( - ArgGroup::new("genesis_source") - .args(["chain", "runtime"]) - .required(true) -), group( ArgGroup::new("chain_source") .args(["chain"]) -) -)] +))] pub struct PalletCmd { /// Select a FRAME Pallet to benchmark, or `*` for all (in which case `extrinsic` must be `*`). #[arg(short, long, value_parser = parse_pallet_name, required_unless_present_any = ["list", "json_input", "all"], default_value_if("all", "true", Some("*".into())))] From 0ad7cd9f7cd08e20e9c233fbefe7025f083ef0a8 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 28 Oct 2024 16:30:41 +0100 Subject: [PATCH 35/43] Apply suggestions from code review Co-authored-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> --- cumulus/test/runtime/src/genesis_config_presets.rs | 5 ++--- substrate/utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../utils/frame/benchmarking-cli/src/shared/genesis_state.rs | 4 ++++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cumulus/test/runtime/src/genesis_config_presets.rs b/cumulus/test/runtime/src/genesis_config_presets.rs index 26745fadf5011..6cf56ef5363fd 100644 --- a/cumulus/test/runtime/src/genesis_config_presets.rs +++ b/cumulus/test/runtime/src/genesis_config_presets.rs @@ -30,15 +30,14 @@ fn cumulus_test_runtime( endowed_accounts: Vec, id: ParaId, ) -> serde_json::Value { - let config = build_struct_json_patch!(RuntimeGenesisConfig { + build_struct_json_patch!(RuntimeGenesisConfig { balances: BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), }, sudo: SudoConfig { key: Some(Sr25519Keyring::Alice.public().into()) }, parachain_info: ParachainInfoConfig { parachain_id: id }, aura: AuraConfig { authorities: invulnerables }, - }); - serde_json::to_value(config).expect("Could not build genesis config.") + }) } fn testnet_genesis_with_default_endowed(self_para_id: ParaId) -> serde_json::Value { diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index d8613d760bb4f..504e38b678cc9 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -70,7 +70,7 @@ cumulus-client-parachain-inherent = { workspace = true, default-features = true polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } gethostname = { workspace = true } -hex = "0.4.3" +hex = { workspace = true, default-features = true } [dev-dependencies] cumulus-test-runtime = { workspace = true, default-features = true } diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs index 274d415cfcb80..15aeca4e5073e 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -35,12 +35,16 @@ generate the genesis state is deprecated. Please remove the `--chain`/`--dev`/`- point `--runtime` to your runtime blob and set `--genesis-builder=runtime`. This warning may \ become a hard error any time after December 2024."; +/// Defines how the chain specification shall be used to build the genesis storage. pub enum SpecGenesisSource { Runtime(String), + /// Use provided chain-specification JSON file. SpecJson, + /// Use default storage. None, } +/// Defines how the genesis storage shall be built. pub enum GenesisStateHandler { ChainSpec(Box, SpecGenesisSource), Runtime(Vec, Option), From 8589d4008065997d3d09586124f7e835f5080461 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 28 Oct 2024 16:42:14 +0100 Subject: [PATCH 36/43] cmd -> command --- .../benchmarking-cli/src/overhead/{cmd.rs => command.rs} | 4 ++-- substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs | 4 ++-- .../frame/benchmarking-cli/src/overhead/runtime_utilities.rs | 2 +- .../utils/frame/benchmarking-cli/src/overhead/template.rs | 2 +- .../utils/frame/benchmarking-cli/src/shared/genesis_state.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) rename substrate/utils/frame/benchmarking-cli/src/overhead/{cmd.rs => command.rs} (99%) diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs similarity index 99% rename from substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs rename to substrate/utils/frame/benchmarking-cli/src/overhead/command.rs index 5737c9ddefc03..70773d812bca9 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs @@ -25,7 +25,7 @@ use crate::{ ExtrinsicBuilder, }, overhead::{ - cmd::ChainType::{Parachain, Relaychain, Unknown}, + command::ChainType::{Parachain, Relaychain, Unknown}, fake_runtime_api, template::TemplateData, }, @@ -654,7 +654,7 @@ impl CliConfiguration for OverheadCmd { #[cfg(test)] mod tests { use crate::{ - overhead::cmd::{identify_chain, ChainType, ParachainHostFunctions, DEFAULT_PARA_ID}, + overhead::command::{identify_chain, ChainType, ParachainHostFunctions, DEFAULT_PARA_ID}, OverheadCmd, }; use clap::Parser; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs index 74f56c6437855..2e37a3bd6e6c5 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs @@ -15,9 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub mod cmd; +pub mod command; pub mod template; -pub use cmd::{OpaqueBlock, OverheadCmd}; +pub use command::{OpaqueBlock, OverheadCmd}; mod fake_runtime_api; pub mod runtime_utilities; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs index 3d3a719c9497b..e3c69dc4a417a 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs @@ -212,7 +212,7 @@ impl<'a, 'b, HF: HostFunctions> RuntimeCaller<'a, 'b, HF> { #[cfg(test)] mod tests { - use crate::overhead::cmd::ParachainHostFunctions; + use crate::overhead::command::ParachainHostFunctions; use codec::Decode; use sc_executor::WasmExecutor; use sp_version::RuntimeVersion; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/template.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/template.rs index a515295968421..08227607951b0 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/template.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/template.rs @@ -26,7 +26,7 @@ use serde::Serialize; use std::{env, fs, path::PathBuf}; use crate::{ - overhead::cmd::{BenchmarkType, OverheadParams}, + overhead::command::{BenchmarkType, OverheadParams}, shared::{Stats, UnderscoreHelper}, }; diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs index 15aeca4e5073e..94f994681196b 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::overhead::cmd::ParachainExtension; +use crate::overhead::command::ParachainExtension; use sc_chain_spec::{ChainSpec, GenericChainSpec, GenesisConfigBuilderRuntimeCaller}; use sc_cli::Result; use serde_json::Value; From 2eaec10b0a4ff72c233caf24562257dc78948e60 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 29 Oct 2024 08:14:46 +0100 Subject: [PATCH 37/43] Move measuring to closure, fix prdoc --- prdoc/pr_5891.prdoc | 14 ++++---- .../benchmarking-cli/src/extrinsic/bench.rs | 32 ++++++++----------- .../src/shared/genesis_state.rs | 4 +-- .../omni-bencher/tests/benchmark_works.rs | 24 +++++++++++--- 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/prdoc/pr_5891.prdoc b/prdoc/pr_5891.prdoc index 84c30ac2a80b1..3634b786b1221 100644 --- a/prdoc/pr_5891.prdoc +++ b/prdoc/pr_5891.prdoc @@ -18,18 +18,18 @@ crates: bump: none - name: frame-benchmarking-cli bump: minor - - name: cumulus-client-parachain-inherent: + - name: cumulus-client-parachain-inherent bump: patch - - name: polkadot-cli: + - name: polkadot-cli bump: none - - name: polkadot-omni-node-lib: + - name: polkadot-omni-node-lib bump: none - - name: polkadot-omni-node: + - name: polkadot-omni-node bump: none - - name: polkadot-parachain-bin: + - name: polkadot-parachain-bin bump: none - - name: polkadot: + - name: polkadot bump: none - - name: frame-omni-bencher: + - name: frame-omni-bencher bump: minor diff --git a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index 0a44522167a1f..0693db0dbbdd8 100644 --- a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -193,8 +193,8 @@ where let mut record = BenchRecord::new(); let genesis = self.client.info().genesis_hash; - info!("Running {} warmups...", self.params.warmup); - for _ in 0..self.params.warmup { + let measure_block = || -> Result { + let block = block.clone(); let mut runtime_api = self.client.runtime_api(); if self.record_proof { runtime_api.record_proof(); @@ -203,31 +203,25 @@ where .expect("Proof recording is enabled in the line above; qed."); runtime_api.register_extension(ProofSizeExt::new(recorder)); } + let start = Instant::now(); + runtime_api - .execute_block(genesis, block.clone()) + .execute_block(genesis, block) .map_err(|e| Error::Client(RuntimeApiError(e)))?; + + Ok(start.elapsed().as_nanos()) + }; + + info!("Running {} warmups...", self.params.warmup); + for _ in 0..self.params.warmup { + let _ = measure_block()?; } info!("Executing block {} times", self.params.repeat); // Interesting part here: // Execute a block multiple times and record each execution time. for _ in 0..self.params.repeat { - let block = block.clone(); - let mut runtime_api = self.client.runtime_api(); - if self.record_proof { - runtime_api.record_proof(); - let recorder = runtime_api - .proof_recorder() - .expect("Proof recording is enabled in the line above; qed."); - runtime_api.register_extension(ProofSizeExt::new(recorder)); - } - let start = Instant::now(); - - runtime_api - .execute_block(genesis, block) - .map_err(|e| Error::Client(RuntimeApiError(e)))?; - - let elapsed = start.elapsed().as_nanos(); + let elapsed = measure_block()?; record.push(elapsed as u64); } diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs index 94f994681196b..1ca3e36d25ad2 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -37,6 +37,7 @@ become a hard error any time after December 2024."; /// Defines how the chain specification shall be used to build the genesis storage. pub enum SpecGenesisSource { + /// Use preset provided by the runtime embedded in the chain specification. Runtime(String), /// Use provided chain-specification JSON file. SpecJson, @@ -117,8 +118,7 @@ fn genesis_from_code( EHF, )>::new(code); - let mut preset_json = - genesis_config_caller.get_named_preset(Some(&genesis_builder_preset.to_string()))?; + let mut preset_json = genesis_config_caller.get_named_preset(Some(genesis_builder_preset))?; if let Some(patcher) = storage_patcher { preset_json = patcher(preset_json); } diff --git a/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs b/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs index fd02e27f00476..fb1687639639e 100644 --- a/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs +++ b/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs @@ -53,7 +53,7 @@ fn benchmark_overhead_runtime_works() -> std::result::Result<(), String> { #[test] fn benchmark_overhead_chain_spec_works() -> std::result::Result<(), String> { let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); - let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path())?; + let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path(), false)?; let status = create_benchmark_spec_command(&base_path, &chain_spec_path) .args(["--genesis-builder-policy", "spec-runtime"]) @@ -64,10 +64,24 @@ fn benchmark_overhead_chain_spec_works() -> std::result::Result<(), String> { assert_benchmark_success(status, &base_path) } +#[test] +fn benchmark_overhead_chain_spec_works_plain_spec() -> std::result::Result<(), String> { + let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); + let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path(), false)?; + + let status = create_benchmark_spec_command(&base_path, &chain_spec_path) + .args(["--genesis-builder-policy", "spec"]) + .args(["--para-id", "100"]) + .status() + .map_err(|e| format!("command failed: {:?}", e))?; + + assert_benchmark_success(status, &base_path) +} + #[test] fn benchmark_overhead_chain_spec_works_raw() -> std::result::Result<(), String> { let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); - let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path())?; + let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path(), true)?; let status = create_benchmark_spec_command(&base_path, &chain_spec_path) .args(["--genesis-builder-policy", "spec"]) @@ -81,7 +95,7 @@ fn benchmark_overhead_chain_spec_works_raw() -> std::result::Result<(), String> #[test] fn benchmark_overhead_chain_spec_fails_wrong_para_id() -> std::result::Result<(), String> { let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); - let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path())?; + let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path(), false)?; let status = create_benchmark_spec_command(&base_path, &chain_spec_path) .args(["--genesis-builder-policy", "spec"]) @@ -100,7 +114,7 @@ fn benchmark_overhead_chain_spec_fails_wrong_para_id() -> std::result::Result<() } /// Sets up a temporary directory and creates a chain spec file -fn setup_chain_spec(tmp_dir: &Path) -> Result<(PathBuf, PathBuf), String> { +fn setup_chain_spec(tmp_dir: &Path, raw: bool) -> Result<(PathBuf, PathBuf), String> { let base_path = tmp_dir.to_path_buf(); let chain_spec_path = base_path.join("chain_spec.json"); @@ -118,7 +132,7 @@ fn setup_chain_spec(tmp_dir: &Path) -> Result<(PathBuf, PathBuf), String> { .with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) .build(); - let json = chain_spec.as_json(false).unwrap(); + let json = chain_spec.as_json(raw).unwrap(); fs::write(&chain_spec_path, json) .map_err(|e| format!("Unable to write chain-spec file: {}", e))?; From ddc1754c13102f723d292723048f003dbfe43668 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 29 Oct 2024 09:55:56 +0100 Subject: [PATCH 38/43] Move more validation back to code --- .../benchmarking-cli/src/overhead/command.rs | 56 ++--- .../benchmarking-cli/src/pallet/command.rs | 199 ++++++++++++++++-- .../frame/benchmarking-cli/src/pallet/mod.rs | 166 +-------------- 3 files changed, 218 insertions(+), 203 deletions(-) diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs index 70773d812bca9..80f13c3de272c 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs @@ -35,7 +35,7 @@ use crate::{ HostInfoParams, WeightParams, }, }; -use clap::{error::ErrorKind, ArgGroup, Args, CommandFactory, Parser}; +use clap::{error::ErrorKind, Args, CommandFactory, Parser}; use codec::Encode; use cumulus_client_parachain_inherent::MockValidationDataInherentDataProvider; use fake_runtime_api::RuntimeApi as FakeRuntimeApi; @@ -76,11 +76,6 @@ const LOG_TARGET: &'static str = "polkadot_sdk_frame::benchmark::overhead"; /// Benchmark the execution overhead per-block and per-extrinsic. #[derive(Debug, Parser)] -#[clap(group( - ArgGroup::new("chain_source") - .args(["chain"]) - ) -)] pub struct OverheadCmd { #[allow(missing_docs)] #[clap(flatten)] @@ -143,15 +138,7 @@ pub struct OverheadParams { /// Can be used together with `--chain` to determine whether the /// genesis state should be initialized with the values from the /// provided chain spec or a runtime-provided genesis preset. - #[arg( - long, - value_enum, - alias = "genesis-builder-policy", - requires_ifs([ - ("spec", "chain_source"), - ("spec-runtime", "chain_source"), - ("spec-genesis", "chain_source"), - ]))] + #[arg(long, value_enum, alias = "genesis-builder-policy")] pub genesis_builder: Option, /// Parachain Id to use for parachains. If not specified, the benchmark code will choose @@ -335,18 +322,32 @@ impl OverheadCmd { Err("Neither a runtime nor a chain-spec were specified".to_string().into()) } - pub fn check_args(&self, chain_spec: &Option>) { + fn check_args( + &self, + chain_spec: &Option>, + ) -> std::result::Result<(), (ErrorKind, String)> { if chain_spec.is_none() && self.params.runtime.is_none() && self.shared_params.chain.is_none() { - let mut cmd = OverheadCmd::command(); - cmd.error( + return Err(( ErrorKind::MissingRequiredArgument, - "Provide either a runtime via `--runtime` or a chain spec via `--chain`", - ) - .exit(); + "Provide either a runtime via `--runtime` or a chain spec via `--chain`" + .to_string(), + )) } + + match self.params.genesis_builder { + Some(GenesisBuilderPolicy::SpecGenesis | GenesisBuilderPolicy::SpecRuntime) => + if chain_spec.is_none() && self.shared_params.chain.is_none() { + return Err(( + ErrorKind::MissingRequiredArgument, + "Provide a chain spec via `--chain`.".to_string(), + )) + }, + _ => {}, + }; + Ok(()) } /// Run the benchmark overhead command. @@ -361,7 +362,10 @@ impl OverheadCmd { Block: BlockT, ExtraHF: HostFunctions, { - self.check_args(&chain_spec); + if let Err((error_kind, msg)) = self.check_args(&chain_spec) { + let mut cmd = OverheadCmd::command(); + cmd.error(error_kind, msg).exit(); + }; let (state_handler, para_id) = self.state_handler_from_cli::<(ParachainHostFunctions, ExtraHF)>(chain_spec)?; @@ -701,12 +705,16 @@ mod tests { } fn cli_succeed(args: &[&str]) -> Result<(), clap::Error> { - OverheadCmd::try_parse_from(args)?; + let cmd = OverheadCmd::try_parse_from(args)?; + assert!(cmd.check_args(&None).is_ok()); Ok(()) } fn cli_fail(args: &[&str]) { - assert!(OverheadCmd::try_parse_from(args).is_err()); + let cmd = OverheadCmd::try_parse_from(args); + if let Ok(cmd) = cmd { + assert!(cmd.check_args(&None).is_err()); + } } #[test] diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index 2ceedc6dbdde8..95796edb81e95 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -236,7 +236,10 @@ impl PalletCmd { Hasher: Hash, ExtraHostFunctions: HostFunctions, { - self.check_args(&chain_spec); + if let Err((error_kind, msg)) = self.check_args(&chain_spec) { + let mut cmd = PalletCmd::command(); + cmd.error(error_kind, msg).exit(); + }; let _d = self.execution.as_ref().map(|exec| { // We print the error at the end, since there is often A LOT of output. @@ -907,52 +910,66 @@ impl PalletCmd { } /// Sanity check the CLI arguments. - fn check_args(&self, chain_spec: &Option>) { + fn check_args( + &self, + chain_spec: &Option>, + ) -> std::result::Result<(), (ErrorKind, String)> { if self.runtime.is_some() && self.shared_params.chain.is_some() { unreachable!("Clap should not allow both `--runtime` and `--chain` to be provided.") } - let abort_with_error = |error_kind: ErrorKind, msg: String| { - let mut cmd = PalletCmd::command(); - cmd.error(error_kind, msg).exit(); - }; - if chain_spec.is_none() && self.runtime.is_none() && self.shared_params.chain.is_none() { - abort_with_error( + return Err(( ErrorKind::MissingRequiredArgument, "Provide either a runtime via `--runtime` or a chain spec via `--chain`" .to_string(), - ) + )) + } + + match self.genesis_builder { + Some( + GenesisBuilderPolicy::None | + GenesisBuilderPolicy::SpecGenesis | + GenesisBuilderPolicy::SpecRuntime, + ) => + if chain_spec.is_none() && self.shared_params.chain.is_none() { + return Err(( + ErrorKind::MissingRequiredArgument, + "Provide a chain spec via `--chain`.".to_string(), + )) + }, + _ => {}, } if let Some(output_path) = &self.output { if !output_path.is_dir() && output_path.file_name().is_none() { - abort_with_error( + return Err(( ErrorKind::InvalidValue, format!("Output path is neither a directory nor a file: {output_path:?}"), - ); + )); } } if let Some(header_file) = &self.header { if !header_file.is_file() { - abort_with_error( + return Err(( ErrorKind::InvalidValue, format!("Header file could not be found: {header_file:?}"), - ); + )); }; } if let Some(handlebars_template_file) = &self.template { if !handlebars_template_file.is_file() { - abort_with_error( + return Err(( ErrorKind::InvalidValue, format!( "Handlebars template file could not be found: {handlebars_template_file:?}" ), - ); + )); }; } + Ok(()) } } @@ -1006,3 +1023,155 @@ fn list_benchmark( }, } } +#[cfg(test)] +mod tests { + use crate::pallet::PalletCmd; + use clap::Parser; + + fn cli_succeed(args: &[&str]) -> Result<(), clap::Error> { + let cmd = PalletCmd::try_parse_from(args)?; + assert!(cmd.check_args(&None).is_ok()); + Ok(()) + } + + fn cli_fail(args: &[&str]) { + let cmd = PalletCmd::try_parse_from(args); + if let Ok(cmd) = cmd { + assert!(cmd.check_args(&None).is_err()); + } + } + + #[test] + fn test_cli_conflicts() -> Result<(), clap::Error> { + // Runtime tests + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/runtime", + "--genesis-builder", + "runtime", + ])?; + cli_succeed(&["test", "--extrinsic", "", "--pallet", "", "--runtime", "path/to/runtime"])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/runtime", + "--genesis-builder-preset", + "preset", + ])?; + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/runtime", + "--genesis-builder", + "spec", + ]); + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/spec", + "--genesis-builder", + "spec-genesis", + ]); + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/spec", + "--genesis-builder", + "spec-runtime", + ]); + cli_fail(&["test", "--runtime", "path/to/spec", "--genesis-builder", "spec-genesis"]); + + // Spec tests + cli_succeed(&["test", "--extrinsic", "", "--pallet", "", "--chain", "path/to/spec"])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "spec", + ])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "spec-genesis", + ])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "spec-runtime", + ])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "none", + ])?; + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "runtime", + ]); + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "runtime", + "--genesis-builder-preset", + "preset", + ]); + Ok(()) + } +} diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs index b7924c0c6f0c0..54a055d4a33f9 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -20,7 +20,7 @@ mod types; mod writer; use crate::shared::HostInfoParams; -use clap::{ArgGroup, ValueEnum}; +use clap::ValueEnum; use frame_support::Serialize; use sc_cli::{ WasmExecutionMethod, WasmtimeInstantiationStrategy, DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, @@ -45,10 +45,6 @@ pub enum ListOutput { /// Benchmark the extrinsic weight of FRAME Pallets. #[derive(Debug, clap::Parser)] -#[clap(group( - ArgGroup::new("chain_source") - .args(["chain"]) -))] pub struct PalletCmd { /// Select a FRAME Pallet to benchmark, or `*` for all (in which case `extrinsic` must be `*`). #[arg(short, long, value_parser = parse_pallet_name, required_unless_present_any = ["list", "json_input", "all"], default_value_if("all", "true", Some("*".into())))] @@ -187,16 +183,7 @@ pub struct PalletCmd { /// How to construct the genesis state. /// /// Uses `GenesisBuilderPolicy::Spec` by default. - #[arg( - long, - value_enum, - alias = "genesis-builder-policy", - requires_ifs([ - ("spec", "chain_source"), - ("spec-runtime", "chain_source"), - ("spec-genesis", "chain_source"), - ]) - )] + #[arg(long, value_enum, alias = "genesis-builder-policy")] pub genesis_builder: Option, /// The preset that we expect to find in the GenesisBuilder runtime API. @@ -297,152 +284,3 @@ pub enum GenesisBuilderPolicy { #[value(alias = "spec")] SpecGenesis, } - -#[cfg(test)] -mod tests { - use crate::pallet::PalletCmd; - use clap::Parser; - - fn cli_succeed(args: &[&str]) -> Result<(), clap::Error> { - PalletCmd::try_parse_from(args)?; - Ok(()) - } - - fn cli_fail(args: &[&str]) { - assert!(PalletCmd::try_parse_from(args).is_err()); - } - - #[test] - fn test_cli_conflicts() -> Result<(), clap::Error> { - // Runtime tests - cli_succeed(&[ - "test", - "--extrinsic", - "", - "--pallet", - "", - "--runtime", - "path/to/runtime", - "--genesis-builder", - "runtime", - ])?; - cli_succeed(&["test", "--extrinsic", "", "--pallet", "", "--runtime", "path/to/runtime"])?; - cli_succeed(&[ - "test", - "--extrinsic", - "", - "--pallet", - "", - "--runtime", - "path/to/runtime", - "--genesis-builder-preset", - "preset", - ])?; - cli_fail(&[ - "test", - "--extrinsic", - "", - "--pallet", - "", - "--runtime", - "path/to/spec", - "--genesis-builder", - "spec", - ]); - cli_fail(&[ - "test", - "--extrinsic", - "", - "--pallet", - "", - "--runtime", - "path/to/spec", - "--genesis-builder", - "spec-genesis", - ]); - cli_fail(&[ - "test", - "--extrinsic", - "", - "--pallet", - "", - "--runtime", - "path/to/spec", - "--genesis-builder", - "spec-runtime", - ]); - cli_fail(&["test", "--runtime", "path/to/spec", "--genesis-builder", "spec-genesis"]); - - // Spec tests - cli_succeed(&["test", "--extrinsic", "", "--pallet", "", "--chain", "path/to/spec"])?; - cli_succeed(&[ - "test", - "--extrinsic", - "", - "--pallet", - "", - "--chain", - "path/to/spec", - "--genesis-builder", - "spec", - ])?; - cli_succeed(&[ - "test", - "--extrinsic", - "", - "--pallet", - "", - "--chain", - "path/to/spec", - "--genesis-builder", - "spec-genesis", - ])?; - cli_succeed(&[ - "test", - "--extrinsic", - "", - "--pallet", - "", - "--chain", - "path/to/spec", - "--genesis-builder", - "spec-runtime", - ])?; - cli_succeed(&[ - "test", - "--extrinsic", - "", - "--pallet", - "", - "--chain", - "path/to/spec", - "--genesis-builder", - "none", - ])?; - cli_fail(&[ - "test", - "--extrinsic", - "", - "--pallet", - "", - "--chain", - "path/to/spec", - "--genesis-builder", - "runtime", - ]); - cli_fail(&[ - "test", - "--extrinsic", - "", - "--pallet", - "", - "--chain", - "path/to/spec", - "--genesis-builder", - "runtime", - "--genesis-builder-preset", - "preset", - ]); - Ok(()) - } -} From 4d1d8b9def3ea37c3db4dcf017a4b8596a9e5f71 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 29 Oct 2024 14:45:43 +0100 Subject: [PATCH 39/43] Variant `none` should be allowed for runtimes in pallet --- .../benchmarking-cli/src/pallet/command.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index 95796edb81e95..6f7e79f163845 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -927,11 +927,7 @@ impl PalletCmd { } match self.genesis_builder { - Some( - GenesisBuilderPolicy::None | - GenesisBuilderPolicy::SpecGenesis | - GenesisBuilderPolicy::SpecRuntime, - ) => + Some(GenesisBuilderPolicy::SpecGenesis | GenesisBuilderPolicy::SpecRuntime) => if chain_spec.is_none() && self.shared_params.chain.is_none() { return Err(( ErrorKind::MissingRequiredArgument, @@ -1055,6 +1051,17 @@ mod tests { "--genesis-builder", "runtime", ])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/runtime", + "--genesis-builder", + "none", + ])?; cli_succeed(&["test", "--extrinsic", "", "--pallet", "", "--runtime", "path/to/runtime"])?; cli_succeed(&[ "test", From ed08f4f2bf09e6ee160e6cc4381eda21f0960c54 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 29 Oct 2024 20:49:00 +0100 Subject: [PATCH 40/43] Slight API improvements --- polkadot/cli/src/command.rs | 3 +- .../utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../benchmarking-cli/src/overhead/command.rs | 59 ++++++++++++------- .../utils/frame/omni-bencher/src/command.rs | 2 +- 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index c497ad9be8aef..02c9b97150c2d 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -402,8 +402,7 @@ pub fn run() -> Result<()> { .into()) } - cmd.run_with_extrinsic_builder_and_spec::( - None, + cmd.run_with_default_builder_and_spec::( Some(config.chain_spec), ) .map_err(Error::SubstrateCli) diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 504e38b678cc9..8a4a06b1b40ab 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -63,7 +63,7 @@ sp-version = { workspace = true, default-features = true } sp-timestamp = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } sp-wasm-interface = { workspace = true, default-features = true } -subxt = { workspace = true, features = ["native", "substrate-compat"] } +subxt = { workspace = true, features = ["native"] } subxt-signer = { workspace = true, features = ["unstable-eth"] } cumulus-primitives-proof-size-hostfunction = { workspace = true, default-features = true } cumulus-client-parachain-inherent = { workspace = true, default-features = true } diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs index 80f13c3de272c..2a32b148c4206 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs @@ -200,7 +200,7 @@ fn create_inherent_data + HeaderBackend, Blo let genesis = client.usage_info().chain.best_hash; let header = client.header(genesis).unwrap().unwrap(); - let mut inherent_data = sp_inherents::InherentData::new(); + let mut inherent_data = InherentData::new(); // Para inherent can only makes sense when we are handling a parachain. if let Parachain(para_id) = chain_type { @@ -350,16 +350,41 @@ impl OverheadCmd { Ok(()) } + /// Run the overhead benchmark with the default extrinsic builder. + /// + /// This will use [SubstrateRemarkBuilder] to build the extrinsic. It is + /// designed to match common configurations found in substrate chains. + pub fn run_with_default_builder_and_spec( + &self, + chain_spec: Option>, + ) -> Result<()> + where + Block: BlockT, + ExtraHF: HostFunctions, + { + self.run_with_extrinsic_builder_and_spec::( + Box::new(|metadata, hash, version| { + let genesis = subxt::utils::H256::from(hash.to_fixed_bytes()); + Box::new(SubstrateRemarkBuilder::new(metadata, genesis, version)) as Box<_> + }), + chain_spec, + ) + } + /// Run the benchmark overhead command. + /// + /// The provided [ExtrinsicBuilder] will be used to build extrinsics for + /// block-building. It is expected that the provided implementation builds + /// a `System::remark` extrinsic. pub fn run_with_extrinsic_builder_and_spec( &self, - ext_builder_provider: Option< - Box Box>, + ext_builder_provider: Box< + dyn FnOnce(Metadata, Block::Hash, RuntimeVersion) -> Box, >, chain_spec: Option>, ) -> Result<()> where - Block: BlockT, + Block: BlockT, ExtraHF: HostFunctions, { if let Err((error_kind, msg)) = self.check_args(&chain_spec) { @@ -405,17 +430,7 @@ impl OverheadCmd { transaction_version: version.transaction_version, }; - match ext_builder_provider { - Some(provider) => (provider(metadata, genesis, runtime_version), runtime_name), - None => { - let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); - ( - Box::new(SubstrateRemarkBuilder::new(metadata, genesis, runtime_version)) - as Box<_>, - runtime_name, - ) - }, - } + (ext_builder_provider(metadata, genesis, runtime_version), runtime_name) }; self.run( @@ -431,23 +446,27 @@ impl OverheadCmd { /// Run the benchmark overhead command. pub fn run_with_extrinsic_builder( &self, - ext_builder_provider: Option< - Box Box>, + ext_builder_provider: Box< + dyn FnOnce(Metadata, Block::Hash, RuntimeVersion) -> Box, >, ) -> Result<()> where - Block: BlockT, + Block: BlockT, ExtraHF: HostFunctions, { self.run_with_extrinsic_builder_and_spec::(ext_builder_provider, None) } - fn build_client_components( + fn build_client_components( &self, genesis_storage: Storage, executor: WasmExecutor, chain_type: &ChainType, - ) -> Result>> { + ) -> Result>> + where + Block: BlockT, + HF: HostFunctions, + { let extensions = ExecutionExtensions::new(None, Arc::new(executor.clone())); let base_path = match &self.shared_params.base_path { diff --git a/substrate/utils/frame/omni-bencher/src/command.rs b/substrate/utils/frame/omni-bencher/src/command.rs index fddbd9ffa8570..f5796d05e339d 100644 --- a/substrate/utils/frame/omni-bencher/src/command.rs +++ b/substrate/utils/frame/omni-bencher/src/command.rs @@ -145,7 +145,7 @@ impl V1SubCommand { pallet.run_with_spec::(None) }, BenchmarkCmd::Overhead(overhead_cmd) => - overhead_cmd.run_with_extrinsic_builder::(None), + overhead_cmd.run_with_default_builder_and_spec::(None), _ => return Err( "Only the `v1 benchmark pallet` and `v1 benchmark overhead` command is currently supported".into() From f548ce604f71e415ded4f8b28dc00a83b9fc1347 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 30 Oct 2024 09:02:57 +0100 Subject: [PATCH 41/43] prdoc improvements --- prdoc/pr_5891.prdoc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/prdoc/pr_5891.prdoc b/prdoc/pr_5891.prdoc index 3634b786b1221..beef711927e5e 100644 --- a/prdoc/pr_5891.prdoc +++ b/prdoc/pr_5891.prdoc @@ -10,14 +10,12 @@ doc: para- and relay chain teams to generate extrinsic and block base weights. crates: - - name: sc-block-builder - bump: minor - name: sc-chain-spec bump: none - name: polkadot-service - bump: none + bump: major - name: frame-benchmarking-cli - bump: minor + bump: major - name: cumulus-client-parachain-inherent bump: patch - name: polkadot-cli @@ -31,5 +29,5 @@ crates: - name: polkadot bump: none - name: frame-omni-bencher - bump: minor + bump: patch From 9cab200cf569338e0a8d1a3514fe5ed9849ab10c Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 30 Oct 2024 11:57:19 +0100 Subject: [PATCH 42/43] Update PRDOC Bumps --- prdoc/pr_5891.prdoc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/prdoc/pr_5891.prdoc b/prdoc/pr_5891.prdoc index beef711927e5e..4f8252628eb40 100644 --- a/prdoc/pr_5891.prdoc +++ b/prdoc/pr_5891.prdoc @@ -11,7 +11,7 @@ doc: crates: - name: sc-chain-spec - bump: none + bump: minor - name: polkadot-service bump: major - name: frame-benchmarking-cli @@ -19,15 +19,15 @@ crates: - name: cumulus-client-parachain-inherent bump: patch - name: polkadot-cli - bump: none + bump: patch - name: polkadot-omni-node-lib - bump: none + bump: patch - name: polkadot-omni-node - bump: none + bump: patch - name: polkadot-parachain-bin - bump: none + bump: patch - name: polkadot - bump: none - - name: frame-omni-bencher bump: patch + - name: frame-omni-bencher + bump: minor From 52458b8d636670eddac8f17a265f91f06db68334 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 30 Oct 2024 12:09:09 +0100 Subject: [PATCH 43/43] Move remark builders to own file. --- .../utils/frame/benchmarking-cli/src/lib.rs | 5 +- .../benchmarking-cli/src/overhead/command.rs | 1 + .../benchmarking-cli/src/overhead/mod.rs | 4 +- .../src/overhead/remark_builder.rs | 122 ++++++++++++++++++ .../src/overhead/runtime_utilities.rs | 105 +-------------- 5 files changed, 129 insertions(+), 108 deletions(-) create mode 100644 substrate/utils/frame/benchmarking-cli/src/overhead/remark_builder.rs diff --git a/substrate/utils/frame/benchmarking-cli/src/lib.rs b/substrate/utils/frame/benchmarking-cli/src/lib.rs index 09b12d8716adf..1e8642e54d701 100644 --- a/substrate/utils/frame/benchmarking-cli/src/lib.rs +++ b/substrate/utils/frame/benchmarking-cli/src/lib.rs @@ -29,9 +29,8 @@ pub use block::BlockCmd; pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; pub use machine::{MachineCmd, SUBSTRATE_REFERENCE_HARDWARE}; pub use overhead::{ - runtime_utilities::{ - fetch_latest_metadata_from_code_blob, DynamicRemarkBuilder, SubstrateRemarkBuilder, - }, + remark_builder::{DynamicRemarkBuilder, SubstrateRemarkBuilder}, + runtime_utilities::fetch_latest_metadata_from_code_blob, OpaqueBlock, OverheadCmd, }; pub use pallet::PalletCmd; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs index 2a32b148c4206..8102f14b4f4b9 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs @@ -27,6 +27,7 @@ use crate::{ overhead::{ command::ChainType::{Parachain, Relaychain, Unknown}, fake_runtime_api, + remark_builder::SubstrateRemarkBuilder, template::TemplateData, }, shared::{ diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs index 2e37a3bd6e6c5..89c23d1fb6c19 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs @@ -18,6 +18,8 @@ pub mod command; pub mod template; -pub use command::{OpaqueBlock, OverheadCmd}; mod fake_runtime_api; +pub mod remark_builder; pub mod runtime_utilities; + +pub use command::{OpaqueBlock, OverheadCmd}; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builder.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builder.rs new file mode 100644 index 0000000000000..a1d5f282d9f88 --- /dev/null +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builder.rs @@ -0,0 +1,122 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::extrinsic::ExtrinsicBuilder; +use codec::Decode; +use sc_client_api::UsageProvider; +use sp_api::{ApiExt, Core, Metadata, ProvideRuntimeApi}; +use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; +use std::sync::Arc; +use subxt::{ + client::RuntimeVersion as SubxtRuntimeVersion, + config::substrate::SubstrateExtrinsicParamsBuilder, Config, OfflineClient, SubstrateConfig, +}; + +pub type SubstrateRemarkBuilder = DynamicRemarkBuilder; + +/// Remark builder that can be used to build simple extrinsics for +/// FRAME-based runtimes. +pub struct DynamicRemarkBuilder { + offline_client: OfflineClient, +} + +impl> DynamicRemarkBuilder { + /// Initializes a new remark builder from a client. + /// + /// This will first fetch metadata and runtime version from the runtime and then + /// construct an offline client that provides the extrinsics. + pub fn new_from_client(client: Arc) -> sc_cli::Result + where + Block: BlockT, + Client: UsageProvider + ProvideRuntimeApi, + Client::Api: Metadata + Core, + { + let genesis = client.usage_info().chain.best_hash; + let api = client.runtime_api(); + + let Ok(Some(metadata_api_version)) = api.api_version::>(genesis) else { + return Err("Unable to fetch metadata runtime API version.".to_string().into()); + }; + + log::debug!("Found metadata API version {}.", metadata_api_version); + let opaque_metadata = if metadata_api_version > 1 { + let Ok(mut supported_metadata_versions) = api.metadata_versions(genesis) else { + return Err("Unable to fetch metadata versions".to_string().into()); + }; + + let latest = supported_metadata_versions + .pop() + .ok_or("No metadata version supported".to_string())?; + + api.metadata_at_version(genesis, latest) + .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? + .ok_or("Unable to decode metadata".to_string())? + } else { + // Fall back to using the non-versioned metadata API. + api.metadata(genesis) + .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? + }; + + let version = api.version(genesis).unwrap(); + let runtime_version = SubxtRuntimeVersion { + spec_version: version.spec_version, + transaction_version: version.transaction_version, + }; + let metadata = subxt::Metadata::decode(&mut (*opaque_metadata).as_slice())?; + let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); + + Ok(Self { offline_client: OfflineClient::new(genesis, runtime_version, metadata) }) + } +} + +impl DynamicRemarkBuilder { + /// Constructs a new remark builder. + pub fn new( + metadata: subxt::Metadata, + genesis_hash: C::Hash, + runtime_version: SubxtRuntimeVersion, + ) -> Self { + Self { offline_client: OfflineClient::new(genesis_hash, runtime_version, metadata) } + } +} + +impl ExtrinsicBuilder for DynamicRemarkBuilder { + fn pallet(&self) -> &str { + "system" + } + + fn extrinsic(&self) -> &str { + "remark" + } + + fn build(&self, nonce: u32) -> std::result::Result { + let signer = subxt_signer::sr25519::dev::alice(); + let dynamic_tx = subxt::dynamic::tx("System", "remark", vec![Vec::::new()]); + + let params = SubstrateExtrinsicParamsBuilder::new().nonce(nonce.into()).build(); + + // Default transaction parameters assume a nonce of 0. + let transaction = self + .offline_client + .tx() + .create_signed_offline(&dynamic_tx, &signer, params) + .unwrap(); + let mut encoded = transaction.into_encoded(); + + OpaqueExtrinsic::from_bytes(&mut encoded).map_err(|_| "Unable to construct OpaqueExtrinsic") + } +} diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs index e3c69dc4a417a..c498da38afb04 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs @@ -15,118 +15,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::extrinsic::ExtrinsicBuilder; use codec::{Decode, Encode}; -use sc_client_api::UsageProvider; use sc_executor::WasmExecutor; -use sp_api::{ApiExt, Core, Metadata, ProvideRuntimeApi}; use sp_core::{ traits::{CallContext, CodeExecutor, FetchRuntimeCode, RuntimeCode}, OpaqueMetadata, }; -use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; use sp_state_machine::BasicExternalities; use sp_wasm_interface::HostFunctions; -use std::{borrow::Cow, sync::Arc}; -use subxt::{ - client::RuntimeVersion as SubxtRuntimeVersion, - config::substrate::SubstrateExtrinsicParamsBuilder, Config, OfflineClient, SubstrateConfig, -}; - -pub type SubstrateRemarkBuilder = DynamicRemarkBuilder; - -/// Remark builder that can be used to build simple extrinsics for -/// FRAME-based runtimes. -pub struct DynamicRemarkBuilder { - offline_client: OfflineClient, -} - -impl> DynamicRemarkBuilder { - /// Initializes a new remark builder from a client. - /// - /// This will first fetch metadata and runtime version from the runtime and then - /// construct an offline client that provides the extrinsics. - pub fn new_from_client(client: Arc) -> sc_cli::Result - where - Block: BlockT, - Client: UsageProvider + ProvideRuntimeApi, - Client::Api: Metadata + Core, - { - let genesis = client.usage_info().chain.best_hash; - let api = client.runtime_api(); - - let Ok(Some(metadata_api_version)) = api.api_version::>(genesis) else { - return Err("Unable to fetch metadata runtime API version.".to_string().into()); - }; - - log::debug!("Found metadata API version {}.", metadata_api_version); - let opaque_metadata = if metadata_api_version > 1 { - let Ok(mut supported_metadata_versions) = api.metadata_versions(genesis) else { - return Err("Unable to fetch metadata versions".to_string().into()); - }; - - let latest = supported_metadata_versions - .pop() - .ok_or("No metadata version supported".to_string())?; - - api.metadata_at_version(genesis, latest) - .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? - .ok_or("Unable to decode metadata".to_string())? - } else { - // Fall back to using the non-versioned metadata API. - api.metadata(genesis) - .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? - }; - - let version = api.version(genesis).unwrap(); - let runtime_version = SubxtRuntimeVersion { - spec_version: version.spec_version, - transaction_version: version.transaction_version, - }; - let metadata = subxt::Metadata::decode(&mut (*opaque_metadata).as_slice())?; - let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); - - Ok(Self { offline_client: OfflineClient::new(genesis, runtime_version, metadata) }) - } -} - -impl DynamicRemarkBuilder { - /// Constructs a new remark builder. - pub fn new( - metadata: subxt::Metadata, - genesis_hash: C::Hash, - runtime_version: SubxtRuntimeVersion, - ) -> Self { - Self { offline_client: OfflineClient::new(genesis_hash, runtime_version, metadata) } - } -} - -impl ExtrinsicBuilder for DynamicRemarkBuilder { - fn pallet(&self) -> &str { - "system" - } - - fn extrinsic(&self) -> &str { - "remark" - } - - fn build(&self, nonce: u32) -> std::result::Result { - let signer = subxt_signer::sr25519::dev::alice(); - let dynamic_tx = subxt::dynamic::tx("System", "remark", vec![Vec::::new()]); - - let params = SubstrateExtrinsicParamsBuilder::new().nonce(nonce.into()).build(); - - // Default transaction parameters assume a nonce of 0. - let transaction = self - .offline_client - .tx() - .create_signed_offline(&dynamic_tx, &signer, params) - .unwrap(); - let mut encoded = transaction.into_encoded(); - - OpaqueExtrinsic::from_bytes(&mut encoded).map_err(|_| "Unable to construct OpaqueExtrinsic") - } -} +use std::borrow::Cow; /// Fetches the latest metadata from the given runtime blob. pub fn fetch_latest_metadata_from_code_blob(