Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: check genesis data of dev chain in unit tests to lock the consensus #1304

Merged
merged 1 commit into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 21 additions & 37 deletions core/run/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ pub struct Axon {
state_root: MerkleRoot,
}

#[cfg(test)]
mod tests;

impl Axon {
pub fn new(config: Config, genesis: RichBlock) -> Axon {
Axon {
Expand Down Expand Up @@ -143,20 +146,21 @@ impl Axon {
storage: &Arc<ImplStorage<RocksAdapter>>,
) -> ProtocolResult<()> {
let trie_db = self.init_trie_db(false).await?;
let mut mpt = MPTTrie::new(Arc::clone(&trie_db));

insert_accounts(&mut mpt, &self.config.accounts).await?;
let state_root = {
let mut mpt = MPTTrie::new(Arc::clone(&trie_db));
insert_accounts(&mut mpt, &self.config.accounts).expect("insert accounts");
mpt.commit()?
};

let path_metadata = self.config.data_path_for_system_contract();
let resp = execute_transactions(
&self.genesis,
&mut mpt,
state_root,
&trie_db,
storage,
path_metadata,
&self.config.rocksdb.clone(),
)
.await?;
)?;

log::info!(
"Execute the genesis distribute success, genesis state root {:?}, response {:?}",
Expand Down Expand Up @@ -197,20 +201,21 @@ impl Axon {
)?;
Arc::new(trie_db)
};
let mut mpt = MPTTrie::new(Arc::clone(&trie_db));

insert_accounts(&mut mpt, &self.config.accounts).await?;
let state_root = {
let mut mpt = MPTTrie::new(Arc::clone(&trie_db));
insert_accounts(&mut mpt, &self.config.accounts).expect("insert accounts");
mpt.commit()?
};

let path_metadata = tmp_dir.path().join("metadata");
let resp = execute_transactions(
&self.genesis,
&mut mpt,
state_root,
&trie_db,
&storage,
path_metadata,
&self.config.rocksdb.clone(),
)
.await?;
)?;

self.apply_genesis_data(resp.state_root, resp.receipt_root)?;

Expand Down Expand Up @@ -995,7 +1000,7 @@ where
}
}

async fn insert_accounts(
fn insert_accounts(
mpt: &mut MPTTrie<RocksTrieDB>,
accounts: &[InitialAccount],
) -> ProtocolResult<()> {
Expand All @@ -1012,9 +1017,9 @@ async fn insert_accounts(
Ok(())
}

async fn execute_transactions<S, DB>(
fn execute_transactions<S, DB>(
rich: &RichBlock,
mpt: &mut MPTTrie<RocksTrieDB>,
state_root: H256,
trie_db: &Arc<DB>,
storage: &Arc<S>,
path_metadata: PathBuf,
Expand All @@ -1026,7 +1031,7 @@ where
{
let executor = AxonExecutor::default();
let mut backend = AxonExecutorAdapter::from_root(
mpt.commit()?,
state_root,
Arc::clone(trie_db),
Arc::clone(storage),
Proposal::new_without_state_root(&rich.block.header).into(),
Expand Down Expand Up @@ -1064,24 +1069,3 @@ where

Ok(())
}

#[cfg(test)]
mod tests {
use protocol::codec::hex_decode;
use protocol::types::RichBlock;
use std::fs;

#[test]
fn decode_genesis() {
let raw = fs::read("../../devtools/chain/genesis_single_node.json").unwrap();
let genesis: RichBlock = serde_json::from_slice(&raw).unwrap();
println!("{:?}", genesis);
}

#[test]
fn decode_type_id() {
let type_id =
hex_decode("c0810210210c06ba233273e94d7fc89b00a705a07fdc0ae4c78e4036582ff336").unwrap();
println!("{:?}", type_id);
}
}
138 changes: 138 additions & 0 deletions core/run/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
use std::{
convert::AsRef,
env::set_current_dir,
fs, io,
path::{Path, PathBuf},
str::FromStr,
sync::Arc,
};

use common_config_parser::{parse_file, types::Config};
use core_executor::{MPTTrie, RocksTrieDB};
use core_storage::{adapter::rocks::RocksAdapter, ImplStorage};
use protocol::{
codec::hex_decode,
tokio,
types::{RichBlock, H256},
};

use crate::{execute_transactions, insert_accounts};

const DEV_CONFIG_DIR: &str = "../../devtools/chain";

const GENESIS_FILE: &str = "genesis_single_node.json";
const CONFIG_FILE: &str = "config.toml";

const GENESIS_HASH: &str = "0x69eca8420bb4b072d732db96260a656f0e10201c6841b215a8ed107681e17d1c";
const GENESIS_STATE_ROOT: &str =
"0x65f57a6a666e656de33ed68957e04b35b3fe1b35a90f6eafb6f283c907dc3d77";
const GENESIS_RECEIPTS_ROOT: &str =
"0x0abcdb8fd7acc8c71f28a16c3095fdafca0171f371076650152b1c356a1bccad";

#[test]
fn decode_genesis() {
let raw = fs::read("../../devtools/chain/genesis_single_node.json").unwrap();
assert!(serde_json::from_slice::<RichBlock>(&raw).is_ok());
}

#[test]
fn decode_type_id() {
let type_id_str = "c0810210210c06ba233273e94d7fc89b00a705a07fdc0ae4c78e4036582ff336";
assert!(hex_decode(type_id_str).is_ok());
}

#[tokio::test(flavor = "multi_thread")]
async fn genesis_hash_for_dev_chain() {
let dev_config_dir = PathBuf::from_str(DEV_CONFIG_DIR).expect("read dev config dir");
let tmp_dir = tempfile::tempdir().unwrap_or_else(|err| {
panic!("failed to create temporary directory since {err:?}");
});
let tmp_dir_path = tmp_dir.path();

copy_dir(dev_config_dir, tmp_dir_path).expect("configs copied");
set_current_dir(tmp_dir_path).expect("change work directory");

let config: Config = {
let config_path = tmp_dir_path.join(CONFIG_FILE);
parse_file(config_path, false).expect("parse config file")
};
let genesis: RichBlock = {
let genesis_path = tmp_dir_path.join(GENESIS_FILE);
parse_file(genesis_path, true).expect("parse genesis file")
};

let expected_genesis_hash = H256::from_str(GENESIS_HASH).expect("expected genesis hash");
check_hashes(
"genesis hash",
expected_genesis_hash,
genesis.block.header.hash(),
);

let storage = {
let path_block = tmp_dir.path().join("block");
let rocks_adapter = Arc::new(
RocksAdapter::new(path_block, config.rocksdb.clone()).expect("temporary block storage"),
);
let impl_storage = ImplStorage::new(rocks_adapter, config.rocksdb.cache_size);
Arc::new(impl_storage)
};

let trie_db = {
let path_state = tmp_dir.path().join("state");
let trie_db = RocksTrieDB::new(
path_state,
config.rocksdb.clone(),
config.executor.triedb_cache_size,
)
.expect("temporary trie db");
Arc::new(trie_db)
};

let state_root = {
let mut mpt = MPTTrie::new(Arc::clone(&trie_db));
insert_accounts(&mut mpt, &config.accounts).expect("insert accounts");
mpt.commit().expect("mpt commit")
};

let path_metadata = tmp_dir_path.join("metadata");
let resp = execute_transactions(
&genesis,
state_root,
&trie_db,
&storage,
path_metadata,
&config.rocksdb,
)
.expect("execute transactions");

let expected_state_root = H256::from_str(GENESIS_STATE_ROOT).expect("expected genesis hash");
check_hashes("genesis state root", expected_state_root, resp.state_root);
let expected_receipts_root =
H256::from_str(GENESIS_RECEIPTS_ROOT).expect("expected genesis hash");
check_hashes(
"genesis receipts root",
expected_receipts_root,
resp.receipt_root,
);
}

fn check_hashes(name: &str, expected: H256, actual: H256) {
assert_eq!(
expected, actual,
"{name} of dev chain is changed, expect {expected:#x}, but got {actual:#x}",
);
}

fn copy_dir(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
fs::create_dir_all(&dst)?;
for entry in fs::read_dir(src)? {
let entry = entry?;
let ty = entry.file_type()?;
if ty.is_dir() {
copy_dir(entry.path(), dst.as_ref().join(entry.file_name()))?;
} else {
std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
}
}
Ok(())
}