Skip to content

Commit

Permalink
refactor!: insert metadata directly and remove genesis transactions (#…
Browse files Browse the repository at this point in the history
…1454)

* refactor: insert metadata directly when init chain

* add unit test case

* follow review opinion

* test: extend unit test scope
  • Loading branch information
Eason Gao authored Oct 9, 2023
1 parent 2dd3e88 commit 5b2310c
Show file tree
Hide file tree
Showing 11 changed files with 215 additions and 102 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions core/executor/src/system_contract/metadata/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mod abi;
pub(crate) mod handle;
mod segment;
pub mod segment;
mod store;

pub use abi::metadata_abi;
Expand Down Expand Up @@ -30,7 +30,7 @@ pub const METADATA_CONTRACT_ADDRESS: H160 = system_contract_address(0x1);
const METADATA_CACHE_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(10) };

lazy_static::lazy_static! {
static ref EPOCH_SEGMENT_KEY: H256 = Hasher::digest("epoch_segment");
pub static ref EPOCH_SEGMENT_KEY: H256 = Hasher::digest("epoch_segment");
static ref CKB_RELATED_INFO_KEY: H256 = Hasher::digest("ckb_related_info");
static ref HARDFORK_KEY: H256 = Hasher::digest("hardfork");
static ref HARDFORK_INFO: ArcSwap<H256> = ArcSwap::new(Arc::new(H256::zero()));
Expand Down
51 changes: 45 additions & 6 deletions core/executor/src/system_contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ 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::{
ckb_light_client::CkbHeaderReader, image_cell::ImageCellReader,
ckb_light_client::CkbHeaderReader, image_cell::ImageCellReader, metadata::MetadataStore,
utils::generate_mpt_root_changes,
};

Expand Down Expand Up @@ -105,9 +105,29 @@ pub fn swap_header_cell_db(new_db: Arc<RocksTrieDB>) -> Arc<RocksTrieDB> {
.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<Adapter: ExecutorAdapter + ApplyBackend>(
db: Arc<DB>,
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<Adapter: ExecutorAdapter + ApplyBackend>(
db: Arc<DB>,
adapter: &mut Adapter,
) -> (H256, H256) {
let current_metadata_root = adapter.storage(METADATA_CONTRACT_ADDRESS, *METADATA_ROOT_KEY);

Expand All @@ -128,19 +148,38 @@ pub fn init<Adapter: ExecutorAdapter + ApplyBackend>(
)));
}

let current_cell_root =
let current_light_client_root =
adapter.storage(CKB_LIGHT_CLIENT_CONTRACT_ADDRESS, *HEADER_CELL_ROOT_KEY);

// Current cell root is zero means there is no image cell and header contains in
// the MPT. Because of the empty cell root is zero rather than NLP_NULL, it is
// necessary to init the ckb light client and image account in state MPT. The
// initial process is set the storage root of the two accounts as H256::zero().
if current_cell_root.is_zero() {
if current_light_client_root.is_zero() {
let changes = generate_mpt_root_changes(adapter, CKB_LIGHT_CLIENT_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: ExecutorAdapter + ApplyBackend>(
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: ExecutorAdapter + ApplyBackend>(adapter: &mut Adapter) {
Expand Down
6 changes: 3 additions & 3 deletions core/executor/src/tests/system_script/ckb_light_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions core/executor/src/tests/system_script/image_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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);
Expand Down
6 changes: 2 additions & 4 deletions core/executor/src/tests/system_script/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -22,15 +22,14 @@ static ROCKSDB_PATH: &str = "./free-space/system-contract/metadata";

#[test]
fn test_write_functions() {
env_logger::init();
let vicinity = gen_vicinity();
let mut backend = MemoryBackend::new(&vicinity, BTreeMap::new());

let executor = MetadataContract::default();
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);

Expand All @@ -48,7 +47,6 @@ fn test_init<'a>(backend: &mut MemoryBackend<'a>, executor: &MetadataContract<Me
let addr = H160::from_str("0xf000000000000000000000000000000000000000").unwrap();
let tx = prepare_tx_1(&addr);
let r = executor.exec_(backend, &tx);
println!("{:?}", r);
assert!(r.exit_reason.is_succeed());
}

Expand Down
2 changes: 1 addition & 1 deletion core/interoperation/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
1 change: 1 addition & 0 deletions core/run/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jemallocator = { version = "0.5", features = ["profiling", "stats", "unprefixed_

[dev-dependencies]
clap = "4.4"
hasher = "0.1"
tempfile = "3.6"

[features]
Expand Down
73 changes: 8 additions & 65 deletions core/run/src/components/chain_spec.rs
Original file line number Diff line number Diff line change
@@ -1,15 +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 common_crypto::Secp256k1RecoverablePrivateKey;

use protocol::types::{
Block, Eip1559Transaction, Hasher, Metadata, RichBlock, SignedTransaction, TransactionAction,
UnsignedTransaction, UnverifiedTransaction, BASE_FEE_PER_GAS,
Block, Eip1559Transaction, RichBlock, TransactionAction, UnsignedTransaction, BASE_FEE_PER_GAS,
};

pub(crate) trait ChainSpecExt {
Expand All @@ -18,39 +11,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::<Vec<_>>();
let block = Block { header, tx_hashes };

RichBlock { block, txs }
}
}

#[allow(dead_code)]
fn build_unverified_transaction(
nonce: u64,
action: TransactionAction,
Expand All @@ -68,32 +40,3 @@ fn build_unverified_transaction(
};
UnsignedTransaction::Eip1559(tx)
}

fn build_transaction(
priv_key: &Secp256k1RecoverablePrivateKey,
tx: UnsignedTransaction,
id: u64,
) -> SignedTransaction {
let signature = priv_key.sign_message(
&Hasher::digest(tx.encode(Some(id), None))
.as_bytes()
.try_into()
.unwrap(),
);
let utx = UnverifiedTransaction {
unsigned: tx,
signature: Some(signature.to_bytes().into()),
chain_id: Some(id),
hash: Default::default(),
}
.calc_hash();

SignedTransaction::from_unverified(utx, None).unwrap()
}

fn encode_metadata(metadata: Metadata) -> Vec<u8> {
MetadataContractCalls::AppendMetadata(AppendMetadataCall {
metadata: metadata.into(),
})
.encode()
}
26 changes: 20 additions & 6 deletions core/run/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,9 @@ async fn start<K: KeyProvider>(
Proposal::new_without_state_root(&current_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);
Expand Down Expand Up @@ -445,7 +447,18 @@ async fn execute_genesis(
spec: &ChainSpec,
db_group: &DatabaseGroup,
) -> ProtocolResult<RichBlock> {
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_genesis_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;
Expand All @@ -461,10 +474,11 @@ async fn execute_genesis(
Ok(partial_genesis)
}

fn execute_transactions(
fn execute_genesis_transactions(
rich: &RichBlock,
db_group: &DatabaseGroup,
accounts: &[InitialAccount],
metadata_list: &[Metadata],
) -> ProtocolResult<ExecResp> {
let state_root = MPTTrie::new(db_group.trie_db())
.insert_accounts(accounts)
Expand All @@ -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, &[]);

Expand Down Expand Up @@ -527,15 +541,15 @@ 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),
Arc::clone(&storage),
Proposal::new_without_state_root(&current_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,
Expand Down
Loading

0 comments on commit 5b2310c

Please sign in to comment.