From 3745d65e4dd4f84476a1b5e2939a5e17599a3266 Mon Sep 17 00:00:00 2001 From: bgallois <benjamin@gallois.cc> Date: Fri, 31 Mar 2023 13:48:26 +0200 Subject: [PATCH] feat(node): add genesis builder for benchmarking Added a genesis builder for benchmarking with pre-configured accounts that can be used during the benchmarking and circumvent limitation imposed by pallets coupling. --- docs/dev/weights-benchmarking.md | 6 +- node/src/chain_spec/gdev.rs | 257 +++++++++++++++++++++++++++++++ node/src/command.rs | 2 + 3 files changed, 262 insertions(+), 3 deletions(-) diff --git a/docs/dev/weights-benchmarking.md b/docs/dev/weights-benchmarking.md index e60893212..330a56394 100644 --- a/docs/dev/weights-benchmarking.md +++ b/docs/dev/weights-benchmarking.md @@ -22,13 +22,13 @@ complete real example. machine: `cargo build --release --features runtime-benchmarks` 4. Run the benchmarks on your local machine (to test if it work with a real runtime). The command is: `duniter benchmark pallet --chain=CURRENCY-dev --steps=50 --repeat=20 --pallet=pallet_universal_dividend --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --header=./file_header.txt --output=.` -5. If it worked, use the generated file content to create or update the `WeightInfo` trait and the `()` dummy implementation. Then use the `WeightInfo` tarit in the real code of the pallet. See 79e0fd4bf3b0579279fc957da5e2fdfc6d8a17fa for a +5. If it worked, use the generated file content to create or update by hand the `WeightInfo` trait and the `()` dummy implementation. Then use the `WeightInfo` tarit in the real code of the pallet. See 79e0fd4bf3b0579279fc957da5e2fdfc6d8a17fa for a complete real example. 6. Redo steps `3.` and `4.` on the reference machine. -7. Put the generated file on `runtime/common/src/weights` and use it in the runtimes configuration. +7. Put the automatically generated file on `runtime/common/src/weights` and use it in the runtimes configuration. See cee7c3b2763ba402e807f126534d9cd39a8bd025 for a complete real example. -Note 1: You *must* replace `CURRENCY` by the currency type, or for ÄžDev use directly `--chain=dev`. +Note 1: You *must* replace `CURRENCY` by the currency type, or for ÄžDev use directly `--chain=gdev-benchmark`. Note 2: If the reference machine does not support wasmtime, you should replace `--wasm-execution=compiled` by `--wasm-execution=interpreted-i-know-what-i-do`. diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs index b83bfa370..015813f1b 100644 --- a/node/src/chain_spec/gdev.rs +++ b/node/src/chain_spec/gdev.rs @@ -183,6 +183,53 @@ pub fn development_chain_spec() -> Result<ChainSpec, String> { } } +/// generate chainspecs used for benchmarks +pub fn benchmark_chain_spec() -> Result<ChainSpec, String> { + let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; + + Ok(ChainSpec::from_genesis( + // Name + "Development", + // ID + "gdev-benchmark", + ChainType::Development, + move || { + gen_genesis_for_benchmark_chain( + wasm_binary, + // Initial authorities len + 1, + // Initial smiths members len + 3, + // Inital identities len + 4, + // Sudo account + get_account_id_from_seed::<sr25519::Public>("Alice"), + true, + ) + }, + // Bootnodes + vec![], + // Telemetry + None, + // Protocol ID + None, + //Fork ID + None, + // Properties + Some( + serde_json::json!({ + "tokenDecimals": TOKEN_DECIMALS, + "tokenSymbol": TOKEN_SYMBOL, + }) + .as_object() + .expect("must be a map") + .clone(), + ), + // Extensions + None, + )) +} + /// generate live network chainspecs pub fn gen_live_conf() -> Result<ChainSpec, String> { let wasm_binary = WASM_BINARY.ok_or_else(|| "wasm not available".to_string())?; @@ -443,6 +490,216 @@ fn gen_genesis_for_local_chain( } } +/// genesis used for benchmark +/// contain identities prepared for testing +fn gen_genesis_for_benchmark_chain( + wasm_binary: &[u8], + initial_authorities_len: usize, + initial_smiths_len: usize, + initial_identities_len: usize, + root_key: AccountId, + _enable_println: bool, +) -> gdev_runtime::GenesisConfig { + assert!(initial_identities_len <= 6); + assert!(initial_smiths_len <= initial_identities_len); + assert!(initial_authorities_len <= initial_smiths_len); + + let babe_epoch_duration = get_env_u32("DUNITER_BABE_EPOCH_DURATION", 30) as u64; + let cert_validity_period = get_env_u32("DUNITER_CERT_VALIDITY_PERIOD", 1_000); + let first_ud = 1_000; + let membership_period = get_env_u32("DUNITER_MEMBERSHIP_PERIOD", 1_000); + let smith_cert_validity_period = get_env_u32("DUNITER_SMITH_CERT_VALIDITY_PERIOD", 1_000); + let smith_membership_period = get_env_u32("DUNITER_SMITH_MEMBERSHIP_PERIOD", 1_000); + let ud_creation_period = get_env_u32("DUNITER_UD_CREATION_PERIOD", 10); + let ud_reeval_period = get_env_u32("DUNITER_UD_REEEVAL_PERIOD", 200); + + let initial_smiths = (0..initial_smiths_len) + .map(|i| get_authority_keys_from_seed(NAMES[i])) + .collect::<Vec<AuthorityKeys>>(); + let initial_identities = (0..initial_identities_len) + .map(|i| { + ( + IdtyName::from(NAMES[i]), + get_account_id_from_seed::<sr25519::Public>(NAMES[i]), + ) + }) + .collect::<BTreeMap<IdtyName, AccountId>>(); + + gdev_runtime::GenesisConfig { + system: SystemConfig { + // Add Wasm runtime to storage. + code: wasm_binary.to_vec(), + }, + account: AccountConfig { + accounts: initial_identities + .iter() + .enumerate() + .map(|(i, (_, owner_key))| { + ( + owner_key.clone(), + GenesisAccountData { + random_id: H256(blake2_256(&(i as u32, owner_key).encode())), + balance: first_ud, + is_identity: true, + }, + ) + }) + .collect(), + }, + parameters: ParametersConfig { + parameters: GenesisParameters { + babe_epoch_duration, + cert_period: 15, + cert_max_by_issuer: 10, + cert_min_received_cert_to_issue_cert: 2, + cert_validity_period, + idty_confirm_period: 40, + idty_creation_period: 50, + membership_period, + pending_membership_period: 500, + ud_creation_period, + ud_reeval_period, + smith_cert_period: 15, + smith_cert_max_by_issuer: 8, + smith_cert_min_received_cert_to_issue_cert: 2, + smith_cert_validity_period, + smith_membership_period, + smith_pending_membership_period: 500, + smiths_wot_first_cert_issuable_on: 20, + smiths_wot_min_cert_for_membership: 2, + wot_first_cert_issuable_on: 20, + wot_min_cert_for_create_idty_right: 2, + wot_min_cert_for_membership: 2, + }, + }, + authority_discovery: Default::default(), + authority_members: AuthorityMembersConfig { + initial_authorities: initial_smiths + .iter() + .enumerate() + .map(|(i, keys)| (i as u32 + 1, (keys.0.clone(), i < initial_authorities_len))) + .collect(), + }, + balances: BalancesConfig { + balances: Default::default(), + }, + babe: BabeConfig { + authorities: Vec::with_capacity(0), + epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG), + }, + grandpa: Default::default(), + im_online: Default::default(), + session: SessionConfig { + keys: initial_smiths + .iter() + .map(|x| { + ( + x.0.clone(), + x.0.clone(), + session_keys(x.1.clone(), x.2.clone(), x.3.clone(), x.4.clone()), + ) + }) + .collect::<Vec<_>>(), + }, + sudo: SudoConfig { + // Assign network admin rights. + key: Some(root_key), + }, + technical_committee: TechnicalCommitteeConfig { + members: initial_smiths + .iter() + .map(|x| x.0.clone()) + .collect::<Vec<_>>(), + ..Default::default() + }, + identity: IdentityConfig { + identities: initial_identities + .iter() + .enumerate() + .map(|(i, (name, owner_key))| { + if i != initial_identities_len - 1 { + GenesisIdty { + index: i as u32 + 1, + name: name.clone(), + value: IdtyValue { + data: IdtyData::new(), + next_creatable_identity_on: Default::default(), + old_owner_key: None, + owner_key: owner_key.clone(), + removable_on: 0, + status: IdtyStatus::Validated, + }, + } + } else { + GenesisIdty { + index: i as u32 + 1, + name: name.clone(), + value: IdtyValue { + data: IdtyData::new(), + next_creatable_identity_on: Default::default(), + old_owner_key: None, + owner_key: owner_key.clone(), + removable_on: 0, + status: IdtyStatus::Created, + }, + } + } + }) + .collect(), + }, + membership: MembershipConfig { + memberships: (1..=initial_identities.len()) + .filter_map(|i| { + if i != initial_identities_len { + Some((i as u32, MembershipData { expire_on: 0 })) + } else { + None + } + }) + .collect(), + }, + cert: CertConfig { + apply_cert_period_at_genesis: false, + certs_by_receiver: clique_wot(initial_identities.len()), + }, + smiths_membership: SmithsMembershipConfig { + memberships: (1..=initial_smiths_len) + .map(|i| (i as u32, MembershipData { expire_on: 0 })) + .collect(), + }, + smiths_cert: SmithsCertConfig { + apply_cert_period_at_genesis: false, + certs_by_receiver: clique_wot(initial_smiths_len), + }, + universal_dividend: UniversalDividendConfig { + first_reeval: 100, + first_ud, + initial_monetary_mass: initial_identities_len as u64 * first_ud, + }, + treasury: Default::default(), + } +} + +fn get_env_u32(env_var_name: &'static str, default_value: u32) -> u32 { + std::env::var(env_var_name) + .map_or(Ok(default_value), |s| s.parse()) + .unwrap_or_else(|_| panic!("{} must be a number", env_var_name)) +} + +fn session_keys( + babe: BabeId, + grandpa: GrandpaId, + im_online: ImOnlineId, + authority_discovery: AuthorityDiscoveryId, +) -> SessionKeys { + SessionKeys { + babe, + grandpa, + im_online, + authority_discovery, + } +} + /// custom genesis fn genesis_data_to_gdev_genesis_conf( genesis_data: super::gen_genesis_data::GenesisData<GenesisParameters, SessionKeys>, diff --git a/node/src/command.rs b/node/src/command.rs index 4ed633276..ce6f6d500 100644 --- a/node/src/command.rs +++ b/node/src/command.rs @@ -105,6 +105,8 @@ impl SubstrateCli for Cli { "gdev" => Box::new(chain_spec::gdev::ChainSpec::from_json_bytes( &include_bytes!("../specs/gdev-raw.json")[..], )?), + #[cfg(feature = "gdev")] + "gdev-benchmark" => Box::new(chain_spec::gdev::benchmark_chain_spec()?), #[cfg(feature = "gtest")] "gtest_dev" => Box::new(chain_spec::gtest::development_chain_spec()?), #[cfg(feature = "gtest")] -- GitLab