From 85239131515ad6820b2a7a96aedd25fa110eca48 Mon Sep 17 00:00:00 2001 From: Kolby Moroz Liebl <31669092+KolbyML@users.noreply.github.com> Date: Wed, 21 Aug 2024 11:58:09 -0600 Subject: [PATCH] fix(state-bridge): storage trie changes weren't being gossiped (#1393) --- Cargo.lock | 2 +- ethportal-api/Cargo.toml | 2 +- portal-bridge/Cargo.toml | 2 +- portal-bridge/src/bridge/state.rs | 29 ++++++++++++------------ trin-execution/Cargo.toml | 2 +- trin-execution/src/content.rs | 2 +- trin-execution/src/storage/account_db.rs | 13 ++++------- trin-execution/src/storage/evm_db.rs | 16 +++++++++---- trin-execution/src/trie_walker.rs | 6 +++-- trin-state/Cargo.toml | 2 +- 10 files changed, 40 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e90f29aa..8012292ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2389,7 +2389,7 @@ dependencies = [ [[package]] name = "eth_trie" version = "0.4.0" -source = "git+https://github.com/kolbyml/eth-trie.rs.git?rev=7e57d3dfadee126cc9fda2696fb039bf7b6ed688#7e57d3dfadee126cc9fda2696fb039bf7b6ed688" +source = "git+https://github.com/kolbyml/eth-trie.rs.git?rev=7947a83091192a7988f359b750b05121d5d7ba8c#7947a83091192a7988f359b750b05121d5d7ba8c" dependencies = [ "alloy-primitives", "alloy-rlp", diff --git a/ethportal-api/Cargo.toml b/ethportal-api/Cargo.toml index cc8357c96..c69f017c3 100644 --- a/ethportal-api/Cargo.toml +++ b/ethportal-api/Cargo.toml @@ -22,7 +22,7 @@ const_format = {version = "0.2.0", features = ["rust_1_64"]} c-kzg = "1.0.0" discv5 = { version = "0.4.1", features = ["serde"] } ethereum_hashing = "0.6.0" -eth_trie = { git = "https://github.com/kolbyml/eth-trie.rs.git", rev = "7e57d3dfadee126cc9fda2696fb039bf7b6ed688" } +eth_trie = { git = "https://github.com/kolbyml/eth-trie.rs.git", rev = "7947a83091192a7988f359b750b05121d5d7ba8c" } ethereum_serde_utils = "0.5.2" ethereum_ssz = "0.5.3" ethereum_ssz_derive = "0.5.3" diff --git a/portal-bridge/Cargo.toml b/portal-bridge/Cargo.toml index 080e71c67..323536d50 100644 --- a/portal-bridge/Cargo.toml +++ b/portal-bridge/Cargo.toml @@ -22,7 +22,7 @@ clap = { version = "4.2.1", features = ["derive"] } discv5 = { version = "0.4.1", features = ["serde"] } ethereum_ssz = "0.5.3" ethportal-api = { path = "../ethportal-api" } -eth_trie = { git = "https://github.com/kolbyml/eth-trie.rs.git", rev = "7e57d3dfadee126cc9fda2696fb039bf7b6ed688" } +eth_trie = { git = "https://github.com/kolbyml/eth-trie.rs.git", rev = "7947a83091192a7988f359b750b05121d5d7ba8c" } e2store = { path = "../e2store" } futures = "0.3.21" jsonrpsee = { version = "0.20.0", features = [ diff --git a/portal-bridge/src/bridge/state.rs b/portal-bridge/src/bridge/state.rs index f2625a7ee..76fcac78d 100644 --- a/portal-bridge/src/bridge/state.rs +++ b/portal-bridge/src/bridge/state.rs @@ -168,11 +168,6 @@ impl StateBridge { }; let account: AccountStateInfo = Decodable::decode(&mut leaf.value.as_slice())?; - // if the code_hash is empty then it isn't a contract so we can skip it - if account.code_hash == keccak256([]) { - continue; - } - // reconstruct the address hash from the path so that we can fetch the // address from the database let mut partial_key_path = leaf.key.get_data().to_vec(); @@ -181,16 +176,19 @@ impl StateBridge { [&account_proof.path.clone(), partial_key_path.as_slice()].concat(); let address_hash = full_nibble_path_to_address_hash(&full_key_path); - // gossip contract bytecode - let code = state.database.code_by_hash_ref(account.code_hash)?; - self.gossip_contract_bytecode( - address_hash, - &account_proof, - block_tuple.header.header.hash(), - account.code_hash, - code, - ) - .await?; + // if the code_hash is empty then then don't try to gossip the contract bytecode + if account.code_hash != keccak256([]) { + // gossip contract bytecode + let code = state.database.code_by_hash_ref(account.code_hash)?; + self.gossip_contract_bytecode( + address_hash, + &account_proof, + block_tuple.header.header.hash(), + account.code_hash, + code, + ) + .await?; + } // gossip contract storage let storage_changed_nodes = state.database.get_storage_trie_diff(address_hash); @@ -209,6 +207,7 @@ impl StateBridge { .await?; } } + // flush the database cache // This is used for gossiping storage trie diffs state.database.storage_cache.clear(); diff --git a/trin-execution/Cargo.toml b/trin-execution/Cargo.toml index 5f7380141..668aadae8 100644 --- a/trin-execution/Cargo.toml +++ b/trin-execution/Cargo.toml @@ -20,7 +20,7 @@ clap = { version = "4.2.1", features = ["derive"] } directories = "3.0" ethportal-api = { path = "../ethportal-api" } e2store = { path = "../e2store" } -eth_trie = { git = "https://github.com/kolbyml/eth-trie.rs.git", rev = "7e57d3dfadee126cc9fda2696fb039bf7b6ed688" } +eth_trie = { git = "https://github.com/kolbyml/eth-trie.rs.git", rev = "7947a83091192a7988f359b750b05121d5d7ba8c" } hashbrown = "0.14.0" lazy_static = "1.4.0" parking_lot = "0.11.2" diff --git a/trin-execution/src/content.rs b/trin-execution/src/content.rs index 7902039c2..723b74c13 100644 --- a/trin-execution/src/content.rs +++ b/trin-execution/src/content.rs @@ -56,7 +56,7 @@ pub fn create_contract_content_value( Ok(StateContentValue::ContractBytecodeWithProof( ContractBytecodeWithProof { block_hash, - code: code.bytecode.to_vec().into(), + code: code.original_bytes().to_vec().into(), account_proof: account_proof.into(), }, )) diff --git a/trin-execution/src/storage/account_db.rs b/trin-execution/src/storage/account_db.rs index 476f5fbb5..ff0638255 100644 --- a/trin-execution/src/storage/account_db.rs +++ b/trin-execution/src/storage/account_db.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use alloy_primitives::{keccak256, Address, B256}; +use alloy_primitives::{keccak256, B256}; use eth_trie::DB; use rocksdb::DB as RocksDB; @@ -16,11 +16,8 @@ pub struct AccountDB { } impl AccountDB { - pub fn new(address: Address, db: Arc) -> Self { - Self { - address_hash: keccak256(address), - db, - } + pub fn new(address_hash: B256, db: Arc) -> Self { + Self { address_hash, db } } fn get_db_key(&self, key: &[u8]) -> Vec { @@ -72,7 +69,7 @@ mod test_account_db { #[test] fn test_account_db_get() { let rocksdb = setup_rocksdb(setup_temp_dir().unwrap().into_path()).unwrap(); - let accdb = AccountDB::new(Address::ZERO, Arc::new(rocksdb)); + let accdb = AccountDB::new(B256::ZERO, Arc::new(rocksdb)); accdb .insert(keccak256(b"test-key").as_slice(), b"test-value".to_vec()) .unwrap(); @@ -86,7 +83,7 @@ mod test_account_db { #[test] fn test_account_db_remove() { let rocksdb = setup_rocksdb(setup_temp_dir().unwrap().into_path()).unwrap(); - let accdb = AccountDB::new(Address::ZERO, Arc::new(rocksdb)); + let accdb = AccountDB::new(B256::ZERO, Arc::new(rocksdb)); accdb .insert(keccak256(b"test").as_slice(), b"test".to_vec()) .unwrap(); diff --git a/trin-execution/src/storage/evm_db.rs b/trin-execution/src/storage/evm_db.rs index 4676748d5..43465e789 100644 --- a/trin-execution/src/storage/evm_db.rs +++ b/trin-execution/src/storage/evm_db.rs @@ -94,9 +94,14 @@ impl EvmDB { .get(&address_hash) .unwrap_or(&HashSet::new()) { + // storage trie keys are prefixed with the address hash in the database let value = self .db - .get(key) + .get( + [address_hash.as_slice(), key.as_slice()] + .concat() + .as_slice(), + ) .expect("Getting storage value should never fail"); if let Some(raw_value) = value { @@ -125,7 +130,7 @@ impl DatabaseCommit for EvmDB { None => RocksAccount::default(), }; if rocks_account.storage_root != keccak256([EMPTY_STRING_CODE]) { - let account_db = AccountDB::new(address, self.db.clone()); + let account_db = AccountDB::new(address_hash, self.db.clone()); let mut trie = EthTrie::from(Arc::new(account_db), rocks_account.storage_root) .expect("Creating trie should never fail"); trie.clear_trie_from_db() @@ -167,7 +172,7 @@ impl DatabaseCommit for EvmDB { rocks_account.nonce = account.info.nonce; rocks_account.code_hash = account.info.code_hash; - let account_db = AccountDB::new(address, self.db.clone()); + let account_db = AccountDB::new(address_hash, self.db.clone()); let mut trie = if rocks_account.storage_root == keccak256([EMPTY_STRING_CODE]) { EthTrie::new(Arc::new(account_db)) @@ -268,11 +273,12 @@ impl DatabaseRef for EvmDB { } fn storage_ref(&self, address: Address, index: U256) -> Result { - let account: RocksAccount = match self.db.get(keccak256(address))? { + let address_hash = keccak256(address); + let account: RocksAccount = match self.db.get(address_hash)? { Some(raw_account) => Decodable::decode(&mut raw_account.as_slice())?, None => return Err(Self::Error::NotFound), }; - let account_db = AccountDB::new(address, self.db.clone()); + let account_db = AccountDB::new(address_hash, self.db.clone()); let trie = if account.storage_root == keccak256([EMPTY_STRING_CODE]) { EthTrie::new(Arc::new(account_db)) } else { diff --git a/trin-execution/src/trie_walker.rs b/trin-execution/src/trie_walker.rs index 4135e2825..86f993dc8 100644 --- a/trin-execution/src/trie_walker.rs +++ b/trin-execution/src/trie_walker.rs @@ -39,8 +39,10 @@ pub struct TrieWalker { impl TrieWalker { pub fn new(root_hash: B256, nodes: BrownHashMap>) -> Self { // if the storage root is empty then there is no storage to gossip - if root_hash == keccak256([EMPTY_STRING_CODE]) && !nodes.is_empty() { - panic!("Root hash is empty but there are nodes to gossip. This should never happen."); + if root_hash == keccak256([EMPTY_STRING_CODE]) { + return Self { + nodes: BrownHashMap::new(), + }; } if nodes.is_empty() { diff --git a/trin-state/Cargo.toml b/trin-state/Cargo.toml index 59189f3b7..0db9fcb48 100644 --- a/trin-state/Cargo.toml +++ b/trin-state/Cargo.toml @@ -15,7 +15,7 @@ alloy-primitives = { version = "0.7.0", features = ["getrandom"] } alloy-rlp = "0.3.4" anyhow = "1.0.68" discv5 = { version = "0.4.1", features = ["serde"] } -eth_trie = { git = "https://github.com/kolbyml/eth-trie.rs.git", rev = "7e57d3dfadee126cc9fda2696fb039bf7b6ed688" } +eth_trie = { git = "https://github.com/kolbyml/eth-trie.rs.git", rev = "7947a83091192a7988f359b750b05121d5d7ba8c" } ethportal-api = { path = "../ethportal-api" } keccak-hash = "0.10.0" parking_lot = "0.11.2"