mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 19:09:54 +00:00
feat(primitives): state root methods (#5694)
This commit is contained in:
@ -3,7 +3,7 @@ use crate::{
|
||||
EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR, EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
EIP1559_INITIAL_BASE_FEE, EMPTY_RECEIPTS, EMPTY_TRANSACTIONS, EMPTY_WITHDRAWALS,
|
||||
},
|
||||
proofs::genesis_state_root,
|
||||
proofs::state_root_ref_unhashed,
|
||||
revm_primitives::{address, b256},
|
||||
Address, BlockNumber, Chain, ForkFilter, ForkFilterKey, ForkHash, ForkId, Genesis, Hardfork,
|
||||
Head, Header, SealedHeader, B256, EMPTY_OMMER_ROOT_HASH, U256,
|
||||
@ -606,7 +606,7 @@ impl ChainSpec {
|
||||
difficulty: self.genesis.difficulty,
|
||||
nonce: self.genesis.nonce,
|
||||
extra_data: self.genesis.extra_data.clone(),
|
||||
state_root: genesis_state_root(&self.genesis.alloc),
|
||||
state_root: state_root_ref_unhashed(&self.genesis.alloc),
|
||||
timestamp: self.genesis.timestamp,
|
||||
mix_hash: self.genesis.mix_hash,
|
||||
beneficiary: self.genesis.coinbase,
|
||||
@ -1517,8 +1517,8 @@ impl DepositContract {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
b256, hex, ChainConfig, GenesisAccount, NamedChain, B256, DEV, GOERLI, HOLESKY, MAINNET,
|
||||
SEPOLIA, U256,
|
||||
b256, hex, trie::TrieAccount, ChainConfig, GenesisAccount, NamedChain, B256, DEV, GOERLI,
|
||||
HOLESKY, MAINNET, SEPOLIA, U256,
|
||||
};
|
||||
use alloy_rlp::Encodable;
|
||||
use bytes::BytesMut;
|
||||
@ -2520,7 +2520,7 @@ Post-merge hard forks (timestamp based):
|
||||
for (key, expected_rlp) in key_rlp {
|
||||
let account = chainspec.genesis.alloc.get(&key).expect("account should exist");
|
||||
let mut account_rlp = BytesMut::new();
|
||||
account.encode(&mut account_rlp);
|
||||
TrieAccount::from(account.clone()).encode(&mut account_rlp);
|
||||
assert_eq!(account_rlp, expected_rlp)
|
||||
}
|
||||
|
||||
|
||||
@ -1,16 +1,12 @@
|
||||
use crate::{
|
||||
constants::EMPTY_ROOT_HASH,
|
||||
keccak256,
|
||||
serde_helper::{
|
||||
json_u256::{deserialize_json_ttd_opt, deserialize_json_u256},
|
||||
num::{u64_hex_or_decimal, u64_hex_or_decimal_opt},
|
||||
storage::deserialize_storage_map,
|
||||
},
|
||||
trie::{HashBuilder, Nibbles},
|
||||
Account, Address, Bytes, B256, KECCAK_EMPTY, U256,
|
||||
Account, Address, Bytes, B256, U256,
|
||||
};
|
||||
use alloy_rlp::{encode_fixed_size, length_of_length, Encodable, Header as RlpHeader};
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@ -153,19 +149,6 @@ pub struct GenesisAccount {
|
||||
}
|
||||
|
||||
impl GenesisAccount {
|
||||
/// Determines the RLP payload length, without the RLP header.
|
||||
fn payload_len(&self) -> usize {
|
||||
let mut len = 0;
|
||||
len += self.nonce.unwrap_or_default().length();
|
||||
len += self.balance.length();
|
||||
// rather than rlp-encoding the storage, we just return the length of a single hash
|
||||
// hashes are a fixed size, so it is safe to use the empty root for this
|
||||
len += EMPTY_ROOT_HASH.length();
|
||||
// we are encoding a hash, so let's just use the length of the empty hash for the code hash
|
||||
len += KECCAK_EMPTY.length();
|
||||
len
|
||||
}
|
||||
|
||||
/// Set the nonce.
|
||||
pub fn with_nonce(mut self, nonce: Option<u64>) -> Self {
|
||||
self.nonce = nonce;
|
||||
@ -191,45 +174,6 @@ impl GenesisAccount {
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for GenesisAccount {
|
||||
fn encode(&self, out: &mut dyn bytes::BufMut) {
|
||||
let header = RlpHeader { list: true, payload_length: self.payload_len() };
|
||||
header.encode(out);
|
||||
|
||||
self.nonce.unwrap_or_default().encode(out);
|
||||
self.balance.encode(out);
|
||||
self.storage
|
||||
.as_ref()
|
||||
.map_or(EMPTY_ROOT_HASH, |storage| {
|
||||
if storage.is_empty() {
|
||||
return EMPTY_ROOT_HASH
|
||||
}
|
||||
|
||||
let storage_with_sorted_hashed_keys = storage
|
||||
.iter()
|
||||
.filter(|(_k, &v)| v != B256::ZERO)
|
||||
.map(|(slot, value)| (keccak256(slot), value))
|
||||
.sorted_by_key(|(key, _)| *key);
|
||||
|
||||
let mut hb = HashBuilder::default();
|
||||
for (hashed_slot, value) in storage_with_sorted_hashed_keys {
|
||||
let encoded_value = encode_fixed_size(&U256::from_be_bytes(**value));
|
||||
hb.add_leaf(Nibbles::unpack(hashed_slot), &encoded_value);
|
||||
}
|
||||
|
||||
hb.root()
|
||||
})
|
||||
.encode(out);
|
||||
self.code.as_ref().map_or(KECCAK_EMPTY, keccak256).encode(out);
|
||||
}
|
||||
|
||||
fn length(&self) -> usize {
|
||||
let len = self.payload_len();
|
||||
// RLP header length + payload length
|
||||
len + length_of_length(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GenesisAccount> for Account {
|
||||
fn from(value: GenesisAccount) -> Self {
|
||||
Account {
|
||||
|
||||
@ -3,14 +3,14 @@
|
||||
use crate::{
|
||||
constants::EMPTY_OMMER_ROOT_HASH,
|
||||
keccak256,
|
||||
trie::{HashBuilder, Nibbles},
|
||||
Address, GenesisAccount, Header, Receipt, ReceiptWithBloom, ReceiptWithBloomRef,
|
||||
TransactionSigned, Withdrawal, B256,
|
||||
trie::{HashBuilder, Nibbles, TrieAccount},
|
||||
Address, Header, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, TransactionSigned, Withdrawal,
|
||||
B256,
|
||||
};
|
||||
use alloy_primitives::U256;
|
||||
use alloy_rlp::Encodable;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Adjust the index of an item for rlp encoding.
|
||||
pub const fn adjust_index_for_rlp(i: usize, len: usize) -> usize {
|
||||
@ -164,22 +164,73 @@ pub fn calculate_ommers_root(ommers: &[Header]) -> B256 {
|
||||
keccak256(ommers_rlp)
|
||||
}
|
||||
|
||||
/// Calculates the root hash for the state, this corresponds to [geth's
|
||||
/// `deriveHash`](https://github.com/ethereum/go-ethereum/blob/6c149fd4ad063f7c24d726a73bc0546badd1bc73/core/genesis.go#L119).
|
||||
pub fn genesis_state_root(genesis_alloc: &HashMap<Address, GenesisAccount>) -> B256 {
|
||||
let accounts_with_sorted_hashed_keys = genesis_alloc
|
||||
.iter()
|
||||
.map(|(address, account)| (keccak256(address), account))
|
||||
.sorted_by_key(|(key, _)| *key);
|
||||
|
||||
let mut hb = HashBuilder::default();
|
||||
let mut account_rlp_buf = Vec::new();
|
||||
for (hashed_key, account) in accounts_with_sorted_hashed_keys {
|
||||
account_rlp_buf.clear();
|
||||
account.encode(&mut account_rlp_buf);
|
||||
hb.add_leaf(Nibbles::unpack(hashed_key), &account_rlp_buf);
|
||||
/// Hashes and sorts account keys, then proceeds to calculating the root hash of the state
|
||||
/// represented as MPT.
|
||||
/// See [state_root_unsorted] for more info.
|
||||
pub fn state_root_ref_unhashed<'a, A: Into<TrieAccount> + Clone + 'a>(
|
||||
state: impl IntoIterator<Item = (&'a Address, &'a A)>,
|
||||
) -> B256 {
|
||||
state_root_unsorted(
|
||||
state.into_iter().map(|(address, account)| (keccak256(address), account.clone())),
|
||||
)
|
||||
}
|
||||
|
||||
/// Hashes and sorts account keys, then proceeds to calculating the root hash of the state
|
||||
/// represented as MPT.
|
||||
/// See [state_root_unsorted] for more info.
|
||||
pub fn state_root_unhashed<A: Into<TrieAccount>>(
|
||||
state: impl IntoIterator<Item = (Address, A)>,
|
||||
) -> B256 {
|
||||
state_root_unsorted(state.into_iter().map(|(address, account)| (keccak256(address), account)))
|
||||
}
|
||||
|
||||
/// Sorts the hashed account keys and calculates the root hash of the state represented as MPT.
|
||||
/// See [state_root] for more info.
|
||||
pub fn state_root_unsorted<A: Into<TrieAccount>>(
|
||||
state: impl IntoIterator<Item = (B256, A)>,
|
||||
) -> B256 {
|
||||
state_root(state.into_iter().sorted_by_key(|(key, _)| *key))
|
||||
}
|
||||
|
||||
/// Calculates the root hash of the state represented as MPT.
|
||||
/// Corresponds to [geth's `deriveHash`](https://github.com/ethereum/go-ethereum/blob/6c149fd4ad063f7c24d726a73bc0546badd1bc73/core/genesis.go#L119).
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the items are not in sorted order.
|
||||
pub fn state_root<A: Into<TrieAccount>>(state: impl IntoIterator<Item = (B256, A)>) -> B256 {
|
||||
let mut hb = HashBuilder::default();
|
||||
let mut account_rlp_buf = Vec::new();
|
||||
for (hashed_key, account) in state {
|
||||
account_rlp_buf.clear();
|
||||
account.into().encode(&mut account_rlp_buf);
|
||||
hb.add_leaf(Nibbles::unpack(hashed_key), &account_rlp_buf);
|
||||
}
|
||||
hb.root()
|
||||
}
|
||||
|
||||
/// Hashes storage keys, sorts them and them calculates the root hash of the storage trie.
|
||||
/// See [storage_root_unsorted] for more info.
|
||||
pub fn storage_root_unhashed(storage: impl IntoIterator<Item = (B256, U256)>) -> B256 {
|
||||
storage_root_unsorted(storage.into_iter().map(|(slot, value)| (keccak256(slot), value)))
|
||||
}
|
||||
|
||||
/// Sorts and calculates the root hash of account storage trie.
|
||||
/// See [storage_root] for more info.
|
||||
pub fn storage_root_unsorted(storage: impl IntoIterator<Item = (B256, U256)>) -> B256 {
|
||||
storage_root(storage.into_iter().sorted_by_key(|(key, _)| *key))
|
||||
}
|
||||
|
||||
/// Calculates the root hash of account storage trie.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the items are not in sorted order.
|
||||
pub fn storage_root(storage: impl IntoIterator<Item = (B256, U256)>) -> B256 {
|
||||
let mut hb = HashBuilder::default();
|
||||
for (hashed_slot, value) in storage {
|
||||
hb.add_leaf(Nibbles::unpack(hashed_slot), alloy_rlp::encode_fixed_size(&value).as_ref());
|
||||
}
|
||||
hb.root()
|
||||
}
|
||||
|
||||
@ -216,12 +267,13 @@ mod tests {
|
||||
bloom,
|
||||
constants::EMPTY_ROOT_HASH,
|
||||
hex_literal::hex,
|
||||
proofs::{calculate_receipt_root, calculate_transaction_root, genesis_state_root},
|
||||
proofs::{calculate_receipt_root, calculate_transaction_root},
|
||||
Address, Block, GenesisAccount, Log, Receipt, ReceiptWithBloom, TxType, B256, GOERLI,
|
||||
HOLESKY, MAINNET, SEPOLIA, U256,
|
||||
};
|
||||
use alloy_primitives::b256;
|
||||
use alloy_rlp::Decodable;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[test]
|
||||
fn check_transaction_root() {
|
||||
@ -549,8 +601,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn check_empty_state_root() {
|
||||
let genesis_alloc = HashMap::new();
|
||||
let root = genesis_state_root(&genesis_alloc);
|
||||
let genesis_alloc = HashMap::<Address, GenesisAccount>::new();
|
||||
let root = state_root_unhashed(genesis_alloc);
|
||||
assert_eq!(root, EMPTY_ROOT_HASH);
|
||||
}
|
||||
|
||||
@ -577,7 +629,7 @@ mod tests {
|
||||
test_addr,
|
||||
GenesisAccount { nonce: None, balance: U256::MAX, code: None, storage: None },
|
||||
);
|
||||
let root = genesis_state_root(&genesis_alloc);
|
||||
let root = state_root_unhashed(genesis_alloc);
|
||||
|
||||
assert_eq!(root, expected_root);
|
||||
}
|
||||
@ -587,7 +639,7 @@ mod tests {
|
||||
fn test_chain_state_roots() {
|
||||
let expected_mainnet_state_root =
|
||||
b256!("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544");
|
||||
let calculated_mainnet_state_root = genesis_state_root(&MAINNET.genesis.alloc);
|
||||
let calculated_mainnet_state_root = state_root_ref_unhashed(&MAINNET.genesis.alloc);
|
||||
assert_eq!(
|
||||
expected_mainnet_state_root, calculated_mainnet_state_root,
|
||||
"mainnet state root mismatch"
|
||||
@ -595,7 +647,7 @@ mod tests {
|
||||
|
||||
let expected_goerli_state_root =
|
||||
b256!("5d6cded585e73c4e322c30c2f782a336316f17dd85a4863b9d838d2d4b8b3008");
|
||||
let calculated_goerli_state_root = genesis_state_root(&GOERLI.genesis.alloc);
|
||||
let calculated_goerli_state_root = state_root_ref_unhashed(&GOERLI.genesis.alloc);
|
||||
assert_eq!(
|
||||
expected_goerli_state_root, calculated_goerli_state_root,
|
||||
"goerli state root mismatch"
|
||||
@ -603,7 +655,7 @@ mod tests {
|
||||
|
||||
let expected_sepolia_state_root =
|
||||
b256!("5eb6e371a698b8d68f665192350ffcecbbbf322916f4b51bd79bb6887da3f494");
|
||||
let calculated_sepolia_state_root = genesis_state_root(&SEPOLIA.genesis.alloc);
|
||||
let calculated_sepolia_state_root = state_root_ref_unhashed(&SEPOLIA.genesis.alloc);
|
||||
assert_eq!(
|
||||
expected_sepolia_state_root, calculated_sepolia_state_root,
|
||||
"sepolia state root mismatch"
|
||||
@ -611,7 +663,7 @@ mod tests {
|
||||
|
||||
let expected_holesky_state_root =
|
||||
b256!("69d8c9d72f6fa4ad42d4702b433707212f90db395eb54dc20bc85de253788783");
|
||||
let calculated_holesky_state_root = genesis_state_root(&HOLESKY.genesis.alloc);
|
||||
let calculated_holesky_state_root = state_root_ref_unhashed(&HOLESKY.genesis.alloc);
|
||||
assert_eq!(
|
||||
expected_holesky_state_root, calculated_holesky_state_root,
|
||||
"holesky state root mismatch"
|
||||
|
||||
59
crates/primitives/src/trie/account.rs
Normal file
59
crates/primitives/src/trie/account.rs
Normal file
@ -0,0 +1,59 @@
|
||||
use crate::{
|
||||
constants::EMPTY_ROOT_HASH, proofs, Account, GenesisAccount, B256, KECCAK_EMPTY, U256,
|
||||
};
|
||||
use alloy_primitives::keccak256;
|
||||
use alloy_rlp::{RlpDecodable, RlpEncodable};
|
||||
|
||||
/// An Ethereum account as represented in the trie.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)]
|
||||
pub struct TrieAccount {
|
||||
/// Account nonce.
|
||||
nonce: u64,
|
||||
/// Account balance.
|
||||
balance: U256,
|
||||
/// Account's storage root.
|
||||
storage_root: B256,
|
||||
/// Hash of the account's bytecode.
|
||||
code_hash: B256,
|
||||
}
|
||||
|
||||
impl From<(Account, B256)> for TrieAccount {
|
||||
fn from((account, storage_root): (Account, B256)) -> Self {
|
||||
Self {
|
||||
nonce: account.nonce,
|
||||
balance: account.balance,
|
||||
storage_root,
|
||||
code_hash: account.bytecode_hash.unwrap_or(KECCAK_EMPTY),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GenesisAccount> for TrieAccount {
|
||||
fn from(account: GenesisAccount) -> Self {
|
||||
let storage_root = account
|
||||
.storage
|
||||
.map(|storage| {
|
||||
proofs::storage_root_unhashed(
|
||||
storage
|
||||
.into_iter()
|
||||
.filter(|(_, value)| *value != B256::ZERO)
|
||||
.map(|(slot, value)| (slot, U256::from_be_bytes(*value))),
|
||||
)
|
||||
})
|
||||
.unwrap_or(EMPTY_ROOT_HASH);
|
||||
|
||||
Self {
|
||||
nonce: account.nonce.unwrap_or_default(),
|
||||
balance: account.balance,
|
||||
storage_root,
|
||||
code_hash: account.code.map_or(KECCAK_EMPTY, keccak256),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TrieAccount {
|
||||
/// Get account's storage root.
|
||||
pub fn storage_root(&self) -> B256 {
|
||||
self.storage_root
|
||||
}
|
||||
}
|
||||
@ -12,12 +12,14 @@ pub use hash_builder::HashBuilder;
|
||||
mod proofs;
|
||||
pub use proofs::{AccountProof, StorageProof};
|
||||
|
||||
mod account;
|
||||
mod mask;
|
||||
mod nibbles;
|
||||
mod storage;
|
||||
mod subnode;
|
||||
|
||||
pub use self::{
|
||||
account::TrieAccount,
|
||||
mask::TrieMask,
|
||||
nibbles::{Nibbles, StoredNibblesSubKey},
|
||||
storage::StorageTrieEntry,
|
||||
|
||||
@ -1,39 +0,0 @@
|
||||
use alloy_rlp::{RlpDecodable, RlpEncodable};
|
||||
use reth_primitives::{constants::EMPTY_ROOT_HASH, Account, B256, KECCAK_EMPTY, U256};
|
||||
|
||||
/// An Ethereum account as represented in the trie.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)]
|
||||
pub struct EthAccount {
|
||||
/// Account nonce.
|
||||
nonce: u64,
|
||||
/// Account balance.
|
||||
balance: U256,
|
||||
/// Account's storage root.
|
||||
storage_root: B256,
|
||||
/// Hash of the account's bytecode.
|
||||
code_hash: B256,
|
||||
}
|
||||
|
||||
impl From<Account> for EthAccount {
|
||||
fn from(acc: Account) -> Self {
|
||||
EthAccount {
|
||||
nonce: acc.nonce,
|
||||
balance: acc.balance,
|
||||
storage_root: EMPTY_ROOT_HASH,
|
||||
code_hash: acc.bytecode_hash.unwrap_or(KECCAK_EMPTY),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EthAccount {
|
||||
/// Set storage root on account.
|
||||
pub fn with_storage_root(mut self, storage_root: B256) -> Self {
|
||||
self.storage_root = storage_root;
|
||||
self
|
||||
}
|
||||
|
||||
/// Get account's storage root.
|
||||
pub fn storage_root(&self) -> B256 {
|
||||
self.storage_root
|
||||
}
|
||||
}
|
||||
@ -15,9 +15,6 @@
|
||||
#![deny(unused_must_use, rust_2018_idioms)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||
|
||||
/// The Ethereum account as represented in the trie.
|
||||
pub mod account;
|
||||
|
||||
/// The implementation of a container for storing intermediate changes to a trie.
|
||||
/// The container indicates when the trie has been modified.
|
||||
pub mod prefix_set;
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
use crate::{
|
||||
account::EthAccount,
|
||||
hashed_cursor::{HashedCursorFactory, HashedStorageCursor},
|
||||
node_iter::{AccountNode, AccountNodeIter, StorageNode, StorageNodeIter},
|
||||
prefix_set::PrefixSetMut,
|
||||
@ -12,7 +11,7 @@ use reth_db::{tables, transaction::DbTx};
|
||||
use reth_primitives::{
|
||||
constants::EMPTY_ROOT_HASH,
|
||||
keccak256,
|
||||
trie::{AccountProof, HashBuilder, Nibbles, StorageProof},
|
||||
trie::{AccountProof, HashBuilder, Nibbles, StorageProof, TrieAccount},
|
||||
Address, B256,
|
||||
};
|
||||
|
||||
@ -81,7 +80,7 @@ where
|
||||
};
|
||||
|
||||
account_rlp.clear();
|
||||
let account = EthAccount::from(account).with_storage_root(storage_root);
|
||||
let account = TrieAccount::from((account, storage_root));
|
||||
account.encode(&mut account_rlp as &mut dyn BufMut);
|
||||
|
||||
hash_builder.add_leaf(Nibbles::unpack(hashed_address), &account_rlp);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use crate::account::EthAccount;
|
||||
use alloy_rlp::{encode_fixed_size, Encodable};
|
||||
use reth_primitives::{proofs::triehash::KeccakHasher, Account, Address, B256, U256};
|
||||
use reth_primitives::{
|
||||
proofs::triehash::KeccakHasher, trie::TrieAccount, Account, Address, B256, U256,
|
||||
};
|
||||
|
||||
/// Re-export of [triehash].
|
||||
pub use triehash;
|
||||
@ -14,7 +15,7 @@ where
|
||||
let encoded_accounts = accounts.map(|(address, (account, storage))| {
|
||||
let storage_root = storage_root(storage.into_iter());
|
||||
let mut out = Vec::new();
|
||||
EthAccount::from(account).with_storage_root(storage_root).encode(&mut out);
|
||||
TrieAccount::from((account, storage_root)).encode(&mut out);
|
||||
(address, out)
|
||||
});
|
||||
|
||||
@ -37,7 +38,7 @@ where
|
||||
let encoded_accounts = accounts.map(|(address, (account, storage))| {
|
||||
let storage_root = storage_root_prehashed(storage.into_iter());
|
||||
let mut out = Vec::new();
|
||||
EthAccount::from(account).with_storage_root(storage_root).encode(&mut out);
|
||||
TrieAccount::from((account, storage_root)).encode(&mut out);
|
||||
(address, out)
|
||||
});
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
use crate::{
|
||||
account::EthAccount,
|
||||
hashed_cursor::{HashedCursorFactory, HashedStorageCursor},
|
||||
node_iter::{AccountNode, AccountNodeIter, StorageNode, StorageNodeIter},
|
||||
prefix_set::{PrefixSet, PrefixSetLoader, PrefixSetMut},
|
||||
@ -14,7 +13,7 @@ use reth_db::{tables, transaction::DbTx};
|
||||
use reth_primitives::{
|
||||
constants::EMPTY_ROOT_HASH,
|
||||
keccak256,
|
||||
trie::{HashBuilder, Nibbles},
|
||||
trie::{HashBuilder, Nibbles, TrieAccount},
|
||||
Address, BlockNumber, B256,
|
||||
};
|
||||
use std::{
|
||||
@ -287,7 +286,7 @@ where
|
||||
storage_root_calculator.root()?
|
||||
};
|
||||
|
||||
let account = EthAccount::from(account).with_storage_root(storage_root);
|
||||
let account = TrieAccount::from((account, storage_root));
|
||||
|
||||
account_rlp.clear();
|
||||
account.encode(&mut account_rlp as &mut dyn BufMut);
|
||||
@ -769,10 +768,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn encode_account(account: Account, storage_root: Option<B256>) -> Vec<u8> {
|
||||
let mut account = EthAccount::from(account);
|
||||
if let Some(storage_root) = storage_root {
|
||||
account = account.with_storage_root(storage_root);
|
||||
}
|
||||
let account = TrieAccount::from((account, storage_root.unwrap_or(EMPTY_ROOT_HASH)));
|
||||
let mut account_rlp = Vec::with_capacity(account.length());
|
||||
account.encode(&mut account_rlp);
|
||||
account_rlp
|
||||
|
||||
Reference in New Issue
Block a user