diff --git a/core/api/src/adapter.rs b/core/api/src/adapter.rs index 9b346634f..91ab37d3d 100644 --- a/core/api/src/adapter.rs +++ b/core/api/src/adapter.rs @@ -10,7 +10,7 @@ use protocol::types::{ Proposal, Receipt, SignedTransaction, TxResp, H160, H256, MAX_BLOCK_GAS_LIMIT, NIL_DATA, RLP_NULL, U256, }; -use protocol::{async_trait, codec::ProtocolCodec, trie, ProtocolError, ProtocolResult}; +use protocol::{async_trait, codec::ProtocolCodec, trie, ProtocolResult}; use core_executor::{ system_contract::metadata::MetadataHandle, AxonExecutor, AxonExecutorReadOnlyAdapter, MPTTrie, @@ -239,10 +239,11 @@ where let storage_mpt_tree = MPTTrie::from_root(account.storage_root, Arc::clone(&self.trie_db))?; let hash: Hash = BigEndianHash::from_uint(&position); - storage_mpt_tree + let value: H256 = storage_mpt_tree .get(hash.as_bytes())? - .map(Into::into) - .ok_or_else(|| APIError::Adapter("Can't find this position".to_string()).into()) + .map(|v| BigEndianHash::from_uint(&U256::decode(v).unwrap())) + .unwrap_or(H256::zero()); + Ok(Bytes::from(value.0.to_vec())) } async fn get_proof( @@ -253,51 +254,72 @@ where state_root: Hash, ) -> ProtocolResult { let state_mpt_tree = MPTTrie::from_root(state_root, Arc::clone(&self.trie_db))?; - let raw_account = state_mpt_tree - .get(address.as_bytes())? - .ok_or_else(|| APIError::Adapter("Can't find this address".to_string()))?; - - let account = Account::decode(raw_account).unwrap(); - - let account_proof = state_mpt_tree + let account_proof: Vec = state_mpt_tree .get_proof(address.as_bytes())? .into_iter() .map(Hex::encode) .collect(); - - let storage_mpt_tree = MPTTrie::from_root(account.storage_root, Arc::clone(&self.trie_db))?; - - let mut storage_proofs = Vec::with_capacity(storage_position.len()); - - for h in storage_position { - let hash: Hash = BigEndianHash::from_uint(&h); - let proof = EthStorageProof { - key: hash, - value: storage_mpt_tree - .get(hash.as_bytes())? - .map(|v| H256::from_slice(&v)) - .ok_or_else(|| { - Into::::into(APIError::Adapter( - "Can't find this position".to_string(), - )) - })?, - proof: storage_mpt_tree - .get_proof(hash.as_bytes())? - .into_iter() - .map(Hex::encode) - .collect(), - }; - storage_proofs.push(proof); + match state_mpt_tree.get(address.as_bytes())? { + Some(raw_account) => { + let account = Account::decode(raw_account).unwrap(); + + let storage_mpt_tree = + MPTTrie::from_root(account.storage_root, Arc::clone(&self.trie_db))?; + + let mut storage_proofs = Vec::with_capacity(storage_position.len()); + + for h in storage_position { + let hash: Hash = BigEndianHash::from_uint(&h); + let storage_proof = storage_mpt_tree + .get_proof(hash.as_bytes())? + .into_iter() + .map(Hex::encode) + .collect(); + let proof = match storage_mpt_tree.get(hash.as_bytes())? { + Some(v) => EthStorageProof { + key: h, + value: U256::decode(&v).unwrap(), + proof: storage_proof, + }, + // key is not exist + None => EthStorageProof { + key: h, + value: U256::zero(), + proof: storage_proof, + }, + }; + storage_proofs.push(proof); + } + Ok(EthAccountProof { + address, + balance: account.balance, + code_hash: account.code_hash, + nonce: account.nonce, + storage_hash: account.storage_root, + account_proof, + storage_proof: storage_proofs, + }) + } + None => { + // account is not exist + Ok(EthAccountProof { + address, + balance: U256::zero(), + code_hash: H256::zero(), + nonce: U256::zero(), + storage_hash: H256::zero(), + account_proof, + storage_proof: storage_position + .into_iter() + .map(|h| EthStorageProof { + key: h, + value: U256::zero(), + proof: Vec::new(), + }) + .collect(), + }) + } } - - Ok(EthAccountProof { - balance: account.balance, - code_hash: account.code_hash, - nonce: account.nonce, - storage_hash: account.storage_root, - account_proof, - storage_proof: storage_proofs, - }) } async fn get_metadata_by_number( diff --git a/core/executor/src/adapter/backend/apply.rs b/core/executor/src/adapter/backend/apply.rs index 0877f75f5..ef5c364ad 100644 --- a/core/executor/src/adapter/backend/apply.rs +++ b/core/executor/src/adapter/backend/apply.rs @@ -175,7 +175,25 @@ where }; storage.into_iter().for_each(|(k, v)| { - let _ = storage_trie.insert(k.as_bytes().to_vec(), v.as_bytes().to_vec()); + // https://github.com/ethereum/go-ethereum/blob/ad16f11f841ab3a5fdedc8ddfc602f0717a34dd0/core/state/state_object.go#L306-L311 + // if value is zero, delete it's key + if v == H256::zero() { + storage_trie + .remove(k.as_bytes()) + .expect("Failed to remove entry with zero value from storage trie"); + } else { + storage_trie + .insert( + k.as_bytes().to_vec(), + // https://github.com/ethereum/go-ethereum/blob/ad16f11f841ab3a5fdedc8ddfc602f0717a34dd0/core/state/state_object.go#L314 + // Trim left zeroes and then rlp + U256::from_big_endian(v.as_bytes()) + .encode() + .unwrap() + .to_vec(), + ) + .expect("trie tree insert fail"); + } }); let storage_root = storage_trie diff --git a/core/executor/src/adapter/backend/read_only.rs b/core/executor/src/adapter/backend/read_only.rs index 31a3a5d56..1c41e626c 100644 --- a/core/executor/src/adapter/backend/read_only.rs +++ b/core/executor/src/adapter/backend/read_only.rs @@ -5,7 +5,8 @@ use evm::backend::Basic; use protocol::traits::{Backend, Context, ExecutorReadOnlyAdapter, ReadOnlyStorage}; use protocol::trie::Trie as _; use protocol::types::{ - Account, Bytes, ExecutorContext, MerkleRoot, H160, H256, NIL_DATA, RLP_NULL, U256, + Account, BigEndianHash, Bytes, ExecutorContext, MerkleRoot, H160, H256, NIL_DATA, RLP_NULL, + U256, }; use protocol::{codec::ProtocolCodec, trie, ProtocolResult}; @@ -172,7 +173,10 @@ where } else { MPTTrie::from_root(storage_root, Arc::clone(&self.db)).map( |trie| match trie.get(index.as_bytes()) { - Ok(Some(res)) => H256::from_slice(res.as_ref()), + Ok(Some(res)) => { + let value = U256::decode(res).unwrap(); + BigEndianHash::from_uint(&value) + } _ => H256::default(), }, ) diff --git a/core/executor/src/adapter/trie/wrapped.rs b/core/executor/src/adapter/trie/wrapped.rs index d5b73ca34..f51a93382 100644 --- a/core/executor/src/adapter/trie/wrapped.rs +++ b/core/executor/src/adapter/trie/wrapped.rs @@ -3,26 +3,26 @@ use std::sync::Arc; use hasher::HasherKeccak; use protocol::trie::{PatriciaTrie, Trie, TrieError, DB as TrieDB}; -use protocol::types::MerkleRoot; +use protocol::types::{Hasher, MerkleRoot}; use protocol::ProtocolResult; pub struct MPTTrie(PatriciaTrie); impl Trie for MPTTrie { fn get(&self, key: &[u8]) -> Result>, TrieError> { - self.0.get(key) + self.0.get(&Hasher::digest(key).0) } fn contains(&self, key: &[u8]) -> Result { - self.0.contains(key) + self.0.contains(&Hasher::digest(key).0) } fn insert(&mut self, key: Vec, value: Vec) -> Result<(), TrieError> { - self.0.insert(key, value) + self.0.insert(Hasher::digest(key).0.to_vec(), value) } fn remove(&mut self, key: &[u8]) -> Result { - self.0.remove(key) + self.0.remove(&Hasher::digest(key).0) } fn root(&mut self) -> Result, TrieError> { @@ -30,7 +30,7 @@ impl Trie for MPTTrie { } fn get_proof(&self, key: &[u8]) -> Result>, TrieError> { - self.0.get_proof(key) + self.0.get_proof(&Hasher::digest(key).0) } fn verify_proof( @@ -39,7 +39,8 @@ impl Trie for MPTTrie { key: &[u8], proof: Vec>, ) -> Result>, TrieError> { - self.0.verify_proof(root_hash, key, proof) + self.0 + .verify_proof(root_hash, &Hasher::digest(key).0, proof) } } diff --git a/core/executor/src/tests/system_script/metadata.rs b/core/executor/src/tests/system_script/metadata.rs index cca9cfdc0..3588717f0 100644 --- a/core/executor/src/tests/system_script/metadata.rs +++ b/core/executor/src/tests/system_script/metadata.rs @@ -250,64 +250,3 @@ fn test_set_ckb_related_info() { assert_ne!(new_metadata_root, old_metadata_root); }); } - -// #[tokio::test] -// async fn update_consensus_config() { -// let config: -// crate::system_contract::metadata::metadata_abi::ConsensusConfig = -// ConsensusConfig { gas_limit: 0x3e7fffffc18, -// interval: 0xbb8, -// propose_ratio: 0xf, -// prevote_ratio: 0xa, -// precommit_ratio: 0xa, -// brake_ratio: 0xa, -// tx_num_limit: 0x4e20, -// max_tx_size: 0x186a0000, -// max_contract_limit: 0x8000u64, -// } -// .into(); - -// let tx_data = -// crate::system_contract::metadata::metadata_abi::UpdateConsensusConfigCall { config } -// .encode(); - -// send_eth_tx("http://127.0.0.1:8000", tx_data, METADATA_CONTRACT_ADDRESS).await -// } -// use ethers::prelude::*; -// use ethers::signers::{LocalWallet, Signer}; -// use ethers::types::transaction::eip2718::TypedTransaction::Legacy; -// use ethers::types::{Address, TransactionRequest}; - -// const ADDRESS: &str = "0x8ab0CF264DF99D83525e9E11c7e4db01558AE1b1"; -// const PRIVATE_KEY: &str = -// "37aa0f893d05914a4def0460c0a984d3611546cfb26924d7a7ca6e0db9950a2d"; pub async -// fn send_eth_tx(axon_url: &str, data: Vec, to: Address) { let provider -// = Provider::::try_from(axon_url).unwrap(); - -// let from: Address = ADDRESS.parse().unwrap(); -// let nonce = provider.get_transaction_count(from, None).await.unwrap(); - -// let transaction_request = TransactionRequest::new() -// .chain_id(0x41786f6e) -// .to(to) -// .data(data) -// .from(from) -// .gas_price(1) -// .gas(21000) -// .nonce(nonce); - -// let wallet = LocalWallet::from_str(PRIVATE_KEY).expect( -// "failed to create -// wallet", -// ); -// let tx = Legacy(transaction_request); -// let signature: Signature = wallet.sign_transaction(&tx).await.unwrap(); - -// provider -// .send_raw_transaction(tx.rlp_signed(&signature)) -// .await -// .unwrap() -// .await -// .unwrap() -// .expect("failed to send eth tx"); -// } diff --git a/core/run/src/tests.rs b/core/run/src/tests.rs index 4ba8bb8c3..693764308 100644 --- a/core/run/src/tests.rs +++ b/core/run/src/tests.rs @@ -27,8 +27,8 @@ use protocol::{ tokio, trie::{MemoryDB, PatriciaTrie, Trie as _}, types::{ - Bloom, BloomInput, HardforkInfo, HardforkInfoInner, Header, Metadata, Proposal, H256, - RLP_EMPTY_LIST, RLP_NULL, + Bloom, BloomInput, HardforkInfo, HardforkInfoInner, Hasher, Header, Metadata, Proposal, + H256, RLP_EMPTY_LIST, RLP_NULL, }, }; @@ -49,22 +49,22 @@ const TESTCASES: &[TestCase] = &[ chain_name: "single_node", config_file: "config.toml", chain_spec_file: "specs/single_node/chain-spec.toml", - input_genesis_hash: "0x3428ea0eb8fb33f193e4680772ec6f68279c24bb7f135a8a3f790af6539fc100", - genesis_state_root: "0xe7799df5d8256add895412df5889c4ae07bb5c0d7fa438801b910cfef9d5dc37", + input_genesis_hash: "0x81a546a456b357e2aa153ff1ae52ef72ae88311019e663e0b02d3d17b0a2bab8", + genesis_state_root: "0x9f856541bfd1093d7e05e2b6e04920374bacb77bcfbcce84faaf3ae9dcbb84ec", }, TestCase { chain_name: "multi_nodes", config_file: "nodes/node_1.toml", chain_spec_file: "specs/multi_nodes/chain-spec.toml", - input_genesis_hash: "0xa2559187fdb9bc172ee82b40c9f4f166d56d0ba9dc2fc47538e7d95a8d641575", - genesis_state_root: "0x04b03f59e424ab276cd3a8c54e9f3d51c8f1c9fc64c4b2fda7accd2ddffb46b4", + input_genesis_hash: "0x8cd98b38a4497c589d8d9e3702509fdc2926881c15e6213520f45786c997925b", + genesis_state_root: "0x9640c85b7678de401d32d3a79eb3720e50652cf9779989ecc64f6e16209ed5f3", }, TestCase { chain_name: "multi_nodes_short_epoch_len", config_file: "nodes/node_1.toml", chain_spec_file: "specs/multi_nodes_short_epoch_len/chain-spec.toml", - input_genesis_hash: "0xa710efc9621394b5138a0e9a87c7b8586a88f4d26059bcb06ee76cc5e0bf12b0", - genesis_state_root: "0x3a9030d8e60478866e618a92c5137e02c1f3dc0b20dc5b51f4e720d7a7a58a0b", + input_genesis_hash: "0x176067cef619d3f70986445c8608f5ab2307b999640a7eccab442905741fddca", + genesis_state_root: "0xb99c220162105f73505923d88818d5dd937f14e65b677df1f05a3bb8c4a53265", }, ]; @@ -256,30 +256,39 @@ fn generate_memory_mpt_root(metadata_0: Metadata, metadata_1: Metadata) -> Vec Vec Vec for ExecutorContext { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct EthAccountProof { + pub address: H160, pub balance: U256, pub code_hash: H256, pub nonce: U256, @@ -107,8 +108,8 @@ pub struct EthAccountProof { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct EthStorageProof { - pub key: H256, - pub value: H256, + pub key: U256, + pub value: U256, pub proof: Vec, }