From 592fdefd29c15317e9e9d571408ec1fd605b45eb Mon Sep 17 00:00:00 2001 From: KaoImin Date: Wed, 27 Sep 2023 11:03:58 +0800 Subject: [PATCH] refactor: insert metadata directly when init chain --- core/executor/src/system_contract/mod.rs | 50 +++++++++++++++++-- .../tests/system_script/ckb_light_client.rs | 6 +-- .../src/tests/system_script/image_cell.rs | 6 +-- .../src/tests/system_script/metadata.rs | 4 +- core/interoperation/src/tests/mod.rs | 2 +- core/run/src/components/chain_spec.rs | 49 +++--------------- core/run/src/lib.rs | 24 +++++++-- core/run/src/tests.rs | 33 ++++++++---- 8 files changed, 105 insertions(+), 69 deletions(-) diff --git a/core/executor/src/system_contract/mod.rs b/core/executor/src/system_contract/mod.rs index fc3a85bbb..78b31896a 100644 --- a/core/executor/src/system_contract/mod.rs +++ b/core/executor/src/system_contract/mod.rs @@ -10,6 +10,7 @@ pub use crate::system_contract::ckb_light_client::{ CkbLightClientContract, CKB_LIGHT_CLIENT_CONTRACT_ADDRESS, }; pub use crate::system_contract::image_cell::{ImageCellContract, IMAGE_CELL_CONTRACT_ADDRESS}; +use crate::system_contract::metadata::MetadataStore; pub use crate::system_contract::metadata::{ check_ckb_related_info_exist, MetadataContract, METADATA_CONTRACT_ADDRESS, }; @@ -27,9 +28,9 @@ use evm::backend::ApplyBackend; use parking_lot::RwLock; use rocksdb::DB; -use protocol::ckb_blake2b_256; use protocol::traits::{CkbDataProvider, ExecutorAdapter}; -use protocol::types::{Bytes, Hasher, SignedTransaction, TxResp, H160, H256}; +use protocol::types::{Bytes, Hasher, Metadata, SignedTransaction, TxResp, H160, H256}; +use protocol::{ckb_blake2b_256, ProtocolResult}; use crate::adapter::RocksTrieDB; use crate::system_contract::{ @@ -105,9 +106,29 @@ pub fn swap_header_cell_db(new_db: Arc) -> Arc { .unwrap_or_else(|| panic!("header cell db is not initialized")) } +/// This method init the CKB light client and metadata DB and insert the first +/// two metadata, so the `metadata_list.len()` should be equal to 2. The Axon +/// run process contains two part: `init` and `start`. The `init` part +/// should initialize the DB and insert the first two metadata. The `start` part +/// only need to initialize the DB. This method should be used in the `init` +/// process. pub fn init( db: Arc, adapter: &mut Adapter, + metadata_list: &[Metadata], +) -> ProtocolResult<(H256, H256)> { + let ret = init_system_contract_db(db, adapter); + init_metadata(adapter, ret.0, metadata_list)?; + + Ok(ret) +} + +/// This method only init the CKB light client and metadata DB and should be +/// used in run process. The return value`tuple[0]` is current metadata MPT +/// root, `tuple[1]` is current CKB light client MPT root. +pub fn init_system_contract_db( + db: Arc, + adapter: &mut Adapter, ) -> (H256, H256) { let current_metadata_root = adapter.storage(METADATA_CONTRACT_ADDRESS, *METADATA_ROOT_KEY); @@ -128,14 +149,33 @@ pub fn init( ))); } - let current_cell_root = + let current_light_client_root = adapter.storage(CKB_LIGHT_CLIENT_CONTRACT_ADDRESS, *HEADER_CELL_ROOT_KEY); - if current_cell_root.is_zero() { + if current_light_client_root.is_zero() { let changes = generate_mpt_root_changes(adapter, IMAGE_CELL_CONTRACT_ADDRESS); adapter.apply(changes, vec![], false); } - (current_metadata_root, current_cell_root) + (current_metadata_root, current_light_client_root) +} + +/// This method is used for insert the first two metadata, so the +/// `metadata_list.len()` should be equal to 2. +fn init_metadata( + adapter: &mut Adapter, + metadata_root: H256, + metadata_list: &[Metadata], +) -> ProtocolResult<()> { + debug_assert!(metadata_list.len() == 2); + + let mut store = MetadataStore::new(metadata_root)?; + store.append_metadata(&metadata_list[0])?; + store.append_metadata(&metadata_list[1])?; + + let changes = generate_mpt_root_changes(adapter, METADATA_CONTRACT_ADDRESS); + adapter.apply(changes, vec![], false); + + Ok(()) } pub fn before_block_hook(adapter: &mut Adapter) { diff --git a/core/executor/src/tests/system_script/ckb_light_client.rs b/core/executor/src/tests/system_script/ckb_light_client.rs index 16c1036fb..cb4442edf 100644 --- a/core/executor/src/tests/system_script/ckb_light_client.rs +++ b/core/executor/src/tests/system_script/ckb_light_client.rs @@ -10,8 +10,8 @@ use crate::system_contract::ckb_light_client::{ ckb_light_client_abi, CkbHeaderReader, CkbLightClientContract, }; use crate::system_contract::{ - init, SystemContract, CKB_LIGHT_CLIENT_CONTRACT_ADDRESS, HEADER_CELL_ROOT_KEY, - IMAGE_CELL_CONTRACT_ADDRESS, + init_system_contract_db, SystemContract, CKB_LIGHT_CLIENT_CONTRACT_ADDRESS, + HEADER_CELL_ROOT_KEY, IMAGE_CELL_CONTRACT_ADDRESS, }; use crate::tests::{gen_tx, gen_vicinity}; @@ -25,7 +25,7 @@ pub fn test_write_functions() { let inner_db = RocksAdapter::new(ROCKSDB_PATH, Default::default()) .unwrap() .inner_db(); - init(inner_db, &mut backend); + init_system_contract_db(inner_db, &mut backend); // need to refactor to be OO test_update_first(&mut backend, &executor); diff --git a/core/executor/src/tests/system_script/image_cell.rs b/core/executor/src/tests/system_script/image_cell.rs index 6cbd4f3b1..da8aed5a7 100644 --- a/core/executor/src/tests/system_script/image_cell.rs +++ b/core/executor/src/tests/system_script/image_cell.rs @@ -11,8 +11,8 @@ use crate::system_contract::image_cell::{ image_cell_abi, CellInfo, CellKey, ImageCellContract, ImageCellReader, }; use crate::system_contract::{ - init, SystemContract, CKB_LIGHT_CLIENT_CONTRACT_ADDRESS, HEADER_CELL_ROOT_KEY, - IMAGE_CELL_CONTRACT_ADDRESS, + init_system_contract_db, SystemContract, CKB_LIGHT_CLIENT_CONTRACT_ADDRESS, + HEADER_CELL_ROOT_KEY, IMAGE_CELL_CONTRACT_ADDRESS, }; use crate::tests::{gen_tx, gen_vicinity}; use crate::{CURRENT_HEADER_CELL_ROOT, CURRENT_METADATA_ROOT}; @@ -27,7 +27,7 @@ pub fn test_write_functions() { let inner_db = RocksAdapter::new(ROCKSDB_PATH, Default::default()) .unwrap() .inner_db(); - let (m_root, h_root) = init(inner_db, &mut backend); + let (m_root, h_root) = init_system_contract_db(inner_db, &mut backend); CURRENT_METADATA_ROOT.with(|r| *r.borrow_mut() = m_root); CURRENT_HEADER_CELL_ROOT.with(|r| *r.borrow_mut() = h_root); diff --git a/core/executor/src/tests/system_script/metadata.rs b/core/executor/src/tests/system_script/metadata.rs index d5ad4b715..6d2b29ee3 100644 --- a/core/executor/src/tests/system_script/metadata.rs +++ b/core/executor/src/tests/system_script/metadata.rs @@ -7,7 +7,7 @@ use protocol::types::{MemoryBackend, SignedTransaction, H160, U256}; use crate::{ system_contract::{ - init, + init_system_contract_db, metadata::{ metadata_abi::{self, ConsensusConfig, Metadata, MetadataVersion, ValidatorExtend}, MetadataContract, MetadataStore, @@ -29,7 +29,7 @@ fn test_write_functions() { let inner_db = RocksAdapter::new(ROCKSDB_PATH, Default::default()) .unwrap() .inner_db(); - init(inner_db, &mut backend); + init_system_contract_db(inner_db, &mut backend); test_init(&mut backend, &executor); diff --git a/core/interoperation/src/tests/mod.rs b/core/interoperation/src/tests/mod.rs index f9e7fbb22..91f3c17a9 100644 --- a/core/interoperation/src/tests/mod.rs +++ b/core/interoperation/src/tests/mod.rs @@ -60,7 +60,7 @@ impl TestHandle { ) .unwrap(); - core_executor::system_contract::init(inner_db, &mut backend); + core_executor::system_contract::init_system_contract_db(inner_db, &mut backend); handle } diff --git a/core/run/src/components/chain_spec.rs b/core/run/src/components/chain_spec.rs index c08a22f90..5bab25ec1 100644 --- a/core/run/src/components/chain_spec.rs +++ b/core/run/src/components/chain_spec.rs @@ -1,14 +1,8 @@ -use ethers_core::abi::AbiEncode; - use common_config_parser::types::spec::ChainSpec; use common_crypto::{PrivateKey as _, Secp256k1RecoverablePrivateKey, Signature}; -use core_executor::system_contract::{ - metadata::metadata_abi::{AppendMetadataCall, MetadataContractCalls}, - METADATA_CONTRACT_ADDRESS, -}; use protocol::types::{ - Block, Eip1559Transaction, Hasher, Metadata, RichBlock, SignedTransaction, TransactionAction, + Block, Eip1559Transaction, Hasher, RichBlock, SignedTransaction, TransactionAction, UnsignedTransaction, UnverifiedTransaction, BASE_FEE_PER_GAS, }; @@ -18,39 +12,18 @@ pub(crate) trait ChainSpecExt { } impl ChainSpecExt for ChainSpec { - fn generate_genesis_block(&self, genesis_key: Secp256k1RecoverablePrivateKey) -> RichBlock { - let metadata_0 = self.params.clone(); - let metadata_1 = { - let mut tmp = metadata_0.clone(); - tmp.epoch = metadata_0.epoch + 1; - tmp.version.start = metadata_0.version.end + 1; - tmp.version.end = tmp.version.start + metadata_0.version.end - 1; - tmp + fn generate_genesis_block(&self, _genesis_key: Secp256k1RecoverablePrivateKey) -> RichBlock { + let txs = vec![]; + let block = Block { + header: self.genesis.build_header(), + tx_hashes: vec![], }; - let data_0 = encode_metadata(metadata_0); - let data_1 = encode_metadata(metadata_1); - - let chain_id = self.genesis.chain_id; - - let txs: Vec<_> = [data_0, data_1] - .into_iter() - .enumerate() - .map(|(index, data)| { - let nonce = index as u64; - let action = TransactionAction::Call(METADATA_CONTRACT_ADDRESS); - let utx = build_unverified_transaction(nonce, action, data); - build_transaction(&genesis_key, utx, chain_id) - }) - .collect(); - - let header = self.genesis.build_header(); - let tx_hashes = txs.iter().map(|tx| tx.transaction.hash).collect::>(); - let block = Block { header, tx_hashes }; RichBlock { block, txs } } } +#[allow(dead_code)] fn build_unverified_transaction( nonce: u64, action: TransactionAction, @@ -69,6 +42,7 @@ fn build_unverified_transaction( UnsignedTransaction::Eip1559(tx) } +#[allow(dead_code)] fn build_transaction( priv_key: &Secp256k1RecoverablePrivateKey, tx: UnsignedTransaction, @@ -90,10 +64,3 @@ fn build_transaction( SignedTransaction::from_unverified(utx, None).unwrap() } - -fn encode_metadata(metadata: Metadata) -> Vec { - MetadataContractCalls::AppendMetadata(AppendMetadataCall { - metadata: metadata.into(), - }) - .encode() -} diff --git a/core/run/src/lib.rs b/core/run/src/lib.rs index 11b126d82..c00a3cc64 100644 --- a/core/run/src/lib.rs +++ b/core/run/src/lib.rs @@ -173,7 +173,9 @@ async fn start( Proposal::new_without_state_root(¤t_block.header).into(), )?; - system_contract::init(inner_db, &mut backend); + // The first two metadata has been inserted in the init process, only need to + // init the system contract DB here. + system_contract::init_system_contract_db(inner_db, &mut backend); // Init mempool and recover signed transactions with the current block number let current_stxs = txs_wal.load_by_number(current_block.header.number + 1); @@ -445,7 +447,18 @@ async fn execute_genesis( spec: &ChainSpec, db_group: &DatabaseGroup, ) -> ProtocolResult { - let resp = execute_transactions(&partial_genesis, db_group, &spec.accounts)?; + let metadata_0 = spec.params.clone(); + let metadata_1 = { + let mut tmp = metadata_0.clone(); + tmp.epoch = metadata_0.epoch + 1; + tmp.version.start = metadata_0.version.end + 1; + tmp.version.end = tmp.version.start + metadata_0.version.end - 1; + tmp + }; + + let resp = execute_transactions(&partial_genesis, db_group, &spec.accounts, &[ + metadata_0, metadata_1, + ])?; partial_genesis.block.header.state_root = resp.state_root; partial_genesis.block.header.receipts_root = resp.receipt_root; @@ -465,6 +478,7 @@ fn execute_transactions( rich: &RichBlock, db_group: &DatabaseGroup, accounts: &[InitialAccount], + metadata_list: &[Metadata], ) -> ProtocolResult { let state_root = MPTTrie::new(db_group.trie_db()) .insert_accounts(accounts) @@ -477,7 +491,7 @@ fn execute_transactions( Proposal::new_without_state_root(&rich.block.header).into(), )?; - system_contract::init(db_group.inner_db(), &mut backend); + system_contract::init(db_group.inner_db(), &mut backend, metadata_list)?; let resp = AxonExecutor.exec(&mut backend, &rich.txs, &[]); @@ -527,7 +541,7 @@ pub fn set_hardfork_info( let current_block = storage.get_latest_block(Context::new()).await?; let current_state_root = current_block.header.state_root; - // Init system contract + // Init system contract DB let mut backend = AxonExecutorApplyAdapter::from_root( current_block.header.state_root, Arc::clone(&trie_db), @@ -535,7 +549,7 @@ pub fn set_hardfork_info( Proposal::new_without_state_root(¤t_block.header).into(), )?; - system_contract::init(inner_db, &mut backend); + system_contract::init_system_contract_db(inner_db, &mut backend); let metadata_root = AxonExecutorReadOnlyAdapter::from_root( current_state_root, diff --git a/core/run/src/tests.rs b/core/run/src/tests.rs index 6fb3382f4..b651fe306 100644 --- a/core/run/src/tests.rs +++ b/core/run/src/tests.rs @@ -40,8 +40,8 @@ const TESTCASES: &[TestCase] = &[ chain_spec_file: "specs/single_node/chain-spec.toml", key_file: "debug.key", input_genesis_hash: "0x4e06dc4a01178db42c029f7d65f65a5763702a21082cfcb626c6c41054a7a276", - genesis_state_root: "0xb6c51706f77a788606c8b932ad4f752c3f9a54008cd82e85f417d3a7e900d5c2", - genesis_receipts_root: "0x7e747618f612d08dfe54bcb67f58f13a49e8b1bafee9a8f19a3a0f7122f44d02", + genesis_state_root: "0x6d872daaeadbd0c57d9ca58b51e210ff1b440983b8ba2c8cdd208d090e7607f9", + genesis_receipts_root: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", }, TestCase { chain_name: "multi_nodes", @@ -49,8 +49,8 @@ const TESTCASES: &[TestCase] = &[ chain_spec_file: "specs/multi_nodes/chain-spec.toml", key_file: "debug.key", input_genesis_hash: "0xf16db25ca1a0cff5339d76e9802c75c43faac35ee4a9294a51234b167c69159f", - genesis_state_root: "0x9f76f02e823115e7b9887d07678f40b8ff50f82d4d09214fa481bdad68f5192a", - genesis_receipts_root: "0x7e747618f612d08dfe54bcb67f58f13a49e8b1bafee9a8f19a3a0f7122f44d02", + genesis_state_root: "0x019fd9142c6f68322427c71345ef96d2ed42b122c477e342bb97d3b2d34f6a8e", + genesis_receipts_root: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", }, TestCase { chain_name: "multi_nodes_short_epoch_len", @@ -58,8 +58,8 @@ const TESTCASES: &[TestCase] = &[ chain_spec_file: "specs/multi_nodes_short_epoch_len/chain-spec.toml", key_file: "debug.key", input_genesis_hash: "0x4e06dc4a01178db42c029f7d65f65a5763702a21082cfcb626c6c41054a7a276", - genesis_state_root: "0x9dddf9df077b2bb98f72686256dae92fb975d416fa3093956151056b913a065d", - genesis_receipts_root: "0x7e747618f612d08dfe54bcb67f58f13a49e8b1bafee9a8f19a3a0f7122f44d02", + genesis_state_root: "0xb7d27d3c2dc9c99aaf8a4a1420f802c317cb7b053d9268a14a78613949a192a1", + genesis_receipts_root: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", }, ]; @@ -77,7 +77,8 @@ fn decode_type_id() { #[tokio::test(flavor = "multi_thread")] async fn genesis_data_for_dev_chain() { - for case in TESTCASES { + for case in TESTCASES.iter() { + println!("======Test case {:?}======", case.chain_name); check_genesis_data(case).await; } } @@ -115,6 +116,7 @@ async fn check_genesis_data<'a>(case: &TestCase<'a>) { }; let genesis = chain_spec.generate_genesis_block(key); + println!("checking genesis hash"); check_hashes( case.chain_name, "input genesis hash", @@ -149,15 +151,28 @@ async fn check_genesis_data<'a>(case: &TestCase<'a>) { ) .expect("initialize databases"); - let resp = execute_transactions(&genesis, &db_group, &chain_spec.accounts) - .expect("execute transactions"); + let metadata_0 = chain_spec.params.clone(); + let metadata_1 = { + let mut tmp = metadata_0.clone(); + tmp.epoch = metadata_0.epoch + 1; + tmp.version.start = metadata_0.version.end + 1; + tmp.version.end = tmp.version.start + metadata_0.version.end - 1; + tmp + }; + let resp = execute_transactions(&genesis, &db_group, &chain_spec.accounts, &[ + metadata_0, metadata_1, + ]) + .expect("execute transactions"); + println!("checking state root"); check_hashes( case.chain_name, "genesis state root", case.genesis_state_root, resp.state_root, ); + + println!("checking receipts hash"); check_hashes( case.chain_name, "genesis receipts root",