From 61b3bcf6e8c035f7f8c1b8847d49ff9717d2d12d Mon Sep 17 00:00:00 2001 From: Boyu Yang Date: Fri, 25 Aug 2023 13:39:18 +0800 Subject: [PATCH] refactor: impl Trie for MPTTrie --- core/api/src/adapter.rs | 2 + core/executor/benches/bench_transfer.rs | 5 +- core/executor/benches/bench_vm.rs | 9 +- core/executor/benches/revm_adapter.rs | 13 ++- core/executor/src/adapter/backend/apply.rs | 10 +- .../executor/src/adapter/backend/read_only.rs | 3 +- core/executor/src/adapter/trie/wrapped.rs | 93 +++++++++---------- core/executor/src/debugger/mod.rs | 5 +- .../system_contract/ckb_light_client/mod.rs | 1 + .../system_contract/ckb_light_client/store.rs | 16 +++- .../src/system_contract/image_cell/store.rs | 22 +++-- .../src/system_contract/metadata/store.rs | 35 ++++--- core/interoperation/src/tests/mod.rs | 5 +- core/run/src/lib.rs | 11 ++- protocol/src/lib.rs | 9 ++ 15 files changed, 144 insertions(+), 95 deletions(-) diff --git a/core/api/src/adapter.rs b/core/api/src/adapter.rs index 400ef7cf5..045b8abe3 100644 --- a/core/api/src/adapter.rs +++ b/core/api/src/adapter.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use protocol::traits::{ APIAdapter, Context, Executor, ExecutorReadOnlyAdapter, MemPool, Network, ReadOnlyStorage, }; +use protocol::trie::Trie as _; use protocol::types::{ Account, BigEndianHash, Block, BlockNumber, Bytes, CkbRelatedInfo, ExecutorContext, Hash, Header, Metadata, Proposal, Receipt, SignedTransaction, TxResp, H160, H256, @@ -231,6 +232,7 @@ where let hash: Hash = BigEndianHash::from_uint(&position); storage_mpt_tree .get(hash.as_bytes())? + .map(Into::into) .ok_or_else(|| APIError::Adapter("Can't find this position".to_string()).into()) } diff --git a/core/executor/benches/bench_transfer.rs b/core/executor/benches/bench_transfer.rs index 46cad9336..39bb5e019 100644 --- a/core/executor/benches/bench_transfer.rs +++ b/core/executor/benches/bench_transfer.rs @@ -9,6 +9,7 @@ use common_crypto::{ }; use protocol::codec::{hex_decode, ProtocolCodec}; use protocol::traits::Executor; +use protocol::trie::Trie as _; use protocol::types::{ public_to_address, Account, Address, Eip1559Transaction, ExecutorContext, Hash, Public, SignedTransaction, TransactionAction, UnsignedTransaction, UnverifiedTransaction, NIL_DATA, @@ -52,8 +53,8 @@ impl BenchAdapter { }; mpt.insert( - DISTRIBUTE_ADDRESS.as_slice(), - distribute_account.encode().unwrap().as_ref(), + DISTRIBUTE_ADDRESS.as_slice().to_vec(), + distribute_account.encode().unwrap().to_vec(), ) .unwrap(); diff --git a/core/executor/benches/bench_vm.rs b/core/executor/benches/bench_vm.rs index 7022496ae..f34d3fab4 100644 --- a/core/executor/benches/bench_vm.rs +++ b/core/executor/benches/bench_vm.rs @@ -9,7 +9,7 @@ use core_executor::{AxonExecutor, AxonExecutorApplyAdapter, MPTTrie}; use protocol::{ codec::ProtocolCodec, traits::{Executor, Storage}, - trie, + trie::{self, Trie as _}, types::{Account, Address, ExecutorContext}, }; @@ -59,8 +59,11 @@ where let db = Arc::new(db); let mut mpt = MPTTrie::new(Arc::clone(&db)); - mpt.insert(addr.as_slice(), init_account.encode().unwrap().as_ref()) - .unwrap(); + mpt.insert( + addr.as_slice().to_vec(), + init_account.encode().unwrap().to_vec(), + ) + .unwrap(); let state_root = mpt.commit().unwrap(); AxonExecutorApplyAdapter::from_root(state_root, db, Arc::new(storage), exec_ctx).unwrap() diff --git a/core/executor/benches/revm_adapter.rs b/core/executor/benches/revm_adapter.rs index 5e8e33ffc..e758de640 100644 --- a/core/executor/benches/revm_adapter.rs +++ b/core/executor/benches/revm_adapter.rs @@ -7,6 +7,7 @@ use revm::{AccountInfo, Bytecode, Database, DatabaseCommit}; use common_merkle::TrieMerkle; use core_executor::{code_address, MPTTrie}; use protocol::traits::{Context, Storage}; +use protocol::trie::Trie as _; use protocol::types::{ Account, Address, Bytes, ExecResp, ExecutorContext, Hasher, SignedTransaction, TransactionAction, TxResp, H160, H256, NIL_DATA, RLP_NULL, U256, @@ -140,8 +141,10 @@ where MPTTrie::from_root(storage_root, Arc::clone(&self.db)).unwrap() }; change.storage.into_iter().for_each(|(k, v)| { - let _ = - storage_trie.insert(u256_to_u8_slice(&k), u256_to_u8_slice(&v.present_value())); + let _ = storage_trie.insert( + u256_to_u8_slice(&k).to_vec(), + u256_to_u8_slice(&v.present_value()).to_vec(), + ); }); let code_hash = if let Some(code) = change.info.code { @@ -171,7 +174,7 @@ where let account_bytes = new_account.encode().unwrap(); self.trie - .insert(addr.as_bytes(), account_bytes.as_ref()) + .insert(addr.as_bytes().to_vec(), account_bytes.to_vec()) .unwrap(); }); } @@ -187,8 +190,8 @@ where let distribute_account = account; mpt.insert( - addr.as_slice(), - distribute_account.encode().unwrap().as_ref(), + addr.as_slice().to_vec(), + distribute_account.encode().unwrap().to_vec(), ) .unwrap(); diff --git a/core/executor/src/adapter/backend/apply.rs b/core/executor/src/adapter/backend/apply.rs index 7f542d6ef..0877f75f5 100644 --- a/core/executor/src/adapter/backend/apply.rs +++ b/core/executor/src/adapter/backend/apply.rs @@ -6,6 +6,7 @@ use protocol::traits::{ ApplyBackend, Backend, Context, ExecutorAdapter, ExecutorReadOnlyAdapter, ReadOnlyStorage, Storage, }; +use protocol::trie::Trie; use protocol::types::{ Account, Bytes, ExecutorContext, Hasher, Log, MerkleRoot, H160, H256, NIL_DATA, RLP_NULL, U256, }; @@ -130,7 +131,10 @@ where fn save_account(&mut self, address: &H160, account: &Account) { self.inner .trie - .insert(address.as_bytes(), &account.encode().unwrap()) + .insert( + address.as_bytes().to_vec(), + account.encode().unwrap().to_vec(), + ) .unwrap(); } } @@ -171,7 +175,7 @@ where }; storage.into_iter().for_each(|(k, v)| { - let _ = storage_trie.insert(k.as_bytes(), v.as_bytes()); + let _ = storage_trie.insert(k.as_bytes().to_vec(), v.as_bytes().to_vec()); }); let storage_root = storage_trie @@ -207,7 +211,7 @@ where { self.inner .trie - .insert(address.as_bytes(), bytes.as_ref()) + .insert(address.as_bytes().to_vec(), bytes.to_vec()) .unwrap(); } diff --git a/core/executor/src/adapter/backend/read_only.rs b/core/executor/src/adapter/backend/read_only.rs index 361f3e78f..31a3a5d56 100644 --- a/core/executor/src/adapter/backend/read_only.rs +++ b/core/executor/src/adapter/backend/read_only.rs @@ -3,6 +3,7 @@ use std::sync::Arc; 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, }; @@ -32,7 +33,7 @@ where } fn get(&self, key: &[u8]) -> Option { - self.trie.get(key).ok().flatten() + self.trie.get(key).ok().flatten().map(Into::into) } fn get_account(&self, address: &H160) -> Account { diff --git a/core/executor/src/adapter/trie/wrapped.rs b/core/executor/src/adapter/trie/wrapped.rs index 1c07a1d4a..d5b73ca34 100644 --- a/core/executor/src/adapter/trie/wrapped.rs +++ b/core/executor/src/adapter/trie/wrapped.rs @@ -3,73 +3,64 @@ use std::sync::Arc; use hasher::HasherKeccak; use protocol::trie::{PatriciaTrie, Trie, TrieError, DB as TrieDB}; -use protocol::types::{Bytes, MerkleRoot}; -use protocol::{ - codec::hex_encode, Display, From, ProtocolError, ProtocolErrorKind, ProtocolResult, -}; +use protocol::types::MerkleRoot; +use protocol::ProtocolResult; pub struct MPTTrie(PatriciaTrie); -impl MPTTrie { - pub fn new(db: Arc) -> Self { - MPTTrie(PatriciaTrie::new(db, Arc::new(HasherKeccak::new()))) +impl Trie for MPTTrie { + fn get(&self, key: &[u8]) -> Result>, TrieError> { + self.0.get(key) } - pub fn from_root(root: MerkleRoot, db: Arc) -> ProtocolResult { - Ok(MPTTrie( - PatriciaTrie::from(db, Arc::new(HasherKeccak::new()), root.as_bytes()) - .map_err(MPTTrieError::from)?, - )) + fn contains(&self, key: &[u8]) -> Result { + self.0.contains(key) } - pub fn get(&self, key: &[u8]) -> ProtocolResult> { - Ok(self - .0 - .get(key) - .map_err(MPTTrieError::from)? - .map(Bytes::from)) + fn insert(&mut self, key: Vec, value: Vec) -> Result<(), TrieError> { + self.0.insert(key, value) } - pub fn contains(&self, key: &[u8]) -> ProtocolResult { - Ok(self.0.contains(key).map_err(MPTTrieError::from)?) + fn remove(&mut self, key: &[u8]) -> Result { + self.0.remove(key) } - pub fn insert(&mut self, key: &[u8], value: &[u8]) -> ProtocolResult<()> { - self.0 - .insert(key.to_vec(), value.to_vec()) - .map_err(MPTTrieError::from)?; - Ok(()) + fn root(&mut self) -> Result, TrieError> { + self.0.root() } - pub fn remove(&mut self, key: &[u8]) -> ProtocolResult<()> { - if self.0.remove(key).map_err(MPTTrieError::from)? { - Ok(()) - } else { - Err(MPTTrieError::RemoveFailed(hex_encode(key)).into()) - } + fn get_proof(&self, key: &[u8]) -> Result>, TrieError> { + self.0.get_proof(key) } - pub fn commit(&mut self) -> ProtocolResult { - Ok(MerkleRoot::from_slice( - &self.0.root().map_err(MPTTrieError::from)?, - )) + fn verify_proof( + &self, + root_hash: &[u8], + key: &[u8], + proof: Vec>, + ) -> Result>, TrieError> { + self.0.verify_proof(root_hash, key, proof) } } -#[derive(Debug, Display, From)] -pub enum MPTTrieError { - #[display(fmt = "Trie {:?}", _0)] - Trie(TrieError), - - #[display(fmt = "Remove {:?} failed", _0)] - RemoveFailed(String), -} +impl MPTTrie { + pub fn new(db: Arc) -> Self { + MPTTrie(PatriciaTrie::new(db, Arc::new(HasherKeccak::new()))) + } -impl std::error::Error for MPTTrieError {} + pub fn from_root(root: MerkleRoot, db: Arc) -> ProtocolResult { + Ok(MPTTrie(PatriciaTrie::from( + db, + Arc::new(HasherKeccak::new()), + root.as_bytes(), + )?)) + } -impl From for ProtocolError { - fn from(err: MPTTrieError) -> ProtocolError { - ProtocolError::new(ProtocolErrorKind::Executor, Box::new(err)) + pub fn commit(&mut self) -> ProtocolResult { + self.0 + .root() + .map(|r| MerkleRoot::from_slice(&r)) + .map_err(Into::into) } } @@ -99,12 +90,12 @@ mod tests { let key_2 = rand_bytes(10); let val_2 = rand_bytes(20); - mpt.insert(&key_1, &val_1).unwrap(); - mpt.insert(&key_2, &val_2).unwrap(); + mpt.insert(key_1.clone(), val_1.clone()).unwrap(); + mpt.insert(key_2.clone(), val_2.clone()).unwrap(); mpt.commit().unwrap(); - assert_eq!(mpt.get(&key_1).unwrap(), Some(Bytes::from(val_1))); - assert_eq!(mpt.get(&key_2).unwrap(), Some(Bytes::from(val_2))); + assert_eq!(mpt.get(&key_1).unwrap(), Some(val_1)); + assert_eq!(mpt.get(&key_2).unwrap(), Some(val_2)); assert!(mpt.remove(&key_1).is_ok()); assert!(mpt.get(&key_1).unwrap().is_none()); diff --git a/core/executor/src/debugger/mod.rs b/core/executor/src/debugger/mod.rs index 1359c3358..2be9255df 100644 --- a/core/executor/src/debugger/mod.rs +++ b/core/executor/src/debugger/mod.rs @@ -12,6 +12,7 @@ use common_config_parser::parse_file; use common_crypto::{PrivateKey, Secp256k1RecoverablePrivateKey, Signature}; use protocol::codec::{hex_decode, ProtocolCodec}; use protocol::traits::{Backend, Executor}; +use protocol::trie::Trie as _; use protocol::types::{ Account, Eip1559Transaction, ExecResp, ExecutorContext, Hash, Hasher, RichBlock, SignedTransaction, TxResp, UnsignedTransaction, UnverifiedTransaction, H160, H256, @@ -59,8 +60,8 @@ impl EvmDebugger { }; mpt.insert( - distribute_address.as_bytes(), - distribute_account.encode().unwrap().as_ref(), + distribute_address.as_bytes().to_vec(), + distribute_account.encode().unwrap().to_vec(), ) .unwrap(); } diff --git a/core/executor/src/system_contract/ckb_light_client/mod.rs b/core/executor/src/system_contract/ckb_light_client/mod.rs index 9ee4d95dc..6bf877c80 100644 --- a/core/executor/src/system_contract/ckb_light_client/mod.rs +++ b/core/executor/src/system_contract/ckb_light_client/mod.rs @@ -8,6 +8,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use ethers::abi::AbiDecode; use protocol::traits::{ApplyBackend, ExecutorAdapter}; +use protocol::trie::Trie as _; use protocol::types::{SignedTransaction, TxResp, H160, H256}; use protocol::ProtocolResult; diff --git a/core/executor/src/system_contract/ckb_light_client/store.rs b/core/executor/src/system_contract/ckb_light_client/store.rs index 3ebff59cd..151167a97 100644 --- a/core/executor/src/system_contract/ckb_light_client/store.rs +++ b/core/executor/src/system_contract/ckb_light_client/store.rs @@ -2,7 +2,8 @@ use std::sync::Arc; use ethers::abi::{AbiDecode, AbiEncode}; -use protocol::{types::H256, ProtocolResult}; +use protocol::trie::Trie as _; +use protocol::{codec::hex_encode, types::H256, ProtocolResult}; use crate::system_contract::{ ckb_light_client::ckb_light_client_abi, error::SystemScriptError, HEADER_CELL_DB, @@ -71,14 +72,23 @@ impl CkbLightClientStore { fn save_header(&mut self, header: &ckb_light_client_abi::Header) -> ProtocolResult<()> { self.trie - .insert(&header.block_hash, &header.clone().encode()) + .insert(header.block_hash.to_vec(), header.clone().encode().to_vec()) .map_err(|e| SystemScriptError::InsertHeader(e.to_string()).into()) } fn remove_header(&mut self, block_hash: &[u8]) -> ProtocolResult<()> { self.trie .remove(block_hash) - .map_err(|e| SystemScriptError::RemoveHeader(e.to_string()).into()) + .map_err(|e| SystemScriptError::RemoveHeader(e.to_string())) + .and_then(|removed| { + if removed { + Ok(()) + } else { + let content = format!("remove header {} failed", hex_encode(block_hash)); + Err(SystemScriptError::RemoveHeader(content)) + } + }) + .map_err(Into::into) } pub fn commit(&mut self) -> ProtocolResult<()> { diff --git a/core/executor/src/system_contract/image_cell/store.rs b/core/executor/src/system_contract/image_cell/store.rs index d91dd8d16..7df06bf7a 100644 --- a/core/executor/src/system_contract/image_cell/store.rs +++ b/core/executor/src/system_contract/image_cell/store.rs @@ -3,9 +3,7 @@ use std::sync::Arc; use ckb_types::{bytes::Bytes, core::cell::CellMeta, packed, prelude::*}; use rlp::{RlpDecodable, RlpEncodable}; -use protocol::ckb_blake2b_256; -use protocol::types::H256; -use protocol::ProtocolResult; +use protocol::{ckb_blake2b_256, codec::hex_encode, trie::Trie as _, types::H256, ProtocolResult}; use crate::system_contract::image_cell::{image_cell_abi, MPTTrie}; use crate::system_contract::HEADER_CELL_DB; @@ -164,14 +162,24 @@ impl ImageCellStore { pub fn insert_cell(&mut self, key: &CellKey, cell: &CellInfo) -> ProtocolResult<()> { self.trie - .insert(&key.encode(), &rlp::encode(cell)) + .insert(key.encode().to_vec(), rlp::encode(cell).to_vec()) .map_err(|e| SystemScriptError::InsertCell(e.to_string()).into()) } - pub fn remove_cell(&mut self, key: &CellKey) -> ProtocolResult<()> { + pub fn remove_cell(&mut self, cell_key: &CellKey) -> ProtocolResult<()> { + let key = cell_key.encode(); self.trie - .remove(&key.encode()) - .map_err(|e| SystemScriptError::RemoveCell(e.to_string()).into()) + .remove(&key) + .map_err(|e| SystemScriptError::RemoveCell(e.to_string())) + .and_then(|removed| { + if removed { + Ok(()) + } else { + let content = format!("remove cell {} failed", hex_encode(&key)); + Err(SystemScriptError::RemoveCell(content)) + } + }) + .map_err(Into::into) } pub fn commit(&mut self) -> ProtocolResult<()> { diff --git a/core/executor/src/system_contract/metadata/store.rs b/core/executor/src/system_contract/metadata/store.rs index 8c4d29cbc..71d061799 100644 --- a/core/executor/src/system_contract/metadata/store.rs +++ b/core/executor/src/system_contract/metadata/store.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::sync::Arc; +use protocol::trie::Trie as _; use protocol::types::{CkbRelatedInfo, Metadata, H160, H256}; use protocol::{codec::ProtocolCodec, ProtocolResult}; @@ -29,8 +30,8 @@ impl MetadataStore { let trie = if root == H256::default() { let mut m = MPTTrie::new(Arc::clone(&trie_db)); m.insert( - EPOCH_SEGMENT_KEY.as_bytes(), - &EpochSegment::new().as_bytes(), + EPOCH_SEGMENT_KEY.as_bytes().to_vec(), + EpochSegment::new().as_bytes(), )?; m } else { @@ -45,7 +46,11 @@ impl MetadataStore { pub fn set_ckb_related_info(&mut self, info: &CkbRelatedInfo) -> ProtocolResult<()> { self.trie - .insert(CKB_RELATED_INFO_KEY.as_bytes(), &info.encode()?) + .insert( + CKB_RELATED_INFO_KEY.as_bytes().to_vec(), + info.encode()?.to_vec(), + ) + .map_err(Into::into) } pub fn append_metadata(&mut self, metadata: &Metadata) -> ProtocolResult<()> { @@ -81,10 +86,14 @@ impl MetadataStore { epoch_segment.append_endpoint(metadata.version.end)?; - self.trie - .insert(EPOCH_SEGMENT_KEY.as_bytes(), &epoch_segment.as_bytes())?; - self.trie - .insert(&metadata.epoch.to_be_bytes(), &metadata.encode()?)?; + self.trie.insert( + EPOCH_SEGMENT_KEY.as_bytes().to_vec(), + epoch_segment.as_bytes(), + )?; + self.trie.insert( + metadata.epoch.to_be_bytes().to_vec(), + metadata.encode()?.to_vec(), + )?; let new_root = self.trie.commit()?; CURRENT_METADATA_ROOT.with(|r| *r.borrow_mut() = new_root); @@ -105,8 +114,10 @@ impl MetadataStore { counter.increase(); } - self.trie - .insert(&metadata.epoch.to_be_bytes(), &metadata.encode()?)?; + self.trie.insert( + metadata.epoch.to_be_bytes().to_vec(), + metadata.encode()?.to_vec(), + )?; let new_root = self.trie.commit()?; CURRENT_METADATA_ROOT.with(|r| *r.borrow_mut() = new_root); @@ -145,8 +156,10 @@ impl MetadataStore { let mut metadata = self.get_metadata(latest_epoch)?; metadata.consensus_config = config.into(); - self.trie - .insert(&metadata.epoch.to_be_bytes(), &metadata.encode()?)?; + self.trie.insert( + metadata.epoch.to_be_bytes().to_vec(), + metadata.encode()?.to_vec(), + )?; let new_root = self.trie.commit()?; CURRENT_METADATA_ROOT.with(|r| *r.borrow_mut() = new_root); Ok(()) diff --git a/core/interoperation/src/tests/mod.rs b/core/interoperation/src/tests/mod.rs index 3832c2a73..05981956c 100644 --- a/core/interoperation/src/tests/mod.rs +++ b/core/interoperation/src/tests/mod.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use protocol::codec::ProtocolCodec; use protocol::traits::{Context, Executor, Storage}; +use protocol::trie::Trie as _; use protocol::types::{ Account, Address, Bytes, Eip1559Transaction, ExecResp, Proposal, Public, RichBlock, SignatureComponents, SignedTransaction, TransactionAction, UnsignedTransaction, @@ -79,8 +80,8 @@ impl TestHandle { let mut mpt = MPTTrie::new(Arc::clone(&self.trie_db)); mpt.insert( - distribute_address.as_slice(), - distribute_account.encode().unwrap().as_ref(), + distribute_address.as_slice().to_vec(), + distribute_account.encode().unwrap().to_vec(), ) .unwrap(); diff --git a/core/run/src/lib.rs b/core/run/src/lib.rs index 0a2242554..af5577a2c 100644 --- a/core/run/src/lib.rs +++ b/core/run/src/lib.rs @@ -32,6 +32,7 @@ use protocol::traits::{ Consensus, Context, Executor, Gossip, MemPool, Network, NodeInfo, PeerTrust, ReadOnlyStorage, Rpc, Storage, SynchronizationAdapter, }; +use protocol::trie::Trie; use protocol::types::{ Account, Address, Block, ExecResp, MerkleRoot, Metadata, Proposal, RichBlock, SignedTransaction, Validator, ValidatorExtend, H256, NIL_DATA, RLP_NULL, @@ -987,10 +988,10 @@ where } } -fn insert_accounts( - mpt: &mut MPTTrie, - accounts: &[InitialAccount], -) -> ProtocolResult<()> { +fn insert_accounts(mpt: &mut MPTTrie, accounts: &[InitialAccount]) -> ProtocolResult<()> +where + DB: TrieDB, +{ for account in accounts { let raw_account = Account { nonce: 0u64.into(), @@ -999,7 +1000,7 @@ fn insert_accounts( code_hash: NIL_DATA, } .encode()?; - mpt.insert(account.address.as_bytes(), &raw_account)?; + mpt.insert(account.address.as_bytes().to_vec(), raw_account.to_vec())?; } Ok(()) } diff --git a/protocol/src/lib.rs b/protocol/src/lib.rs index c12e4f2f0..6e4aed508 100644 --- a/protocol/src/lib.rs +++ b/protocol/src/lib.rs @@ -65,6 +65,15 @@ impl From for String { } } +impl From for ProtocolError { + fn from(error: trie::TrieError) -> Self { + ProtocolError { + kind: ProtocolErrorKind::DB, + error: Box::new(error), + } + } +} + impl Error for ProtocolError {} pub type ProtocolResult = Result;