diff --git a/Cargo.lock b/Cargo.lock index c964ab2855d9..8fae53681028 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,9 +109,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-chains" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03fd095a9d70f4b1c5c102c84a4c782867a5c6416dbf6dcd42a63e7c7a89d3c8" +checksum = "24ceb48af11349cd7fbd12aa739800be3c4b3965f640b7ae26666907f3bdf091" dependencies = [ "alloy-rlp", "arbitrary", @@ -140,7 +140,7 @@ dependencies = [ [[package]] name = "alloy-consensus" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#7578618d61213ea832c40c7e613f1d644ce08f27" +source = "git+https://github.com/alloy-rs/alloy#b000e16f06161c15b42a4c59f27cb3feb23b3c14" dependencies = [ "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy)", "alloy-primitives", @@ -189,7 +189,7 @@ dependencies = [ [[package]] name = "alloy-eips" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#7578618d61213ea832c40c7e613f1d644ce08f27" +source = "git+https://github.com/alloy-rs/alloy#b000e16f06161c15b42a4c59f27cb3feb23b3c14" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -214,7 +214,7 @@ dependencies = [ [[package]] name = "alloy-genesis" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#7578618d61213ea832c40c7e613f1d644ce08f27" +source = "git+https://github.com/alloy-rs/alloy#b000e16f06161c15b42a4c59f27cb3feb23b3c14" dependencies = [ "alloy-primitives", "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy)", @@ -418,7 +418,7 @@ dependencies = [ [[package]] name = "alloy-rpc-types" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#7578618d61213ea832c40c7e613f1d644ce08f27" +source = "git+https://github.com/alloy-rs/alloy#b000e16f06161c15b42a4c59f27cb3feb23b3c14" dependencies = [ "alloy-rpc-types-eth 0.1.0 (git+https://github.com/alloy-rs/alloy)", "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy)", @@ -490,7 +490,7 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#7578618d61213ea832c40c7e613f1d644ce08f27" +source = "git+https://github.com/alloy-rs/alloy#b000e16f06161c15b42a4c59f27cb3feb23b3c14" dependencies = [ "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy)", "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy)", @@ -530,7 +530,7 @@ dependencies = [ [[package]] name = "alloy-serde" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#7578618d61213ea832c40c7e613f1d644ce08f27" +source = "git+https://github.com/alloy-rs/alloy#b000e16f06161c15b42a4c59f27cb3feb23b3c14" dependencies = [ "alloy-primitives", "serde", @@ -680,7 +680,7 @@ dependencies = [ "alloy-transport", "bytes", "futures", - "interprocess 2.1.1", + "interprocess 2.2.0", "pin-project", "serde_json", "tokio", @@ -697,7 +697,7 @@ dependencies = [ "alloy-transport", "futures", "http 1.1.0", - "rustls 0.23.9", + "rustls 0.23.10", "serde_json", "tokio", "tokio-tungstenite", @@ -1122,9 +1122,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.72" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -3647,9 +3647,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3935c160d00ac752e09787e6e6bfc26494c2183cc922f1bc678a60d4733bc2" +checksum = "d0e7a4dd27b9476dc40cb050d3632d3bba3a70ddbff012285f7f8559a1e7e545" [[package]] name = "httpdate" @@ -3728,7 +3728,7 @@ dependencies = [ "hyper", "hyper-util", "log", - "rustls 0.23.9", + "rustls 0.23.10", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -4110,9 +4110,9 @@ dependencies = [ [[package]] name = "interprocess" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f2533e1f1a70bec71ea7a85d1c0a4dab141c314035ce76e51a19a2f48be708" +checksum = "67bafc2f5dbdad79a6d925649758d5472647b416028099f0b829d1b67fdd47d3" dependencies = [ "doctest-file", "futures-core", @@ -4285,7 +4285,7 @@ dependencies = [ "http 1.1.0", "jsonrpsee-core", "pin-project", - "rustls 0.23.9", + "rustls 0.23.10", "rustls-pki-types", "rustls-platform-verifier", "soketto", @@ -4340,7 +4340,7 @@ dependencies = [ "hyper-util", "jsonrpsee-core", "jsonrpsee-types", - "rustls 0.23.9", + "rustls 0.23.10", "rustls-platform-verifier", "serde", "serde_json", @@ -4605,9 +4605,9 @@ dependencies = [ [[package]] name = "libp2p-identity" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999ec70441b2fb35355076726a6bc466c932e9bdc66f6a11c6c0aa17c7ab9be0" +checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" dependencies = [ "asn1_der", "bs58", @@ -4835,9 +4835,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "6d0d8b92cd8358e8d229c11df9358decae64d137c5be540952c5ca7b25aea768" [[package]] name = "memmap2" @@ -5333,9 +5333,9 @@ dependencies = [ [[package]] name = "object" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" dependencies = [ "memchr", ] @@ -6656,7 +6656,7 @@ dependencies = [ "reth-stages-types", "reth-storage-errors", "reth-tracing", - "reth-trie-types", + "reth-trie-common", "rustc-hash", "serde", "serde_json", @@ -6690,7 +6690,7 @@ dependencies = [ "reth-prune-types", "reth-stages-types", "reth-storage-errors", - "reth-trie-types", + "reth-trie-common", "serde", "serde_json", "test-fuzz", @@ -7711,12 +7711,9 @@ dependencies = [ "c-kzg", "criterion", "derive_more", - "hash-db", - "itertools 0.12.1", "modular-bitfield", "nybbles", "once_cell", - "plain_hasher", "pprof", "proptest", "proptest-derive", @@ -7727,7 +7724,7 @@ dependencies = [ "reth-network-peers", "reth-primitives-traits", "reth-static-file-types", - "reth-trie-types", + "reth-trie-common", "revm", "revm-primitives", "roaring", @@ -8077,6 +8074,7 @@ dependencies = [ "alloy-rpc-types 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=00d81d7)", "reth-primitives", "reth-rpc-types", + "reth-trie-common", "serde_json", ] @@ -8162,7 +8160,7 @@ dependencies = [ "proptest-derive", "rand 0.8.5", "reth-codecs", - "reth-trie-types", + "reth-trie-common", "serde", "test-fuzz", ] @@ -8329,7 +8327,7 @@ dependencies = [ "reth-provider", "reth-stages-types", "reth-storage-errors", - "reth-trie-types", + "reth-trie-common", "revm", "serde_json", "similar-asserts", @@ -8339,6 +8337,34 @@ dependencies = [ "triehash", ] +[[package]] +name = "reth-trie-common" +version = "1.0.0-rc.1" +dependencies = [ + "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=00d81d7)", + "alloy-genesis 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=00d81d7)", + "alloy-primitives", + "alloy-rlp", + "alloy-trie", + "arbitrary", + "assert_matches", + "bytes", + "derive_more", + "hash-db", + "itertools 0.12.1", + "nybbles", + "plain_hasher", + "proptest", + "proptest-derive", + "reth-codecs", + "reth-primitives-traits", + "revm-primitives", + "serde", + "serde_json", + "test-fuzz", + "toml", +] + [[package]] name = "reth-trie-parallel" version = "1.0.0-rc.1" @@ -8364,27 +8390,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "reth-trie-types" -version = "1.0.0-rc.1" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "alloy-trie", - "arbitrary", - "assert_matches", - "bytes", - "derive_more", - "nybbles", - "proptest", - "proptest-derive", - "reth-codecs", - "serde", - "serde_json", - "test-fuzz", - "toml", -] - [[package]] name = "revm" version = "9.0.0" @@ -8695,9 +8700,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.9" +version = "0.23.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a218f0f6d05669de4eabfb24f31ce802035c952429d037507b4a4a39f0e60c5b" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" dependencies = [ "log", "once_cell", @@ -8748,7 +8753,7 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.9", + "rustls 0.23.10", "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", @@ -9855,7 +9860,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.9", + "rustls 0.23.10", "rustls-pki-types", "tokio", ] @@ -9880,7 +9885,7 @@ checksum = "becd34a233e7e31a3dbf7c7241b38320f57393dcae8e7324b0167d21b8e320b0" dependencies = [ "futures-util", "log", - "rustls 0.23.9", + "rustls 0.23.10", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -10221,7 +10226,7 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "rustls 0.23.9", + "rustls 0.23.10", "rustls-pki-types", "sha1", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 09ac3ac2bdd9..e55c73f43247 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,9 +99,9 @@ members = [ "crates/tokio-util/", "crates/tracing/", "crates/transaction-pool/", + "crates/trie/common", "crates/trie/parallel/", "crates/trie/trie", - "crates/trie/types", "examples/beacon-api-sidecar-fetcher/", "examples/beacon-api-sse/", "examples/bsc-p2p", @@ -332,8 +332,8 @@ reth-tokio-util = { path = "crates/tokio-util" } reth-tracing = { path = "crates/tracing" } reth-transaction-pool = { path = "crates/transaction-pool" } reth-trie = { path = "crates/trie/trie" } +reth-trie-common = { path = "crates/trie/common" } reth-trie-parallel = { path = "crates/trie/parallel" } -reth-trie-types = { path = "crates/trie/types" } # revm revm = { version = "9.0.0", features = [ diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index 5c8ee5623d22..5359212d1757 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -1383,7 +1383,7 @@ mod tests { use reth_primitives::{ constants::{EIP1559_INITIAL_BASE_FEE, EMPTY_ROOT_HASH, ETHEREUM_BLOCK_GAS_LIMIT}, keccak256, - proofs::{calculate_transaction_root, state_root_unhashed}, + proofs::calculate_transaction_root, revm_primitives::AccountInfo, Account, Address, ChainSpecBuilder, Genesis, GenesisAccount, Header, Signature, Transaction, TransactionSigned, TransactionSignedEcRecovered, TxEip1559, Withdrawals, B256, @@ -1394,7 +1394,7 @@ mod tests { ProviderFactory, }; use reth_stages_api::StageCheckpoint; - use reth_trie::StateRoot; + use reth_trie::{root::state_root_unhashed, StateRoot}; use std::collections::HashMap; fn setup_externals( diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 0add20276386..f1b68e4e5a98 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -18,7 +18,7 @@ reth-codecs.workspace = true reth-ethereum-forks.workspace = true reth-network-peers.workspace = true reth-static-file-types.workspace = true -reth-trie-types.workspace = true +reth-trie-common.workspace = true revm.workspace = true revm-primitives = { workspace = true, features = ["serde"] } @@ -27,7 +27,6 @@ alloy-chains = { workspace = true, features = ["serde", "rlp"] } alloy-consensus = { workspace = true, features = ["arbitrary", "serde"] } alloy-primitives = { workspace = true, features = ["rand", "rlp"] } alloy-rlp = { workspace = true, features = ["arrayvec"] } -alloy-trie = { workspace = true, features = ["serde"] } alloy-rpc-types = { workspace = true, optional = true } alloy-genesis.workspace = true alloy-eips = { workspace = true, features = ["serde"] } @@ -45,7 +44,6 @@ c-kzg = { workspace = true, features = ["serde"], optional = true } bytes.workspace = true byteorder = "1" derive_more.workspace = true -itertools.workspace = true modular-bitfield.workspace = true once_cell.workspace = true rayon.workspace = true @@ -56,10 +54,6 @@ thiserror.workspace = true zstd = { version = "0.13", features = ["experimental"], optional = true } roaring = "0.10.2" -# `test-utils` feature -hash-db = { version = "~0.15", optional = true } -plain_hasher = { version = "0.2", optional = true } - # arbitrary utils arbitrary = { workspace = true, features = ["derive"], optional = true } proptest = { workspace = true, optional = true } @@ -82,9 +76,6 @@ test-fuzz.workspace = true toml.workspace = true triehash = "0.8" -hash-db = "~0.15" -plain_hasher = "0.2" - sucds = "0.8.1" criterion.workspace = true @@ -126,7 +117,7 @@ optimism = [ "revm/optimism", ] alloy-compat = ["alloy-rpc-types"] -test-utils = ["dep:plain_hasher", "dep:hash-db"] +test-utils = [] [[bench]] name = "recover_ecdsa_crit" @@ -137,11 +128,6 @@ name = "validate_blob_tx" required-features = ["arbitrary", "c-kzg"] harness = false -[[bench]] -name = "trie_root" -required-features = ["arbitrary", "test-utils"] -harness = false - [[bench]] name = "integer_list" harness = false diff --git a/crates/primitives/src/chain/spec.rs b/crates/primitives/src/chain/spec.rs index 5bdc5d9c22a3..74c94b345fca 100644 --- a/crates/primitives/src/chain/spec.rs +++ b/crates/primitives/src/chain/spec.rs @@ -5,13 +5,13 @@ use crate::{ }, holesky_nodes, net::{goerli_nodes, mainnet_nodes, sepolia_nodes}, - proofs::state_root_ref_unhashed, revm_primitives::{address, b256}, Address, BlockNumber, Chain, ChainKind, ForkFilter, ForkFilterKey, ForkHash, ForkId, Genesis, Hardfork, Head, Header, NamedChain, NodeRecord, SealedHeader, B256, EMPTY_OMMER_ROOT_HASH, MAINNET_DEPOSIT_CONTRACT, U256, }; use once_cell::sync::Lazy; +use reth_trie_common::root::state_root_ref_unhashed; use serde::{Deserialize, Serialize}; use std::{ collections::BTreeMap, @@ -1726,8 +1726,10 @@ impl OptimismGenesisInfo { #[cfg(test)] mod tests { + use reth_trie_common::TrieAccount; + use super::*; - use crate::{b256, hex, proofs::IntoTrieAccount, ChainConfig, GenesisAccount}; + use crate::{b256, hex, ChainConfig, GenesisAccount}; use std::{collections::HashMap, str::FromStr}; fn test_fork_ids(spec: &ChainSpec, cases: &[(Head, ForkId)]) { for (block, expected_id) in cases { @@ -2829,10 +2831,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"); - assert_eq!( - &alloy_rlp::encode(IntoTrieAccount::to_trie_account(account.clone())), - expected_rlp - ); + assert_eq!(&alloy_rlp::encode(TrieAccount::from(account.clone())), expected_rlp); } assert_eq!(chainspec.genesis_hash, None); diff --git a/crates/primitives/src/proofs/mod.rs b/crates/primitives/src/proofs.rs similarity index 88% rename from crates/primitives/src/proofs/mod.rs rename to crates/primitives/src/proofs.rs index dbce919496e5..b5a050434eaa 100644 --- a/crates/primitives/src/proofs/mod.rs +++ b/crates/primitives/src/proofs.rs @@ -1,58 +1,12 @@ //! Helper function for calculating Merkle proofs and hashes. use crate::{ - constants::EMPTY_OMMER_ROOT_HASH, keccak256, Address, Header, Receipt, ReceiptWithBloom, - ReceiptWithBloomRef, Request, TransactionSigned, Withdrawal, B256, U256, + constants::EMPTY_OMMER_ROOT_HASH, keccak256, Header, Receipt, ReceiptWithBloom, + ReceiptWithBloomRef, Request, TransactionSigned, Withdrawal, B256, }; -use reth_trie_types::{hash_builder::HashBuilder, Nibbles}; - -mod types; -pub use types::{AccountProof, StorageProof}; -mod traits; -pub use traits::IntoTrieAccount; +use reth_trie_common::root::{ordered_trie_root, ordered_trie_root_with_encoder}; use alloy_eips::eip7685::Encodable7685; -use alloy_rlp::Encodable; -use itertools::Itertools; - -/// Adjust the index of an item for rlp encoding. -pub const fn adjust_index_for_rlp(i: usize, len: usize) -> usize { - if i > 0x7f { - i - } else if i == 0x7f || i + 1 == len { - 0 - } else { - i + 1 - } -} - -/// Compute a trie root of the collection of rlp encodable items. -pub fn ordered_trie_root(items: &[T]) -> B256 { - ordered_trie_root_with_encoder(items, |item, buf| item.encode(buf)) -} - -/// Compute a trie root of the collection of items with a custom encoder. -pub fn ordered_trie_root_with_encoder(items: &[T], mut encode: F) -> B256 -where - F: FnMut(&T, &mut Vec), -{ - let mut value_buffer = Vec::new(); - - let mut hb = HashBuilder::default(); - let items_len = items.len(); - for i in 0..items_len { - let index = adjust_index_for_rlp(i, items_len); - - let index_buffer = alloy_rlp::encode_fixed_size(&index); - - value_buffer.clear(); - encode(&items[index], &mut value_buffer); - - hb.add_leaf(Nibbles::unpack(&index_buffer), &value_buffer); - } - - hb.root() -} /// Calculate a transaction root. /// @@ -175,109 +129,16 @@ pub fn calculate_ommers_root(ommers: &[Header]) -> B256 { keccak256(ommers_rlp) } -/// 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: IntoTrieAccount + Clone + 'a>( - state: impl IntoIterator, -) -> 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( - state: impl IntoIterator, -) -> 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(state: impl IntoIterator) -> 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(state: impl IntoIterator) -> B256 { - let mut hb = HashBuilder::default(); - let mut account_rlp_buf = Vec::new(); - for (hashed_key, account) in state { - account_rlp_buf.clear(); - account.to_trie_account().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) -> 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) -> 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) -> 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() -} - -/// Implementation of hasher using our keccak256 hashing function -/// for compatibility with `triehash` crate. -#[cfg(any(test, feature = "test-utils"))] -pub mod triehash { - use super::{keccak256, B256}; - use hash_db::Hasher; - use plain_hasher::PlainHasher; - - /// A [Hasher] that calculates a keccak256 hash of the given data. - #[derive(Default, Debug, Clone, PartialEq, Eq)] - #[non_exhaustive] - pub struct KeccakHasher; - - #[cfg(any(test, feature = "test-utils"))] - impl Hasher for KeccakHasher { - type Out = B256; - type StdHasher = PlainHasher; - - const LENGTH: usize = 32; - - fn hash(x: &[u8]) -> Self::Out { - keccak256(x) - } - } -} - #[cfg(test)] mod tests { use super::*; use crate::{ bloom, constants::EMPTY_ROOT_HASH, hex_literal::hex, Block, GenesisAccount, Log, TxType, - GOERLI, HOLESKY, MAINNET, SEPOLIA, + GOERLI, HOLESKY, MAINNET, SEPOLIA, U256, }; - use alloy_primitives::{b256, LogData}; + use alloy_primitives::{b256, Address, LogData}; use alloy_rlp::Decodable; + use reth_trie_common::root::{state_root_ref_unhashed, state_root_unhashed}; use std::collections::HashMap; #[test] diff --git a/crates/primitives/src/proofs/traits.rs b/crates/primitives/src/proofs/traits.rs deleted file mode 100644 index 7fef86944b7b..000000000000 --- a/crates/primitives/src/proofs/traits.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::Account; -use alloy_consensus::constants::{EMPTY_ROOT_HASH, KECCAK_EMPTY}; -use alloy_genesis::GenesisAccount; -use alloy_primitives::{keccak256, B256, U256}; -use reth_trie_types::TrieAccount; -use revm_primitives::AccountInfo; - -/// Converts a type into a [`TrieAccount`]. -pub trait IntoTrieAccount { - /// Converts to this type into a [`TrieAccount`]. - fn to_trie_account(self) -> TrieAccount; -} - -impl IntoTrieAccount for GenesisAccount { - fn to_trie_account(self) -> TrieAccount { - let storage_root = self - .storage - .map(|storage| { - super::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); - - TrieAccount { - nonce: self.nonce.unwrap_or_default(), - balance: self.balance, - storage_root, - code_hash: self.code.map_or(KECCAK_EMPTY, keccak256), - } - } -} - -impl IntoTrieAccount for (Account, B256) { - fn to_trie_account(self) -> TrieAccount { - let (account, storage_root) = self; - TrieAccount { - nonce: account.nonce, - balance: account.balance, - storage_root, - code_hash: account.bytecode_hash.unwrap_or(KECCAK_EMPTY), - } - } -} - -impl IntoTrieAccount for (AccountInfo, B256) { - fn to_trie_account(self) -> TrieAccount { - let (account, storage_root) = self; - TrieAccount { - nonce: account.nonce, - balance: account.balance, - storage_root, - code_hash: account.code_hash, - } - } -} diff --git a/crates/revm/src/test_utils.rs b/crates/revm/src/test_utils.rs index bfab663dafff..90ac4ea0466e 100644 --- a/crates/revm/src/test_utils.rs +++ b/crates/revm/src/test_utils.rs @@ -1,10 +1,9 @@ use reth_primitives::{ - keccak256, proofs::AccountProof, Account, Address, BlockNumber, Bytecode, Bytes, StorageKey, - B256, U256, + keccak256, Account, Address, BlockNumber, Bytecode, Bytes, StorageKey, B256, U256, }; use reth_storage_api::{AccountReader, BlockHashReader, StateProvider, StateRootProvider}; use reth_storage_errors::provider::ProviderResult; -use reth_trie::updates::TrieUpdates; +use reth_trie::{updates::TrieUpdates, AccountProof}; use revm::db::BundleState; use std::collections::HashMap; diff --git a/crates/rpc/rpc-types-compat/Cargo.toml b/crates/rpc/rpc-types-compat/Cargo.toml index fa21f15c5544..a589ef418c64 100644 --- a/crates/rpc/rpc-types-compat/Cargo.toml +++ b/crates/rpc/rpc-types-compat/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dependencies] reth-primitives.workspace = true reth-rpc-types.workspace = true +reth-trie-common.workspace = true alloy-rlp.workspace = true alloy-rpc-types.workspace = true diff --git a/crates/rpc/rpc-types-compat/src/proof.rs b/crates/rpc/rpc-types-compat/src/proof.rs index 17e5cc193633..9d2fec876b0c 100644 --- a/crates/rpc/rpc-types-compat/src/proof.rs +++ b/crates/rpc/rpc-types-compat/src/proof.rs @@ -1,12 +1,10 @@ //! Compatibility functions for rpc proof related types. -use reth_primitives::{ - proofs::{AccountProof, StorageProof}, - U64, -}; +use reth_primitives::U64; use reth_rpc_types::{ serde_helpers::JsonStorageKey, EIP1186AccountProofResponse, EIP1186StorageProof, }; +use reth_trie_common::{AccountProof, StorageProof}; /// Creates a new rpc storage proof from a primitive storage proof type. pub fn from_primitive_storage_proof(proof: StorageProof) -> EIP1186StorageProof { diff --git a/crates/stages/types/Cargo.toml b/crates/stages/types/Cargo.toml index ab64a89c9036..973cd572ce0b 100644 --- a/crates/stages/types/Cargo.toml +++ b/crates/stages/types/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] reth-codecs.workspace = true -reth-trie-types.workspace = true +reth-trie-common.workspace = true alloy-primitives.workspace = true modular-bitfield.workspace = true diff --git a/crates/stages/types/src/checkpoints.rs b/crates/stages/types/src/checkpoints.rs index b78751cc675b..bc424282b01c 100644 --- a/crates/stages/types/src/checkpoints.rs +++ b/crates/stages/types/src/checkpoints.rs @@ -1,7 +1,7 @@ use alloy_primitives::{Address, BlockNumber, B256}; use bytes::Buf; use reth_codecs::{main_codec, Compact}; -use reth_trie_types::{hash_builder::HashBuilderState, StoredSubNode}; +use reth_trie_common::{hash_builder::HashBuilderState, StoredSubNode}; use std::ops::RangeInclusive; use super::StageId; diff --git a/crates/storage/db-api/Cargo.toml b/crates/storage/db-api/Cargo.toml index fbbf0ca5d7be..a3ecc56f8534 100644 --- a/crates/storage/db-api/Cargo.toml +++ b/crates/storage/db-api/Cargo.toml @@ -18,7 +18,7 @@ reth-primitives.workspace = true reth-prune-types.workspace = true reth-storage-errors.workspace = true reth-stages-types.workspace = true -reth-trie-types.workspace = true +reth-trie-common.workspace = true # codecs modular-bitfield.workspace = true diff --git a/crates/storage/db-api/src/models/mod.rs b/crates/storage/db-api/src/models/mod.rs index 7438feedea51..f5ef4ea5fcce 100644 --- a/crates/storage/db-api/src/models/mod.rs +++ b/crates/storage/db-api/src/models/mod.rs @@ -8,7 +8,7 @@ use reth_codecs::{main_codec, Compact}; use reth_primitives::{Address, B256, *}; use reth_prune_types::{PruneCheckpoint, PruneSegment}; use reth_stages_types::StageCheckpoint; -use reth_trie_types::{StoredNibbles, StoredNibblesSubKey, *}; +use reth_trie_common::{StoredNibbles, StoredNibblesSubKey, *}; pub mod accounts; pub mod blocks; diff --git a/crates/storage/db/Cargo.toml b/crates/storage/db/Cargo.toml index e144e81271b7..2bac4c107867 100644 --- a/crates/storage/db/Cargo.toml +++ b/crates/storage/db/Cargo.toml @@ -25,7 +25,7 @@ reth-nippy-jar.workspace = true reth-prune-types.workspace = true reth-stages-types.workspace = true reth-tracing.workspace = true -reth-trie-types.workspace = true +reth-trie-common.workspace = true # codecs serde = { workspace = true, default-features = false } diff --git a/crates/storage/db/src/tables/mod.rs b/crates/storage/db/src/tables/mod.rs index 5d3c685a526f..367a7dd5531e 100644 --- a/crates/storage/db/src/tables/mod.rs +++ b/crates/storage/db/src/tables/mod.rs @@ -37,7 +37,7 @@ use reth_primitives::{ }; use reth_prune_types::{PruneCheckpoint, PruneSegment}; use reth_stages_types::StageCheckpoint; -use reth_trie_types::{StorageTrieEntry, StoredBranchNode, StoredNibbles, StoredNibblesSubKey}; +use reth_trie_common::{StorageTrieEntry, StoredBranchNode, StoredNibbles, StoredNibblesSubKey}; use serde::{Deserialize, Serialize}; use std::fmt; diff --git a/crates/storage/provider/src/providers/bundle_state_provider.rs b/crates/storage/provider/src/providers/bundle_state_provider.rs index aec1ce18284b..49fb196ffb18 100644 --- a/crates/storage/provider/src/providers/bundle_state_provider.rs +++ b/crates/storage/provider/src/providers/bundle_state_provider.rs @@ -1,9 +1,9 @@ use crate::{ AccountReader, BlockHashReader, ExecutionDataProvider, StateProvider, StateRootProvider, }; -use reth_primitives::{proofs::AccountProof, Account, Address, BlockNumber, Bytecode, B256}; +use reth_primitives::{Account, Address, BlockNumber, Bytecode, B256}; use reth_storage_errors::provider::{ProviderError, ProviderResult}; -use reth_trie::updates::TrieUpdates; +use reth_trie::{updates::TrieUpdates, AccountProof}; use revm::db::BundleState; /// A state provider that resolves to data from either a wrapped [`crate::ExecutionOutcome`] diff --git a/crates/storage/provider/src/providers/state/historical.rs b/crates/storage/provider/src/providers/state/historical.rs index d0304c1c4ac1..12545fe7838e 100644 --- a/crates/storage/provider/src/providers/state/historical.rs +++ b/crates/storage/provider/src/providers/state/historical.rs @@ -10,11 +10,11 @@ use reth_db_api::{ transaction::DbTx, }; use reth_primitives::{ - constants::EPOCH_SLOTS, proofs::AccountProof, Account, Address, BlockNumber, Bytecode, - StaticFileSegment, StorageKey, StorageValue, B256, + constants::EPOCH_SLOTS, Account, Address, BlockNumber, Bytecode, StaticFileSegment, StorageKey, + StorageValue, B256, }; use reth_storage_errors::provider::ProviderResult; -use reth_trie::{updates::TrieUpdates, HashedPostState}; +use reth_trie::{updates::TrieUpdates, AccountProof, HashedPostState}; use revm::db::BundleState; use std::fmt::Debug; diff --git a/crates/storage/provider/src/providers/state/latest.rs b/crates/storage/provider/src/providers/state/latest.rs index a8e554461de3..56b4ecc38b11 100644 --- a/crates/storage/provider/src/providers/state/latest.rs +++ b/crates/storage/provider/src/providers/state/latest.rs @@ -8,11 +8,10 @@ use reth_db_api::{ transaction::DbTx, }; use reth_primitives::{ - proofs::AccountProof, Account, Address, BlockNumber, Bytecode, StaticFileSegment, StorageKey, - StorageValue, B256, + Account, Address, BlockNumber, Bytecode, StaticFileSegment, StorageKey, StorageValue, B256, }; use reth_storage_errors::provider::{ProviderError, ProviderResult}; -use reth_trie::{proof::Proof, updates::TrieUpdates, HashedPostState}; +use reth_trie::{proof::Proof, updates::TrieUpdates, AccountProof, HashedPostState}; use revm::db::BundleState; /// State provider over latest state that takes tx reference. diff --git a/crates/storage/provider/src/providers/state/macros.rs b/crates/storage/provider/src/providers/state/macros.rs index 1d5a9597832c..a39cddfe39fc 100644 --- a/crates/storage/provider/src/providers/state/macros.rs +++ b/crates/storage/provider/src/providers/state/macros.rs @@ -43,7 +43,7 @@ macro_rules! delegate_provider_impls { } StateProvider $(where [$($generics)*])?{ fn storage(&self, account: reth_primitives::Address, storage_key: reth_primitives::StorageKey) -> reth_storage_errors::provider::ProviderResult>; - fn proof(&self, address: reth_primitives::Address, keys: &[reth_primitives::B256]) -> reth_storage_errors::provider::ProviderResult; + fn proof(&self, address: reth_primitives::Address, keys: &[reth_primitives::B256]) -> reth_storage_errors::provider::ProviderResult; fn bytecode_by_hash(&self, code_hash: reth_primitives::B256) -> reth_storage_errors::provider::ProviderResult>; } ); diff --git a/crates/storage/provider/src/test_utils/blocks.rs b/crates/storage/provider/src/test_utils/blocks.rs index be4420fc5199..5fb8beeb2435 100644 --- a/crates/storage/provider/src/test_utils/blocks.rs +++ b/crates/storage/provider/src/test_utils/blocks.rs @@ -5,13 +5,11 @@ use alloy_rlp::Decodable; use reth_db::tables; use reth_db_api::{database::Database, models::StoredBlockBodyIndices}; use reth_primitives::{ - alloy_primitives, b256, - hex_literal::hex, - proofs::{state_root_unhashed, storage_root_unhashed}, - revm::compat::into_reth_acc, - Address, BlockNumber, Bytes, Header, Receipt, Requests, SealedBlock, SealedBlockWithSenders, - TxType, Withdrawal, Withdrawals, B256, U256, + alloy_primitives, b256, hex_literal::hex, revm::compat::into_reth_acc, Address, BlockNumber, + Bytes, Header, Receipt, Requests, SealedBlock, SealedBlockWithSenders, TxType, Withdrawal, + Withdrawals, B256, U256, }; +use reth_trie::root::{state_root_unhashed, storage_root_unhashed}; use revm::{ db::BundleState, primitives::{AccountInfo, HashMap}, diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index a255eb28e1be..0788ddf1e816 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -9,14 +9,14 @@ use parking_lot::Mutex; use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices}; use reth_evm::ConfigureEvmEnv; use reth_primitives::{ - keccak256, proofs::AccountProof, Account, Address, Block, BlockHash, BlockHashOrNumber, - BlockId, BlockNumber, BlockWithSenders, Bytecode, Bytes, ChainInfo, ChainSpec, Header, Receipt, - SealedBlock, SealedBlockWithSenders, SealedHeader, StorageKey, StorageValue, TransactionMeta, + keccak256, Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumber, + BlockWithSenders, Bytecode, Bytes, ChainInfo, ChainSpec, Header, Receipt, SealedBlock, + SealedBlockWithSenders, SealedHeader, StorageKey, StorageValue, TransactionMeta, TransactionSigned, TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, Withdrawals, B256, U256, }; use reth_storage_errors::provider::{ProviderError, ProviderResult}; -use reth_trie::updates::TrieUpdates; +use reth_trie::{updates::TrieUpdates, AccountProof}; use revm::{ db::BundleState, primitives::{BlockEnv, CfgEnvWithHandlerCfg}, diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index 8894a68f7ed6..b681586a1427 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -9,16 +9,15 @@ use crate::{ use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices}; use reth_evm::ConfigureEvmEnv; use reth_primitives::{ - proofs::AccountProof, Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, - BlockNumber, BlockWithSenders, Bytecode, ChainInfo, ChainSpec, Header, Receipt, SealedBlock, - SealedBlockWithSenders, SealedHeader, StorageKey, StorageValue, TransactionMeta, - TransactionSigned, TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, Withdrawals, B256, - MAINNET, U256, + Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumber, BlockWithSenders, + Bytecode, ChainInfo, ChainSpec, Header, Receipt, SealedBlock, SealedBlockWithSenders, + SealedHeader, StorageKey, StorageValue, TransactionMeta, TransactionSigned, + TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, Withdrawals, B256, MAINNET, U256, }; use reth_prune_types::{PruneCheckpoint, PruneSegment}; use reth_stages_types::{StageCheckpoint, StageId}; use reth_storage_errors::provider::ProviderResult; -use reth_trie::updates::TrieUpdates; +use reth_trie::{updates::TrieUpdates, AccountProof}; use revm::{ db::BundleState, primitives::{BlockEnv, CfgEnvWithHandlerCfg}, diff --git a/crates/storage/storage-api/src/state.rs b/crates/storage/storage-api/src/state.rs index 9e258bfd1656..059909a463b0 100644 --- a/crates/storage/storage-api/src/state.rs +++ b/crates/storage/storage-api/src/state.rs @@ -2,10 +2,11 @@ use super::{AccountReader, BlockHashReader, BlockIdReader, StateRootProvider}; use auto_impl::auto_impl; use reth_execution_types::ExecutionOutcome; use reth_primitives::{ - proofs::AccountProof, Address, BlockHash, BlockId, BlockNumHash, BlockNumber, BlockNumberOrTag, - Bytecode, StorageKey, StorageValue, B256, KECCAK_EMPTY, U256, + Address, BlockHash, BlockId, BlockNumHash, BlockNumber, BlockNumberOrTag, Bytecode, StorageKey, + StorageValue, B256, KECCAK_EMPTY, U256, }; use reth_storage_errors::provider::{ProviderError, ProviderResult}; +use reth_trie::AccountProof; /// Type alias of boxed [`StateProvider`]. pub type StateProviderBox = Box; diff --git a/crates/trie/types/Cargo.toml b/crates/trie/common/Cargo.toml similarity index 52% rename from crates/trie/types/Cargo.toml rename to crates/trie/common/Cargo.toml index 4dc2f15dc99f..241a3518f741 100644 --- a/crates/trie/types/Cargo.toml +++ b/crates/trie/common/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "reth-trie-types" +name = "reth-trie-common" version.workspace = true edition.workspace = true homepage.workspace = true @@ -12,17 +12,29 @@ description = "Commonly used types for trie usage in reth." workspace = true [dependencies] +reth-primitives-traits.workspace = true reth-codecs.workspace = true alloy-primitives.workspace = true alloy-rlp = { workspace = true, features = ["arrayvec"] } alloy-trie = { workspace = true, features = ["serde"] } +alloy-consensus.workspace = true +alloy-genesis.workspace = true +revm-primitives.workspace = true + bytes.workspace = true derive_more.workspace = true serde.workspace = true - +itertools.workspace = true nybbles = { workspace = true, features = ["serde", "rlp"] } +# `test-utils` feature +hash-db = { version = "~0.15", optional = true } +plain_hasher = { version = "0.2", optional = true } +arbitrary = { workspace = true, features = ["derive"], optional = true } +proptest = { workspace = true, optional = true } +proptest-derive = { workspace = true, optional = true } + [dev-dependencies] arbitrary = { workspace = true, features = ["derive"] } assert_matches.workspace = true @@ -30,4 +42,15 @@ proptest.workspace = true proptest-derive.workspace = true serde_json.workspace = true test-fuzz.workspace = true -toml.workspace = true \ No newline at end of file +toml.workspace = true +hash-db = "~0.15" +plain_hasher = "0.2" + +[features] +test-utils = ["dep:plain_hasher", "dep:hash-db", "arbitrary"] +arbitrary = [ + "alloy-trie/arbitrary", + "dep:arbitrary", + "dep:proptest", + "dep:proptest-derive", +] \ No newline at end of file diff --git a/crates/trie/common/src/account.rs b/crates/trie/common/src/account.rs new file mode 100644 index 000000000000..64860ab78b31 --- /dev/null +++ b/crates/trie/common/src/account.rs @@ -0,0 +1,73 @@ +use crate::root::storage_root_unhashed; +use alloy_consensus::constants::KECCAK_EMPTY; +use alloy_genesis::GenesisAccount; +use alloy_primitives::{keccak256, B256, U256}; +use alloy_rlp::{RlpDecodable, RlpEncodable}; +use alloy_trie::EMPTY_ROOT_HASH; +use reth_primitives_traits::Account; +use revm_primitives::AccountInfo; + +/// An Ethereum account as represented in the trie. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)] +pub struct TrieAccount { + /// Account nonce. + pub nonce: u64, + /// Account balance. + pub balance: U256, + /// Account's storage root. + pub storage_root: B256, + /// Hash of the account's bytecode. + pub code_hash: B256, +} + +impl TrieAccount { + /// Get account's storage root. + pub const fn storage_root(&self) -> B256 { + self.storage_root + } +} + +impl From for TrieAccount { + fn from(account: GenesisAccount) -> Self { + let storage_root = account + .storage + .map(|storage| { + 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 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<(AccountInfo, B256)> for TrieAccount { + fn from((account, storage_root): (AccountInfo, B256)) -> Self { + Self { + nonce: account.nonce, + balance: account.balance, + storage_root, + code_hash: account.code_hash, + } + } +} diff --git a/crates/trie/types/src/hash_builder/mod.rs b/crates/trie/common/src/hash_builder/mod.rs similarity index 100% rename from crates/trie/types/src/hash_builder/mod.rs rename to crates/trie/common/src/hash_builder/mod.rs diff --git a/crates/trie/types/src/hash_builder/state.rs b/crates/trie/common/src/hash_builder/state.rs similarity index 100% rename from crates/trie/types/src/hash_builder/state.rs rename to crates/trie/common/src/hash_builder/state.rs diff --git a/crates/trie/types/src/hash_builder/value.rs b/crates/trie/common/src/hash_builder/value.rs similarity index 100% rename from crates/trie/types/src/hash_builder/value.rs rename to crates/trie/common/src/hash_builder/value.rs diff --git a/crates/trie/types/src/lib.rs b/crates/trie/common/src/lib.rs similarity index 87% rename from crates/trie/types/src/lib.rs rename to crates/trie/common/src/lib.rs index 0b4927b9c8ac..bc3749e6f936 100644 --- a/crates/trie/types/src/lib.rs +++ b/crates/trie/common/src/lib.rs @@ -31,4 +31,11 @@ pub use storage::StorageTrieEntry; mod subnode; pub use subnode::StoredSubNode; +mod proofs; +#[cfg(any(test, feature = "test-utils"))] +pub use proofs::triehash; +pub use proofs::{AccountProof, StorageProof}; + +pub mod root; + pub use alloy_trie::{proof, BranchNodeCompact, HashBuilder, TrieMask, EMPTY_ROOT_HASH}; diff --git a/crates/trie/types/src/mask.rs b/crates/trie/common/src/mask.rs similarity index 100% rename from crates/trie/types/src/mask.rs rename to crates/trie/common/src/mask.rs diff --git a/crates/trie/types/src/nibbles.rs b/crates/trie/common/src/nibbles.rs similarity index 100% rename from crates/trie/types/src/nibbles.rs rename to crates/trie/common/src/nibbles.rs diff --git a/crates/trie/types/src/nodes/branch.rs b/crates/trie/common/src/nodes/branch.rs similarity index 100% rename from crates/trie/types/src/nodes/branch.rs rename to crates/trie/common/src/nodes/branch.rs diff --git a/crates/trie/types/src/nodes/mod.rs b/crates/trie/common/src/nodes/mod.rs similarity index 100% rename from crates/trie/types/src/nodes/mod.rs rename to crates/trie/common/src/nodes/mod.rs diff --git a/crates/primitives/src/proofs/types.rs b/crates/trie/common/src/proofs.rs similarity index 80% rename from crates/primitives/src/proofs/types.rs rename to crates/trie/common/src/proofs.rs index f2225df7942e..36a0c2615f22 100644 --- a/crates/primitives/src/proofs/types.rs +++ b/crates/trie/common/src/proofs.rs @@ -1,12 +1,13 @@ //! Merkle trie proofs. -use super::{traits::IntoTrieAccount, Nibbles}; -use crate::{keccak256, Account, Address, Bytes, B256, U256}; +use crate::{Nibbles, TrieAccount}; +use alloy_primitives::{keccak256, Address, Bytes, B256, U256}; use alloy_rlp::encode_fixed_size; use alloy_trie::{ proof::{verify_proof, ProofVerificationError}, EMPTY_ROOT_HASH, }; +use reth_primitives_traits::Account; /// The merkle proof with the relevant account info. #[derive(PartialEq, Eq, Debug)] @@ -64,7 +65,7 @@ impl AccountProof { let expected = if self.info.is_none() && self.storage_root == EMPTY_ROOT_HASH { None } else { - Some(alloy_rlp::encode(IntoTrieAccount::to_trie_account(( + Some(alloy_rlp::encode(TrieAccount::from(( self.info.unwrap_or_default(), self.storage_root, )))) @@ -122,3 +123,29 @@ impl StorageProof { verify_proof(root, self.nibbles.clone(), expected, &self.proof) } } + +/// Implementation of hasher using our keccak256 hashing function +/// for compatibility with `triehash` crate. +#[cfg(any(test, feature = "test-utils"))] +pub mod triehash { + use alloy_primitives::{keccak256, B256}; + use hash_db::Hasher; + use plain_hasher::PlainHasher; + + /// A [Hasher] that calculates a keccak256 hash of the given data. + #[derive(Default, Debug, Clone, PartialEq, Eq)] + #[non_exhaustive] + pub struct KeccakHasher; + + #[cfg(any(test, feature = "test-utils"))] + impl Hasher for KeccakHasher { + type Out = B256; + type StdHasher = PlainHasher; + + const LENGTH: usize = 32; + + fn hash(x: &[u8]) -> Self::Out { + keccak256(x) + } + } +} diff --git a/crates/trie/common/src/root.rs b/crates/trie/common/src/root.rs new file mode 100644 index 000000000000..434eea20b59c --- /dev/null +++ b/crates/trie/common/src/root.rs @@ -0,0 +1,117 @@ +//! Common root computation functions. + +use crate::TrieAccount; +use alloy_primitives::{keccak256, Address, B256, U256}; +use alloy_rlp::Encodable; +use alloy_trie::HashBuilder; +use itertools::Itertools; +use nybbles::Nibbles; + +/// Adjust the index of an item for rlp encoding. +pub const fn adjust_index_for_rlp(i: usize, len: usize) -> usize { + if i > 0x7f { + i + } else if i == 0x7f || i + 1 == len { + 0 + } else { + i + 1 + } +} + +/// Compute a trie root of the collection of rlp encodable items. +pub fn ordered_trie_root(items: &[T]) -> B256 { + ordered_trie_root_with_encoder(items, |item, buf| item.encode(buf)) +} + +/// Compute a trie root of the collection of items with a custom encoder. +pub fn ordered_trie_root_with_encoder(items: &[T], mut encode: F) -> B256 +where + F: FnMut(&T, &mut Vec), +{ + let mut value_buffer = Vec::new(); + + let mut hb = HashBuilder::default(); + let items_len = items.len(); + for i in 0..items_len { + let index = adjust_index_for_rlp(i, items_len); + + let index_buffer = alloy_rlp::encode_fixed_size(&index); + + value_buffer.clear(); + encode(&items[index], &mut value_buffer); + + hb.add_leaf(Nibbles::unpack(&index_buffer), &value_buffer); + } + + hb.root() +} + +/// 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 + Clone + 'a>( + state: impl IntoIterator, +) -> 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>( + state: impl IntoIterator, +) -> 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>( + state: impl IntoIterator, +) -> 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>(state: impl IntoIterator) -> 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) -> 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) -> 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) -> 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() +} diff --git a/crates/trie/types/src/storage.rs b/crates/trie/common/src/storage.rs similarity index 100% rename from crates/trie/types/src/storage.rs rename to crates/trie/common/src/storage.rs diff --git a/crates/trie/types/src/subnode.rs b/crates/trie/common/src/subnode.rs similarity index 100% rename from crates/trie/types/src/subnode.rs rename to crates/trie/common/src/subnode.rs diff --git a/crates/trie/parallel/src/async_root.rs b/crates/trie/parallel/src/async_root.rs index 7441bd0a02f4..a36a01be5ecb 100644 --- a/crates/trie/parallel/src/async_root.rs +++ b/crates/trie/parallel/src/async_root.rs @@ -3,7 +3,7 @@ use alloy_rlp::{BufMut, Encodable}; use itertools::Itertools; use reth_db_api::database::Database; use reth_execution_errors::StorageRootError; -use reth_primitives::{proofs::IntoTrieAccount, B256}; +use reth_primitives::B256; use reth_provider::{providers::ConsistentDbView, DatabaseProviderFactory, ProviderError}; use reth_tasks::pool::BlockingTaskPool; use reth_trie::{ @@ -12,7 +12,7 @@ use reth_trie::{ trie_cursor::TrieCursorFactory, updates::TrieUpdates, walker::TrieWalker, - HashBuilder, HashedPostState, Nibbles, StorageRoot, + HashBuilder, HashedPostState, Nibbles, StorageRoot, TrieAccount, }; use std::{collections::HashMap, sync::Arc}; use thiserror::Error; @@ -170,7 +170,7 @@ where } account_rlp.clear(); - let account = IntoTrieAccount::to_trie_account((account, 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); } diff --git a/crates/trie/parallel/src/parallel_root.rs b/crates/trie/parallel/src/parallel_root.rs index f814e2ff88cf..edf552096fca 100644 --- a/crates/trie/parallel/src/parallel_root.rs +++ b/crates/trie/parallel/src/parallel_root.rs @@ -3,7 +3,7 @@ use alloy_rlp::{BufMut, Encodable}; use rayon::prelude::*; use reth_db_api::database::Database; use reth_execution_errors::StorageRootError; -use reth_primitives::{proofs::IntoTrieAccount, B256}; +use reth_primitives::B256; use reth_provider::{providers::ConsistentDbView, DatabaseProviderFactory, ProviderError}; use reth_trie::{ hashed_cursor::{HashedCursorFactory, HashedPostStateCursorFactory}, @@ -11,7 +11,7 @@ use reth_trie::{ trie_cursor::TrieCursorFactory, updates::TrieUpdates, walker::TrieWalker, - HashBuilder, HashedPostState, Nibbles, StorageRoot, + HashBuilder, HashedPostState, Nibbles, StorageRoot, TrieAccount, }; use std::collections::HashMap; use thiserror::Error; @@ -152,7 +152,7 @@ where } account_rlp.clear(); - let account = IntoTrieAccount::to_trie_account((account, 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); } diff --git a/crates/trie/trie/Cargo.toml b/crates/trie/trie/Cargo.toml index 99beeff07004..d01914759a87 100644 --- a/crates/trie/trie/Cargo.toml +++ b/crates/trie/trie/Cargo.toml @@ -18,7 +18,7 @@ reth-execution-errors.workspace = true reth-db.workspace = true reth-db-api.workspace = true reth-stages-types.workspace = true -reth-trie-types.workspace = true +reth-trie-common.workspace = true revm.workspace = true @@ -46,6 +46,7 @@ reth-primitives = { workspace = true, features = ["test-utils", "arbitrary"] } reth-db = { workspace = true, features = ["test-utils"] } reth-provider = { workspace = true, features = ["test-utils"] } reth-storage-errors.workspace = true +reth-trie-common = { workspace = true, features = ["test-utils", "arbitrary"] } # trie triehash = "0.8" @@ -65,7 +66,7 @@ criterion.workspace = true [features] metrics = ["reth-metrics", "dep:metrics"] -test-utils = ["triehash"] +test-utils = ["triehash", "reth-trie-common/test-utils"] [[bench]] name = "prefix_set" @@ -74,3 +75,8 @@ harness = false [[bench]] name = "hash_post_state" harness = false + +[[bench]] +name = "trie_root" +required-features = ["test-utils"] +harness = false diff --git a/crates/primitives/benches/trie_root.rs b/crates/trie/trie/benches/trie_root.rs similarity index 92% rename from crates/primitives/benches/trie_root.rs rename to crates/trie/trie/benches/trie_root.rs index b61e3aa8541d..8a149404abbb 100644 --- a/crates/primitives/benches/trie_root.rs +++ b/crates/trie/trie/benches/trie_root.rs @@ -1,7 +1,8 @@ #![allow(missing_docs, unreachable_pub)] use criterion::{black_box, criterion_group, criterion_main, Criterion}; use proptest::{prelude::*, strategy::ValueTree, test_runner::TestRunner}; -use reth_primitives::{proofs::triehash::KeccakHasher, ReceiptWithBloom, B256}; +use reth_primitives::{ReceiptWithBloom, B256}; +use reth_trie::triehash::KeccakHasher; /// Benchmarks different implementations of the root calculation. pub fn trie_root_benchmark(c: &mut Criterion) { @@ -41,8 +42,7 @@ criterion_main!(benches); mod implementations { use super::*; use alloy_rlp::Encodable; - use reth_primitives::proofs::adjust_index_for_rlp; - use reth_trie_types::{HashBuilder, Nibbles}; + use reth_trie_common::{root::adjust_index_for_rlp, HashBuilder, Nibbles}; pub fn trie_hash_ordered_trie_root(receipts: &[ReceiptWithBloom]) -> B256 { triehash::ordered_trie_root::(receipts.iter().map(|receipt| { diff --git a/crates/trie/trie/src/lib.rs b/crates/trie/trie/src/lib.rs index 16251dc11903..eea65a7b34d8 100644 --- a/crates/trie/trie/src/lib.rs +++ b/crates/trie/trie/src/lib.rs @@ -51,7 +51,7 @@ pub use progress::{IntermediateStateRootState, StateRootProgress}; pub mod stats; // re-export for convenience -pub use reth_trie_types::*; +pub use reth_trie_common::*; /// Trie calculation metrics. #[cfg(feature = "metrics")] diff --git a/crates/trie/trie/src/proof.rs b/crates/trie/trie/src/proof.rs index d3438dfaa57a..19c8b7fabbc6 100644 --- a/crates/trie/trie/src/proof.rs +++ b/crates/trie/trie/src/proof.rs @@ -10,13 +10,8 @@ use alloy_rlp::{BufMut, Encodable}; use reth_db::tables; use reth_db_api::transaction::DbTx; use reth_execution_errors::{StateRootError, StorageRootError}; -use reth_primitives::{ - constants::EMPTY_ROOT_HASH, - keccak256, - proofs::{AccountProof, IntoTrieAccount, StorageProof}, - Address, B256, -}; -use reth_trie_types::proof::ProofRetainer; +use reth_primitives::{constants::EMPTY_ROOT_HASH, keccak256, Address, B256}; +use reth_trie_common::{proof::ProofRetainer, AccountProof, StorageProof, TrieAccount}; /// A struct for generating merkle proofs. /// /// Proof generator adds the target address and slots to the prefix set, enables the proof retainer @@ -83,7 +78,7 @@ where }; account_rlp.clear(); - let account = IntoTrieAccount::to_trie_account((account, 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); diff --git a/crates/trie/trie/src/test_utils.rs b/crates/trie/trie/src/test_utils.rs index bd0c1936fbf7..e2fc1f192c32 100644 --- a/crates/trie/trie/src/test_utils.rs +++ b/crates/trie/trie/src/test_utils.rs @@ -1,8 +1,6 @@ use alloy_rlp::encode_fixed_size; -use reth_primitives::{ - proofs::{triehash::KeccakHasher, IntoTrieAccount}, - Account, Address, B256, U256, -}; +use reth_primitives::{Account, Address, B256, U256}; +use reth_trie_common::{triehash::KeccakHasher, TrieAccount}; /// Re-export of [triehash]. pub use triehash; @@ -15,7 +13,7 @@ where { let encoded_accounts = accounts.into_iter().map(|(address, (account, storage))| { let storage_root = storage_root(storage); - let account = IntoTrieAccount::to_trie_account((account, storage_root)); + let account = TrieAccount::from((account, storage_root)); (address, alloy_rlp::encode(account)) }); triehash::sec_trie_root::(encoded_accounts) @@ -36,7 +34,7 @@ where { let encoded_accounts = accounts.into_iter().map(|(address, (account, storage))| { let storage_root = storage_root_prehashed(storage); - let account = IntoTrieAccount::to_trie_account((account, storage_root)); + let account = TrieAccount::from((account, storage_root)); (address, alloy_rlp::encode(account)) }); diff --git a/crates/trie/trie/src/trie.rs b/crates/trie/trie/src/trie.rs index 91ba2e0463e0..3fe97a6f788c 100644 --- a/crates/trie/trie/src/trie.rs +++ b/crates/trie/trie/src/trie.rs @@ -7,14 +7,12 @@ use crate::{ trie_cursor::TrieCursorFactory, updates::{TrieKey, TrieOp, TrieUpdates}, walker::TrieWalker, - HashBuilder, Nibbles, + HashBuilder, Nibbles, TrieAccount, }; use alloy_rlp::{BufMut, Encodable}; use reth_db_api::transaction::DbTx; use reth_execution_errors::{StateRootError, StorageRootError}; -use reth_primitives::{ - constants::EMPTY_ROOT_HASH, keccak256, proofs::IntoTrieAccount, Address, BlockNumber, B256, -}; +use reth_primitives::{constants::EMPTY_ROOT_HASH, keccak256, Address, BlockNumber, B256}; use std::ops::RangeInclusive; use tracing::{debug, trace}; @@ -282,7 +280,7 @@ where }; account_rlp.clear(); - let account = IntoTrieAccount::to_trie_account((account, 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); @@ -558,10 +556,9 @@ mod tests { cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO}, transaction::DbTxMut, }; - use reth_primitives::{ - hex_literal::hex, proofs::triehash::KeccakHasher, Account, StorageEntry, U256, - }; + use reth_primitives::{hex_literal::hex, Account, StorageEntry, U256}; use reth_provider::{test_utils::create_test_provider_factory, DatabaseProviderRW}; + use reth_trie_common::triehash::KeccakHasher; use std::{ collections::{BTreeMap, HashMap}, ops::Mul, @@ -828,8 +825,7 @@ mod tests { } fn encode_account(account: Account, storage_root: Option) -> Vec { - let account = - IntoTrieAccount::to_trie_account((account, storage_root.unwrap_or(EMPTY_ROOT_HASH))); + 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 diff --git a/crates/trie/types/src/account.rs b/crates/trie/types/src/account.rs deleted file mode 100644 index 480a8c6a69e8..000000000000 --- a/crates/trie/types/src/account.rs +++ /dev/null @@ -1,22 +0,0 @@ -use alloy_primitives::{B256, U256}; -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. - pub nonce: u64, - /// Account balance. - pub balance: U256, - /// Account's storage root. - pub storage_root: B256, - /// Hash of the account's bytecode. - pub code_hash: B256, -} - -impl TrieAccount { - /// Get account's storage root. - pub const fn storage_root(&self) -> B256 { - self.storage_root - } -}