From 75038021d3af14735cf5b356684dacc1866416d2 Mon Sep 17 00:00:00 2001 From: linning Date: Thu, 27 Jul 2023 07:30:31 +0800 Subject: [PATCH 1/7] Add raw_genesis_config to the genesis domain Signed-off-by: linning --- crates/pallet-domains/src/domain_registry.rs | 35 +++-- crates/pallet-domains/src/lib.rs | 3 +- crates/pallet-domains/src/tests.rs | 1 + crates/sp-domains/src/lib.rs | 1 + crates/subspace-node/src/chain_spec.rs | 15 ++ .../src/domain/evm_chain_spec.rs | 146 +++++++++--------- test/subspace-test-client/src/chain_spec.rs | 2 + 7 files changed, 118 insertions(+), 85 deletions(-) diff --git a/crates/pallet-domains/src/domain_registry.rs b/crates/pallet-domains/src/domain_registry.rs index d8ce040769..fba2a1bf64 100644 --- a/crates/pallet-domains/src/domain_registry.rs +++ b/crates/pallet-domains/src/domain_registry.rs @@ -82,6 +82,12 @@ pub struct DomainObject { pub genesis_receipt_hash: ReceiptHash, /// The domain config. pub domain_config: DomainConfig, + /// The genesis config of the domain, encoded in json format. + // + /// NOTE: the WASM code in the `system-pallet` genesis config should be empty to avoid + /// redundancy with the `RuntimeRegistry`. Currently, this value only set to `Some` for + /// the genesis domain instance. + pub raw_genesis_config: Option>, } pub(crate) fn can_instantiate_domain( @@ -130,6 +136,7 @@ pub(crate) fn do_instantiate_domain( domain_config: DomainConfig, owner_account_id: T::AccountId, created_at: T::BlockNumber, + raw_genesis_config: Option>, ) -> Result { can_instantiate_domain::(&owner_account_id, &domain_config)?; @@ -147,6 +154,7 @@ pub(crate) fn do_instantiate_domain( created_at, genesis_receipt_hash, domain_config, + raw_genesis_config, }; DomainRegistry::::insert(domain_id, domain_obj); @@ -237,7 +245,7 @@ mod tests { // Failed to instantiate domain due to `domain_name` too long assert_eq!( - do_instantiate_domain::(domain_config.clone(), creator, created_at), + do_instantiate_domain::(domain_config.clone(), creator, created_at, None), Err(Error::DomainNameTooLong) ); // Recorrect `domain_name` @@ -245,7 +253,7 @@ mod tests { // Failed to instantiate domain due to using unregistered runtime id assert_eq!( - do_instantiate_domain::(domain_config.clone(), creator, created_at), + do_instantiate_domain::(domain_config.clone(), creator, created_at, None), Err(Error::RuntimeNotFound) ); // Register runtime id @@ -271,7 +279,7 @@ mod tests { // Failed to instantiate domain due to exceed max domain block size limit assert_eq!( - do_instantiate_domain::(domain_config.clone(), creator, created_at), + do_instantiate_domain::(domain_config.clone(), creator, created_at, None), Err(Error::ExceedMaxDomainBlockSize) ); // Recorrect `max_block_size` @@ -279,7 +287,7 @@ mod tests { // Failed to instantiate domain due to exceed max domain block weight limit assert_eq!( - do_instantiate_domain::(domain_config.clone(), creator, created_at), + do_instantiate_domain::(domain_config.clone(), creator, created_at, None), Err(Error::ExceedMaxDomainBlockWeight) ); // Recorrect `max_block_weight` @@ -287,12 +295,12 @@ mod tests { // Failed to instantiate domain due to invalid `target_bundles_per_block` assert_eq!( - do_instantiate_domain::(domain_config.clone(), creator, created_at), + do_instantiate_domain::(domain_config.clone(), creator, created_at, None), Err(Error::InvalidBundlesPerBlock) ); domain_config.target_bundles_per_block = u32::MAX; assert_eq!( - do_instantiate_domain::(domain_config.clone(), creator, created_at), + do_instantiate_domain::(domain_config.clone(), creator, created_at, None), Err(Error::InvalidBundlesPerBlock) ); // Recorrect `target_bundles_per_block` @@ -300,22 +308,22 @@ mod tests { // Failed to instantiate domain due to invalid `bundle_slot_probability` assert_eq!( - do_instantiate_domain::(domain_config.clone(), creator, created_at), + do_instantiate_domain::(domain_config.clone(), creator, created_at, None), Err(Error::InvalidSlotProbability) ); domain_config.bundle_slot_probability = (1, 0); assert_eq!( - do_instantiate_domain::(domain_config.clone(), creator, created_at), + do_instantiate_domain::(domain_config.clone(), creator, created_at, None), Err(Error::InvalidSlotProbability) ); domain_config.bundle_slot_probability = (0, 1); assert_eq!( - do_instantiate_domain::(domain_config.clone(), creator, created_at), + do_instantiate_domain::(domain_config.clone(), creator, created_at, None), Err(Error::InvalidSlotProbability) ); domain_config.bundle_slot_probability = (2, 1); assert_eq!( - do_instantiate_domain::(domain_config.clone(), creator, created_at), + do_instantiate_domain::(domain_config.clone(), creator, created_at, None), Err(Error::InvalidSlotProbability) ); // Recorrect `bundle_slot_probability` @@ -323,7 +331,7 @@ mod tests { // Failed to instantiate domain due to creator don't have enough fund assert_eq!( - do_instantiate_domain::(domain_config.clone(), creator, created_at), + do_instantiate_domain::(domain_config.clone(), creator, created_at, None), Err(Error::InsufficientFund) ); // Set enough fund to creator @@ -335,7 +343,8 @@ mod tests { // `instantiate_domain` must success now let domain_id = - do_instantiate_domain::(domain_config.clone(), creator, created_at).unwrap(); + do_instantiate_domain::(domain_config.clone(), creator, created_at, None) + .unwrap(); let domain_obj = DomainRegistry::::get(domain_id).unwrap(); assert_eq!(domain_obj.owner_account_id, creator); @@ -347,7 +356,7 @@ mod tests { // cannot use the locked funds to create a new domain instance assert!( - do_instantiate_domain::(domain_config, creator, created_at) + do_instantiate_domain::(domain_config, creator, created_at, None) == Err(Error::InsufficientFund) ) }); diff --git a/crates/pallet-domains/src/lib.rs b/crates/pallet-domains/src/lib.rs index 41ce2af799..9224514f1d 100644 --- a/crates/pallet-domains/src/lib.rs +++ b/crates/pallet-domains/src/lib.rs @@ -803,7 +803,7 @@ mod pallet { let who = ensure_signed(origin)?; let created_at = frame_system::Pallet::::current_block_number(); - let domain_id = do_instantiate_domain::(domain_config, who, created_at) + let domain_id = do_instantiate_domain::(domain_config, who, created_at, None) .map_err(Error::::from)?; Self::deposit_event(Event::DomainInstantiated { domain_id }); @@ -917,6 +917,7 @@ mod pallet { domain_config, domain_owner.clone(), Zero::zero(), + Some(genesis_domain.raw_genesis_config), ) .expect("Genesis domain instantiation must always succeed"); diff --git a/crates/pallet-domains/src/tests.rs b/crates/pallet-domains/src/tests.rs index 8490ed02f2..93d61a35fc 100644 --- a/crates/pallet-domains/src/tests.rs +++ b/crates/pallet-domains/src/tests.rs @@ -468,6 +468,7 @@ fn test_bundle_fromat_verification() { created_at: Default::default(), genesis_receipt_hash: Default::default(), domain_config, + raw_genesis_config: None, }; DomainRegistry::::insert(domain_id, domain_obj); diff --git a/crates/sp-domains/src/lib.rs b/crates/sp-domains/src/lib.rs index 069039b3aa..a1ef201b4f 100644 --- a/crates/sp-domains/src/lib.rs +++ b/crates/sp-domains/src/lib.rs @@ -431,6 +431,7 @@ pub struct GenesisDomain { pub max_block_weight: Weight, pub bundle_slot_probability: (u64, u64), pub target_bundles_per_block: u32, + pub raw_genesis_config: Vec, // Genesis operator pub signing_key: OperatorPublicKey, diff --git a/crates/subspace-node/src/chain_spec.rs b/crates/subspace-node/src/chain_spec.rs index e10450c578..72c2ae2c67 100644 --- a/crates/subspace-node/src/chain_spec.rs +++ b/crates/subspace-node/src/chain_spec.rs @@ -19,6 +19,7 @@ use crate::chain_spec_utils::{ chain_spec_properties, get_account_id_from_seed, get_public_key_from_seed, }; +use crate::domain::evm_chain_spec::{self, SpecId}; use sc_service::{ChainType, NoExtension}; use sc_subspace_chain_specs::ConsensusChainSpec; use sc_telemetry::TelemetryEndpoints; @@ -137,6 +138,7 @@ pub fn gemini_3e_compiled() -> Result, String> }) .collect::>(); subspace_genesis_config( + SpecId::Gemini, WASM_BINARY.expect("Wasm binary must be built for Gemini"), sudo_account, balances, @@ -230,6 +232,7 @@ pub fn devnet_config_compiled() -> Result, Str }) .collect::>(); subspace_genesis_config( + SpecId::DevNet, WASM_BINARY.expect("Wasm binary must be built for Gemini"), sudo_account, balances, @@ -272,6 +275,7 @@ pub fn dev_config() -> Result, String> { ChainType::Development, || { subspace_genesis_config( + SpecId::Dev, wasm_binary, // Sudo account get_account_id_from_seed("Alice"), @@ -318,6 +322,7 @@ pub fn local_config() -> Result, String> { ChainType::Local, || { subspace_genesis_config( + SpecId::Local, wasm_binary, // Sudo account get_account_id_from_seed("Alice"), @@ -363,6 +368,7 @@ pub fn local_config() -> Result, String> { /// Configure initial storage state for FRAME modules. fn subspace_genesis_config( + spec_id: SpecId, wasm_binary: &[u8], sudo_account: AccountId, balances: Vec<(AccountId, Balance)>, @@ -379,6 +385,14 @@ fn subspace_genesis_config( confirmation_depth_k, } = genesis_params; + let raw_domain_genesis_config = { + let mut domain_genesis_config = evm_chain_spec::get_testnet_genesis_by_spec_id(spec_id); + // Clear the WASM code of the genesis config since it is duplicated with `GenesisDomain::code` + domain_genesis_config.system = Default::default(); + serde_json::to_vec(&domain_genesis_config) + .expect("Genesis config serialization never fails; qed") + }; + GenesisConfig { system: SystemConfig { // Add Wasm runtime to storage. @@ -417,6 +431,7 @@ fn subspace_genesis_config( max_block_weight: MaxDomainBlockWeight::get(), bundle_slot_probability: (1, 1), target_bundles_per_block: 10, + raw_genesis_config: raw_domain_genesis_config, // TODO: Configurable genesis operator signing key. signing_key: get_public_key_from_seed::("Alice"), diff --git a/crates/subspace-node/src/domain/evm_chain_spec.rs b/crates/subspace-node/src/domain/evm_chain_spec.rs index c0d2e3ec9d..55efeee2ef 100644 --- a/crates/subspace-node/src/domain/evm_chain_spec.rs +++ b/crates/subspace-node/src/domain/evm_chain_spec.rs @@ -147,82 +147,86 @@ pub fn devnet_config GenesisConfig + 'static + Send + Sync>( } pub fn load_chain_spec(spec_id: &str) -> Result, String> { - let accounts = get_dev_accounts(); let chain_spec = match spec_id { - "dev" => { - let constructor = move || { - testnet_genesis( - accounts.clone(), - // Alith is Sudo - Some(accounts[0]), - vec![( - accounts[0], - AccountId32ToAccountId20Converter::convert( - get_from_seed::("Alice").into(), - ), - )], - 1000, - ) - }; - development_config(constructor) + "dev" => development_config(move || get_testnet_genesis_by_spec_id(SpecId::Dev)), + "gemini-3e" => gemini_3e_config(move || get_testnet_genesis_by_spec_id(SpecId::Gemini)), + "devnet" => devnet_config(move || get_testnet_genesis_by_spec_id(SpecId::DevNet)), + "" | "local" => local_testnet_config(move || get_testnet_genesis_by_spec_id(SpecId::Local)), + path => ChainSpec::from_json_file(std::path::PathBuf::from(path))?, + }; + Ok(Box::new(chain_spec)) +} + +pub enum SpecId { + Dev, + Gemini, + DevNet, + Local, +} + +pub fn get_testnet_genesis_by_spec_id(spec_id: SpecId) -> GenesisConfig { + let accounts = get_dev_accounts(); + match spec_id { + SpecId::Dev => { + testnet_genesis( + accounts.clone(), + // Alith is Sudo + Some(accounts[0]), + vec![( + accounts[0], + AccountId32ToAccountId20Converter::convert( + get_from_seed::("Alice").into(), + ), + )], + 1000, + ) } - "gemini-3e" => { - let constructor = move || { - let sudo_account = AccountId::from_str("f31e60022e290708c17d6997c34de6a30d09438f") - .expect("Invalid Sudo account"); - testnet_genesis( - vec![ - // Genesis operator - AccountId::from_str("2ac6c70c106138c8cd80da6b6a0e886b7eeee249") - .expect("Wrong executor account address"), - // Sudo account - sudo_account, - ], - Some(sudo_account), - Default::default(), - 1002, - ) - }; - gemini_3e_config(constructor) + SpecId::Gemini => { + let sudo_account = AccountId::from_str("f31e60022e290708c17d6997c34de6a30d09438f") + .expect("Invalid Sudo account"); + testnet_genesis( + vec![ + // Genesis operator + AccountId::from_str("2ac6c70c106138c8cd80da6b6a0e886b7eeee249") + .expect("Wrong executor account address"), + // Sudo account + sudo_account, + ], + Some(sudo_account), + Default::default(), + 1002, + ) } - "devnet" => { - let constructor = move || { - let sudo_account = AccountId::from_str("b66a91845249464309fad766fd0ece8144547736") - .expect("Invalid Sudo account"); - testnet_genesis( - vec![ - // Genesis operator - AccountId::from_str("cfdf9f58d9e532c3807ce62a5489cb19cfa6942d") - .expect("Wrong executor account address"), - // Sudo account - sudo_account, - ], - Some(sudo_account), - vec![( - sudo_account, - AccountId::from_str("5b267fd1ba3ace6e3c3234f9576c49c877b5beb9") - .expect("Wrong relayer account address"), - )], - 1003, - ) - }; - devnet_config(constructor) + SpecId::DevNet => { + let sudo_account = AccountId::from_str("b66a91845249464309fad766fd0ece8144547736") + .expect("Invalid Sudo account"); + testnet_genesis( + vec![ + // Genesis operator + AccountId::from_str("cfdf9f58d9e532c3807ce62a5489cb19cfa6942d") + .expect("Wrong executor account address"), + // Sudo account + sudo_account, + ], + Some(sudo_account), + vec![( + sudo_account, + AccountId::from_str("5b267fd1ba3ace6e3c3234f9576c49c877b5beb9") + .expect("Wrong relayer account address"), + )], + 1003, + ) } - "" | "local" => { - let constructor = move || { - testnet_genesis( - accounts.clone(), - // Alith is sudo - Some(accounts[0]), - vec![(accounts[0], accounts[0]), (accounts[1], accounts[1])], - 1001, - ) - }; - local_testnet_config(constructor) + SpecId::Local => { + testnet_genesis( + accounts.clone(), + // Alith is sudo + Some(accounts[0]), + vec![(accounts[0], accounts[0]), (accounts[1], accounts[1])], + 1001, + ) } - path => ChainSpec::from_json_file(std::path::PathBuf::from(path))?, - }; - Ok(Box::new(chain_spec)) + } } // HACK: `ChainSpec::from_genesis` is only allow to create hardcoded spec and `GenesisConfig` diff --git a/test/subspace-test-client/src/chain_spec.rs b/test/subspace-test-client/src/chain_spec.rs index 154aa1505c..d5fae61ff2 100644 --- a/test/subspace-test-client/src/chain_spec.rs +++ b/test/subspace-test-client/src/chain_spec.rs @@ -109,6 +109,8 @@ fn create_genesis_config( max_block_weight: MaxDomainBlockWeight::get(), bundle_slot_probability: (1, 1), target_bundles_per_block: 10, + // TODO: set to proper value + raw_genesis_config: Default::default(), signing_key: get_from_seed::("Alice"), minimum_nominator_stake: 100 * SSC, From 9eca1e75271e503d78bfda728d302e7dc9b1b27a Mon Sep 17 00:00:00 2001 From: linning Date: Thu, 27 Jul 2023 07:36:14 +0800 Subject: [PATCH 2/7] Use raw_genesis_config to construct the genesis domain block/receipt Signed-off-by: linning --- crates/pallet-domains/src/domain_registry.rs | 9 +++++- crates/pallet-domains/src/lib.rs | 10 +++--- crates/sp-domains/src/lib.rs | 5 +++ crates/subspace-node/src/domain.rs | 11 ++++++- .../src/domain/evm_chain_spec.rs | 19 ++++++----- domains/test/service/src/chain_spec.rs | 32 +++++++++++++++---- domains/test/service/src/domain.rs | 8 ++--- 7 files changed, 66 insertions(+), 28 deletions(-) diff --git a/crates/pallet-domains/src/domain_registry.rs b/crates/pallet-domains/src/domain_registry.rs index fba2a1bf64..8f1b1b47ea 100644 --- a/crates/pallet-domains/src/domain_registry.rs +++ b/crates/pallet-domains/src/domain_registry.rs @@ -145,7 +145,12 @@ pub(crate) fn do_instantiate_domain( let genesis_receipt = { let runtime_obj = RuntimeRegistry::::get(domain_config.runtime_id) .expect("Runtime object must exist as checked in `can_instantiate_domain`; qed"); - initialize_genesis_receipt::(domain_id, runtime_obj.runtime_type, runtime_obj.code)? + initialize_genesis_receipt::( + domain_id, + runtime_obj.runtime_type, + runtime_obj.code, + raw_genesis_config.clone(), + )? }; let genesis_receipt_hash = genesis_receipt.hash(); @@ -191,6 +196,7 @@ fn initialize_genesis_receipt( domain_id: DomainId, runtime_type: RuntimeType, runtime_code: Vec, + raw_genesis_config: Option>, ) -> Result, Error> { let consensus_genesis_hash = frame_system::Pallet::::block_hash(T::BlockNumber::zero()); let genesis_state_root = generate_genesis_state_root( @@ -198,6 +204,7 @@ fn initialize_genesis_receipt( DomainInstanceData { runtime_type, runtime_code, + raw_genesis_config, }, ) .ok_or(Error::FailedToGenerateGenesisStateRoot)?; diff --git a/crates/pallet-domains/src/lib.rs b/crates/pallet-domains/src/lib.rs index 9224514f1d..579f10ed32 100644 --- a/crates/pallet-domains/src/lib.rs +++ b/crates/pallet-domains/src/lib.rs @@ -1043,14 +1043,14 @@ impl Pallet { } pub fn domain_instance_data(domain_id: DomainId) -> Option { - let runtime_id = DomainRegistry::::get(domain_id)? - .domain_config - .runtime_id; - let (runtime_type, runtime_code) = RuntimeRegistry::::get(runtime_id) - .map(|runtime_object| (runtime_object.runtime_type, runtime_object.code))?; + let domain_obj = DomainRegistry::::get(domain_id)?; + let (runtime_type, runtime_code) = + RuntimeRegistry::::get(domain_obj.domain_config.runtime_id) + .map(|runtime_object| (runtime_object.runtime_type, runtime_object.code))?; Some(DomainInstanceData { runtime_type, runtime_code, + raw_genesis_config: domain_obj.raw_genesis_config, }) } diff --git a/crates/sp-domains/src/lib.rs b/crates/sp-domains/src/lib.rs index a1ef201b4f..7b8b702b0d 100644 --- a/crates/sp-domains/src/lib.rs +++ b/crates/sp-domains/src/lib.rs @@ -516,6 +516,11 @@ impl DomainsDigestItem for DigestItem { pub struct DomainInstanceData { pub runtime_type: RuntimeType, pub runtime_code: Vec, + // The genesis config of the domain, encoded in json format. + // + // NOTE: the WASM code in the `system-pallet` genesis config should be empty to avoid + // redundancy with the `runtime_code` field. + pub raw_genesis_config: Option>, } impl PassBy for DomainInstanceData { diff --git a/crates/subspace-node/src/domain.rs b/crates/subspace-node/src/domain.rs index 433d6ac7da..90dbc05be2 100644 --- a/crates/subspace-node/src/domain.rs +++ b/crates/subspace-node/src/domain.rs @@ -90,10 +90,19 @@ where let DomainInstanceData { runtime_type, runtime_code, + raw_genesis_config, } = domain_instance_data; let domain_genesis_block_builder = match runtime_type { RuntimeType::Evm => { - let mut runtime_cfg = evm_domain_runtime::RuntimeGenesisConfig::default(); + let mut runtime_cfg = match raw_genesis_config { + Some(raw_genesis_config) => serde_json::from_slice(&raw_genesis_config) + .map_err(|_| { + sp_blockchain::Error::Application(Box::from( + "Failed to deserialize genesis config of the evm domain", + )) + })?, + None => evm_domain_runtime::RuntimeGenesisConfig::default(), + }; runtime_cfg.system.code = runtime_code; runtime_cfg.self_domain_id.domain_id = Some(domain_id); GenesisBlockBuilder::new( diff --git a/crates/subspace-node/src/domain/evm_chain_spec.rs b/crates/subspace-node/src/domain/evm_chain_spec.rs index 55efeee2ef..be0c286a94 100644 --- a/crates/subspace-node/src/domain/evm_chain_spec.rs +++ b/crates/subspace-node/src/domain/evm_chain_spec.rs @@ -262,13 +262,6 @@ fn load_chain_spec_with( Ok(Box::new(chain_spec)) } -fn domain_instance_genesis_config(domain_id: DomainId, runtime_code: Vec) -> GenesisConfig { - let mut cfg = GenesisConfig::default(); - cfg.system.code = runtime_code; - cfg.self_domain_id.domain_id = Some(domain_id); - cfg -} - pub fn create_domain_spec( domain_id: DomainId, chain_id: &str, @@ -277,11 +270,21 @@ pub fn create_domain_spec( let DomainInstanceData { runtime_type, runtime_code, + raw_genesis_config, } = domain_instance_data; match runtime_type { RuntimeType::Evm => { - let genesis_config = domain_instance_genesis_config(domain_id, runtime_code); + let mut genesis_config = match raw_genesis_config { + Some(raw_genesis_config) => { + serde_json::from_slice(&raw_genesis_config).map_err(|_| { + "Failed to deserialize genesis config of the evm domain".to_string() + })? + } + None => GenesisConfig::default(), + }; + genesis_config.system.code = runtime_code; + genesis_config.self_domain_id.domain_id = Some(domain_id); let spec = load_chain_spec_with(chain_id, genesis_config)?; Ok(spec) } diff --git a/domains/test/service/src/chain_spec.rs b/domains/test/service/src/chain_spec.rs index 48ebca472e..6861a2bd6f 100644 --- a/domains/test/service/src/chain_spec.rs +++ b/domains/test/service/src/chain_spec.rs @@ -130,7 +130,7 @@ fn testnet_evm_genesis() -> GenesisConfig { static GENESIS_CONFIG: OnceCell> = OnceCell::new(); /// Load chain spec that contains the given `GenesisConfig` -pub fn load_chain_spec_with(genesis_config: GenesisConfig) -> Box { +fn load_chain_spec_with(genesis_config: GenesisConfig) -> Box { let _ = GENESIS_CONFIG.set( serde_json::to_vec(&genesis_config).expect("Genesis config serialization never fails; qed"), ); @@ -143,10 +143,28 @@ pub fn load_chain_spec_with(genesis_config: GenesisConfig) -> Box Box::new(chain_spec_from_genesis!(constructor)) } -/// Create a `GenesisConfig` -pub fn domain_instance_genesis_config(domain_id: DomainId, runtime_code: Vec) -> GenesisConfig { - let mut cfg = GenesisConfig::default(); - cfg.system.code = runtime_code; - cfg.self_domain_id.domain_id = Some(domain_id); - cfg +/// Create chain spec +pub fn create_domain_spec( + domain_id: DomainId, + domain_instance_data: DomainInstanceData, +) -> Box { + let DomainInstanceData { + runtime_type, + runtime_code, + raw_genesis_config, + } = domain_instance_data; + + match runtime_type { + RuntimeType::Evm => { + let mut genesis_config = match raw_genesis_config { + Some(raw_genesis_config) => serde_json::from_slice(&raw_genesis_config) + .expect("Raw genesis config should be well-formatted"), + None => GenesisConfig::default(), + }; + genesis_config.system.code = runtime_code; + genesis_config.self_domain_id.domain_id = Some(domain_id); + + load_chain_spec_with(genesis_config) + } + } } diff --git a/domains/test/service/src/domain.rs b/domains/test/service/src/domain.rs index 9683d1a031..72783f9e1b 100644 --- a/domains/test/service/src/domain.rs +++ b/domains/test/service/src/domain.rs @@ -1,7 +1,7 @@ //! Utilities used for testing with the domain. #![warn(missing_docs)] -use crate::chain_spec::{domain_instance_genesis_config, load_chain_spec_with}; +use crate::chain_spec::create_domain_spec; use crate::{construct_extrinsic_generic, node_config, EcdsaKeyring, UncheckedExtrinsicFor}; use domain_client_operator::{Bootstrapper, OperatorStreams}; use domain_runtime_primitives::opaque::Block; @@ -416,11 +416,7 @@ impl DomainNodeBuilder { .expect("Failed to get domain instance data") .domain_instance_data }; - let chain_spec = { - let genesis_config = - domain_instance_genesis_config(domain_id, domain_instance_data.runtime_code); - load_chain_spec_with(genesis_config) - }; + let chain_spec = create_domain_spec(domain_id, domain_instance_data); DomainNode::build( DomainId::new(0u32), self.tokio_handle, From 18e26c4bd22b16db85ef6fe1c597ec07c9e1c20c Mon Sep 17 00:00:00 2001 From: linning Date: Thu, 27 Jul 2023 07:37:22 +0800 Subject: [PATCH 3/7] Minor refactoring to avoid cloning the genesis domain's runtime code Signed-off-by: linning --- crates/pallet-domains/src/domain_registry.rs | 19 +----------------- crates/pallet-domains/src/lib.rs | 21 +++++++++++++------- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/crates/pallet-domains/src/domain_registry.rs b/crates/pallet-domains/src/domain_registry.rs index 8f1b1b47ea..ce3c7d2ca1 100644 --- a/crates/pallet-domains/src/domain_registry.rs +++ b/crates/pallet-domains/src/domain_registry.rs @@ -15,8 +15,7 @@ use scale_info::TypeInfo; use sp_core::Get; use sp_domains::domain::generate_genesis_state_root; use sp_domains::{ - DomainId, DomainInstanceData, DomainsDigestItem, GenesisDomain, ReceiptHash, RuntimeId, - RuntimeType, + DomainId, DomainInstanceData, DomainsDigestItem, ReceiptHash, RuntimeId, RuntimeType, }; use sp_runtime::traits::{CheckedAdd, Zero}; use sp_runtime::DigestItem; @@ -56,22 +55,6 @@ pub struct DomainConfig { pub target_bundles_per_block: u32, } -impl DomainConfig { - pub(crate) fn from_genesis( - genesis_domain: &GenesisDomain, - runtime_id: RuntimeId, - ) -> Self { - DomainConfig { - domain_name: genesis_domain.domain_name.clone(), - runtime_id, - max_block_size: genesis_domain.max_block_size, - max_block_weight: genesis_domain.max_block_weight, - bundle_slot_probability: genesis_domain.bundle_slot_probability, - target_bundles_per_block: genesis_domain.target_bundles_per_block, - } - } -} - #[derive(TypeInfo, Debug, Encode, Decode, Clone, PartialEq, Eq)] pub struct DomainObject { /// The address of the domain creator, used to validate updating the domain config. diff --git a/crates/pallet-domains/src/lib.rs b/crates/pallet-domains/src/lib.rs index 579f10ed32..c6c9abe9e6 100644 --- a/crates/pallet-domains/src/lib.rs +++ b/crates/pallet-domains/src/lib.rs @@ -899,20 +899,27 @@ mod pallet { impl Hooks for Pallet { fn on_initialize(block_number: T::BlockNumber) -> Weight { if block_number.is_one() { - if let Some(ref genesis_domain) = PendingGenesisDomain::::take() { + if let Some(genesis_domain) = PendingGenesisDomain::::take() { // Register the genesis domain runtime let runtime_id = register_runtime_at_genesis::( - genesis_domain.runtime_name.clone(), - genesis_domain.runtime_type.clone(), - genesis_domain.runtime_version.clone(), - genesis_domain.code.clone(), + genesis_domain.runtime_name, + genesis_domain.runtime_type, + genesis_domain.runtime_version, + genesis_domain.code, Zero::zero(), ) .expect("Genesis runtime registration must always succeed"); // Instantiate the genesis domain - let domain_config = DomainConfig::from_genesis::(genesis_domain, runtime_id); - let domain_owner = genesis_domain.owner_account_id.clone(); + let domain_config = DomainConfig { + domain_name: genesis_domain.domain_name, + runtime_id, + max_block_size: genesis_domain.max_block_size, + max_block_weight: genesis_domain.max_block_weight, + bundle_slot_probability: genesis_domain.bundle_slot_probability, + target_bundles_per_block: genesis_domain.target_bundles_per_block, + }; + let domain_owner = genesis_domain.owner_account_id; let domain_id = do_instantiate_domain::( domain_config, domain_owner.clone(), From 5866cde7312b3b8d35857a52229e2c7943f3030e Mon Sep 17 00:00:00 2001 From: linning Date: Thu, 27 Jul 2023 07:42:43 +0800 Subject: [PATCH 4/7] Move the testing domain's genesis config to the testing consensus chain's genesis config Signed-off-by: linning --- domains/test/service/src/chain_spec.rs | 105 +----------------- test/subspace-test-client/Cargo.toml | 2 + test/subspace-test-client/src/chain_spec.rs | 11 +- .../src/domain_chain_spec.rs | 95 ++++++++++++++++ test/subspace-test-client/src/lib.rs | 1 + 5 files changed, 110 insertions(+), 104 deletions(-) create mode 100644 test/subspace-test-client/src/domain_chain_spec.rs diff --git a/domains/test/service/src/chain_spec.rs b/domains/test/service/src/chain_spec.rs index 6861a2bd6f..daeb7f602c 100644 --- a/domains/test/service/src/chain_spec.rs +++ b/domains/test/service/src/chain_spec.rs @@ -1,27 +1,9 @@ //! Chain specification for the domain test runtime. -use crate::EcdsaKeyring::{Alice, Bob, Charlie, Dave, Eve, Ferdie}; -use evm_domain_test_runtime::{AccountId as AccountId20, GenesisConfig, Precompiles, Signature}; + +use evm_domain_test_runtime::GenesisConfig; use once_cell::sync::OnceCell; use sc_service::{ChainSpec, ChainType, GenericChainSpec}; -use sp_core::{ecdsa, Pair, Public}; -use sp_domains::DomainId; -use sp_runtime::traits::{IdentifyAccount, Verify}; -use subspace_runtime_primitives::SSC; - -type AccountPublic = ::Signer; - -/// Helper function to generate an account ID from seed. -pub fn get_account_id_from_seed(seed: &str) -> AccountId20 -where - AccountPublic: From<::Public>, -{ - AccountPublic::from( - TPublic::Pair::from_string(&format!("//{seed}"), None) - .expect("static values are valid; qed") - .public(), - ) - .into_account() -} +use sp_domains::{DomainId, DomainInstanceData, RuntimeType}; macro_rules! chain_spec_from_genesis { ( $constructor:expr ) => {{ @@ -40,87 +22,6 @@ macro_rules! chain_spec_from_genesis { }}; } -/// Get the chain spec for the given domain. -/// -/// Note: for convenience, the returned chain spec give some specific accounts the ability to -/// win the bundle election for a specific domain with (nearly) 100% probability in each slot: -/// [Evm domain => Alice] -pub fn get_chain_spec() -> Box { - Box::new(chain_spec_from_genesis!(testnet_evm_genesis)) -} - -fn endowed_accounts() -> Vec { - vec![ - Alice.to_account_id(), - Bob.to_account_id(), - Charlie.to_account_id(), - Dave.to_account_id(), - Eve.to_account_id(), - Ferdie.to_account_id(), - 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"), - ] -} - -fn testnet_evm_genesis() -> GenesisConfig { - // This is the simplest bytecode to revert without returning any data. - // We will pre-deploy it under all of our precompiles to ensure they can be called from - // within contracts. - // (PUSH1 0x00 PUSH1 0x00 REVERT) - let revert_bytecode = vec![0x60, 0x00, 0x60, 0x00, 0xFD]; - - evm_domain_test_runtime::GenesisConfig { - system: evm_domain_test_runtime::SystemConfig { - code: evm_domain_test_runtime::WASM_BINARY - .expect("WASM binary was not build, please build it!") - .to_vec(), - }, - transaction_payment: Default::default(), - balances: evm_domain_test_runtime::BalancesConfig { - balances: endowed_accounts() - .iter() - .cloned() - .map(|k| (k, 2_000_000 * SSC)) - .collect(), - }, - messenger: evm_domain_test_runtime::MessengerConfig { - relayers: vec![(Alice.to_account_id(), Alice.to_account_id())], - }, - sudo: evm_domain_test_runtime::SudoConfig { - key: Some(Alice.to_account_id()), - }, - evm_chain_id: evm_domain_test_runtime::EVMChainIdConfig { chain_id: 100 }, - evm: evm_domain_test_runtime::EVMConfig { - // We need _some_ code inserted at the precompile address so that - // the evm will actually call the address. - accounts: Precompiles::used_addresses() - .into_iter() - .map(|addr| { - ( - addr, - fp_evm::GenesisAccount { - nonce: Default::default(), - balance: Default::default(), - storage: Default::default(), - code: revert_bytecode.clone(), - }, - ) - }) - .collect(), - }, - ethereum: Default::default(), - base_fee: Default::default(), - self_domain_id: evm_domain_test_runtime::SelfDomainIdConfig { - // Id of the genesis domain - domain_id: Some(DomainId::new(0)), - }, - } -} - /// HACK: `ChainSpec::from_genesis` is only allow to create hardcoded spec and `GenesisConfig` /// dosen't derive `Clone`, using global variable and serialization/deserialization to workaround /// these limits diff --git a/test/subspace-test-client/Cargo.toml b/test/subspace-test-client/Cargo.toml index b35aa45c44..fdc26ab7e0 100644 --- a/test/subspace-test-client/Cargo.toml +++ b/test/subspace-test-client/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] evm-domain-test-runtime = { version = "0.1.0", path = "../../domains/test/runtime/evm" } +fp-evm = { version = "3.0.0-dev", git = "https://github.com/subspace/frontier", rev = "c13d670b25b5506c1c5243f352941dc46c82ffe4" } futures = "0.3.28" schnorrkel = "0.9.1" sc-chain-spec = { git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71" } @@ -23,6 +24,7 @@ sc-client-api = { git = "https://github.com/subspace/substrate", rev = "55c157cf sc-consensus-subspace = { version = "0.1.0", path = "../../crates/sc-consensus-subspace" } sc-executor = { git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71" } sc-service = { git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71", default-features = false } +serde_json = "1.0.95" sp-api = { git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71" } sp-consensus-subspace = { version = "0.1.0", path = "../../crates/sp-consensus-subspace" } sp-core = { git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71" } diff --git a/test/subspace-test-client/src/chain_spec.rs b/test/subspace-test-client/src/chain_spec.rs index d5fae61ff2..e5ab22a650 100644 --- a/test/subspace-test-client/src/chain_spec.rs +++ b/test/subspace-test-client/src/chain_spec.rs @@ -1,5 +1,6 @@ //! Chain specification for the test runtime. +use crate::domain_chain_spec::testnet_evm_genesis; use sc_chain_spec::ChainType; use sp_core::{sr25519, Pair, Public}; use sp_domains::{GenesisDomain, OperatorPublicKey, RuntimeType}; @@ -76,6 +77,13 @@ fn create_genesis_config( // who, start, period, period_count, per_period vesting: Vec<(AccountId, BlockNumber, BlockNumber, u32, Balance)>, ) -> GenesisConfig { + let raw_domain_genesis_config = { + let mut domain_genesis_config = testnet_evm_genesis(); + // Clear the WASM code of the genesis config since it is duplicated with `GenesisDomain::code` + domain_genesis_config.system = Default::default(); + serde_json::to_vec(&domain_genesis_config) + .expect("Genesis config serialization never fails; qed") + }; GenesisConfig { system: SystemConfig { // Add Wasm runtime to storage. @@ -109,8 +117,7 @@ fn create_genesis_config( max_block_weight: MaxDomainBlockWeight::get(), bundle_slot_probability: (1, 1), target_bundles_per_block: 10, - // TODO: set to proper value - raw_genesis_config: Default::default(), + raw_genesis_config: raw_domain_genesis_config, signing_key: get_from_seed::("Alice"), minimum_nominator_stake: 100 * SSC, diff --git a/test/subspace-test-client/src/domain_chain_spec.rs b/test/subspace-test-client/src/domain_chain_spec.rs new file mode 100644 index 0000000000..b973f733db --- /dev/null +++ b/test/subspace-test-client/src/domain_chain_spec.rs @@ -0,0 +1,95 @@ +//! Chain specification for the evm domain. + +use evm_domain_test_runtime::{AccountId as AccountId20, GenesisConfig, Precompiles, Signature}; +use sp_core::{ecdsa, Pair, Public}; +use sp_domains::DomainId; +use sp_runtime::traits::{IdentifyAccount, Verify}; +use subspace_runtime_primitives::SSC; + +type AccountPublic = ::Signer; + +/// Helper function to generate an account ID from seed. +pub fn get_account_id_from_seed(seed: &str) -> AccountId20 +where + AccountPublic: From<::Public>, +{ + AccountPublic::from( + TPublic::Pair::from_string(&format!("//{seed}"), None) + .expect("static values are valid; qed") + .public(), + ) + .into_account() +} + +fn endowed_accounts() -> Vec { + 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"), + ] +} + +/// Get the genesis config of the evm domain +pub fn testnet_evm_genesis() -> GenesisConfig { + // This is the simplest bytecode to revert without returning any data. + // We will pre-deploy it under all of our precompiles to ensure they can be called from + // within contracts. + // (PUSH1 0x00 PUSH1 0x00 REVERT) + let revert_bytecode = vec![0x60, 0x00, 0x60, 0x00, 0xFD]; + + let alice = get_account_id_from_seed::("Alice"); + + evm_domain_test_runtime::GenesisConfig { + system: evm_domain_test_runtime::SystemConfig { + code: evm_domain_test_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + }, + transaction_payment: Default::default(), + balances: evm_domain_test_runtime::BalancesConfig { + balances: endowed_accounts() + .iter() + .cloned() + .map(|k| (k, 2_000_000 * SSC)) + .collect(), + }, + messenger: evm_domain_test_runtime::MessengerConfig { + relayers: vec![(alice, alice)], + }, + sudo: evm_domain_test_runtime::SudoConfig { key: Some(alice) }, + evm_chain_id: evm_domain_test_runtime::EVMChainIdConfig { chain_id: 100 }, + evm: evm_domain_test_runtime::EVMConfig { + // We need _some_ code inserted at the precompile address so that + // the evm will actually call the address. + accounts: Precompiles::used_addresses() + .into_iter() + .map(|addr| { + ( + addr, + fp_evm::GenesisAccount { + nonce: Default::default(), + balance: Default::default(), + storage: Default::default(), + code: revert_bytecode.clone(), + }, + ) + }) + .collect(), + }, + ethereum: Default::default(), + base_fee: Default::default(), + self_domain_id: evm_domain_test_runtime::SelfDomainIdConfig { + // Id of the genesis domain + domain_id: Some(DomainId::new(0)), + }, + } +} diff --git a/test/subspace-test-client/src/lib.rs b/test/subspace-test-client/src/lib.rs index 0b76e10a61..3d30cf2313 100644 --- a/test/subspace-test-client/src/lib.rs +++ b/test/subspace-test-client/src/lib.rs @@ -19,6 +19,7 @@ #![warn(missing_docs, unused_crate_dependencies)] pub mod chain_spec; +pub mod domain_chain_spec; use futures::executor::block_on; use futures::StreamExt; From 4f6caa984c1716c7822a415a6a43f9356d7c2289 Mon Sep 17 00:00:00 2001 From: linning Date: Thu, 27 Jul 2023 07:44:39 +0800 Subject: [PATCH 5/7] Enable domain tests that previously disabled due to the testing account don't have initial balance Signed-off-by: linning --- Cargo.lock | 2 ++ domains/client/domain-operator/src/tests.rs | 10 ---------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b433ef7ae8..f070948bf4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10941,6 +10941,7 @@ name = "subspace-test-client" version = "0.1.0" dependencies = [ "evm-domain-test-runtime", + "fp-evm 3.0.0-dev (git+https://github.com/subspace/frontier?rev=c13d670b25b5506c1c5243f352941dc46c82ffe4)", "futures", "sc-chain-spec", "sc-client-api", @@ -10948,6 +10949,7 @@ dependencies = [ "sc-executor", "sc-service", "schnorrkel", + "serde_json", "sp-api", "sp-consensus-subspace", "sp-core", diff --git a/domains/client/domain-operator/src/tests.rs b/domains/client/domain-operator/src/tests.rs index 7325223b30..1dd518737e 100644 --- a/domains/client/domain-operator/src/tests.rs +++ b/domains/client/domain-operator/src/tests.rs @@ -182,12 +182,7 @@ async fn test_domain_block_production() { assert_eq!(alice.client.info().best_number, domain_block_number + 10); } -// TODO: Disabled because the pallet-balance genesis config of the evm domain is empty and -// there is no initial balance in the testing account thus the `transfer` extrinsic will fail -// due to unable to pay transaction fee, unlock once we can set customized genesis config in -// test environment. #[substrate_test_utils::test(flavor = "multi_thread")] -#[ignore] async fn test_domain_block_deriving_from_multiple_bundles() { let directory = TempDir::new().expect("Must be able to create temporary directory"); @@ -447,12 +442,7 @@ async fn collected_receipts_should_be_on_the_same_branch_with_current_best_block ); } -// TODO: Disabled because the pallet-balance genesis config of the evm domain is empty and -// there is no initial balance in the testing account thus the `transfer` extrinsic will fail -// due to unable to pay transaction fee, unlock once we can set customized genesis config in -// test environment. #[substrate_test_utils::test(flavor = "multi_thread")] -#[ignore] async fn test_domain_tx_propagate() { let directory = TempDir::new().expect("Must be able to create temporary directory"); From 431cb897ec7f43dae13786d75cf3070627792785 Mon Sep 17 00:00:00 2001 From: linning Date: Mon, 31 Jul 2023 17:14:11 +0800 Subject: [PATCH 6/7] Apply review suggestions Signed-off-by: linning --- crates/subspace-node/src/chain_spec.rs | 2 +- crates/subspace-node/src/domain/evm_chain_spec.rs | 3 ++- test/subspace-test-client/src/chain_spec.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/subspace-node/src/chain_spec.rs b/crates/subspace-node/src/chain_spec.rs index 72c2ae2c67..8042ed94d6 100644 --- a/crates/subspace-node/src/chain_spec.rs +++ b/crates/subspace-node/src/chain_spec.rs @@ -388,7 +388,7 @@ fn subspace_genesis_config( let raw_domain_genesis_config = { let mut domain_genesis_config = evm_chain_spec::get_testnet_genesis_by_spec_id(spec_id); // Clear the WASM code of the genesis config since it is duplicated with `GenesisDomain::code` - domain_genesis_config.system = Default::default(); + domain_genesis_config.system.code = Default::default(); serde_json::to_vec(&domain_genesis_config) .expect("Genesis config serialization never fails; qed") }; diff --git a/crates/subspace-node/src/domain/evm_chain_spec.rs b/crates/subspace-node/src/domain/evm_chain_spec.rs index be0c286a94..e0247711c3 100644 --- a/crates/subspace-node/src/domain/evm_chain_spec.rs +++ b/crates/subspace-node/src/domain/evm_chain_spec.rs @@ -165,9 +165,9 @@ pub enum SpecId { } pub fn get_testnet_genesis_by_spec_id(spec_id: SpecId) -> GenesisConfig { - let accounts = get_dev_accounts(); match spec_id { SpecId::Dev => { + let accounts = get_dev_accounts(); testnet_genesis( accounts.clone(), // Alith is Sudo @@ -218,6 +218,7 @@ pub fn get_testnet_genesis_by_spec_id(spec_id: SpecId) -> GenesisConfig { ) } SpecId::Local => { + let accounts = get_dev_accounts(); testnet_genesis( accounts.clone(), // Alith is sudo diff --git a/test/subspace-test-client/src/chain_spec.rs b/test/subspace-test-client/src/chain_spec.rs index e5ab22a650..0bed5402dd 100644 --- a/test/subspace-test-client/src/chain_spec.rs +++ b/test/subspace-test-client/src/chain_spec.rs @@ -80,7 +80,7 @@ fn create_genesis_config( let raw_domain_genesis_config = { let mut domain_genesis_config = testnet_evm_genesis(); // Clear the WASM code of the genesis config since it is duplicated with `GenesisDomain::code` - domain_genesis_config.system = Default::default(); + domain_genesis_config.system.code = Default::default(); serde_json::to_vec(&domain_genesis_config) .expect("Genesis config serialization never fails; qed") }; From 0a680172a87c7e3dd686dc966448c0bc1b843a31 Mon Sep 17 00:00:00 2001 From: linning Date: Mon, 31 Jul 2023 18:43:53 +0800 Subject: [PATCH 7/7] Replace unimplemented! with Ok(()) for the check_transaction_validity runtime api Signed-off-by: linning --- domains/client/block-preprocessor/src/lib.rs | 1 + domains/runtime/evm/src/lib.rs | 3 ++- domains/test/runtime/evm/src/lib.rs | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/domains/client/block-preprocessor/src/lib.rs b/domains/client/block-preprocessor/src/lib.rs index f87f75016c..9ac17ad604 100644 --- a/domains/client/block-preprocessor/src/lib.rs +++ b/domains/client/block-preprocessor/src/lib.rs @@ -391,6 +391,7 @@ where return Ok(false); } + // TODO: the `check_transaction_validity` is unimplemented let is_legal_tx = self .client .runtime_api() diff --git a/domains/runtime/evm/src/lib.rs b/domains/runtime/evm/src/lib.rs index a4c180ad66..9ecafd9ee0 100644 --- a/domains/runtime/evm/src/lib.rs +++ b/domains/runtime/evm/src/lib.rs @@ -795,7 +795,8 @@ impl_runtime_apis! { _uxt: ::Extrinsic, _block_hash: ::Hash, ) -> Result<(), domain_runtime_primitives::CheckTxValidityError> { - unimplemented!("TODO: check transaction fee to core-evm") + // TODO: check transaction fee to core-evm + Ok(()) } fn storage_keys_for_verifying_transaction_validity( diff --git a/domains/test/runtime/evm/src/lib.rs b/domains/test/runtime/evm/src/lib.rs index 671b579c15..684ce1a12d 100644 --- a/domains/test/runtime/evm/src/lib.rs +++ b/domains/test/runtime/evm/src/lib.rs @@ -795,7 +795,8 @@ impl_runtime_apis! { _uxt: ::Extrinsic, _block_hash: ::Hash, ) -> Result<(), domain_runtime_primitives::CheckTxValidityError> { - unimplemented!("TODO: check transaction fee to core-evm") + // TODO: check transaction fee to core-evm + Ok(()) } fn storage_keys_for_verifying_transaction_validity(