mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
chore(primitives): root calculation using HashBuilder (#4780)
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -5927,6 +5927,7 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
"impl-serde",
|
"impl-serde",
|
||||||
|
"itertools 0.11.0",
|
||||||
"modular-bitfield",
|
"modular-bitfield",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"paste",
|
"paste",
|
||||||
|
|||||||
@ -63,9 +63,8 @@ paste = "1.0"
|
|||||||
rayon = "1.7"
|
rayon = "1.7"
|
||||||
tempfile = "3.3"
|
tempfile = "3.3"
|
||||||
sha2 = "0.10.7"
|
sha2 = "0.10.7"
|
||||||
|
itertools = "0.11"
|
||||||
|
|
||||||
# proof related
|
|
||||||
triehash = "0.8"
|
|
||||||
# See to replace hashers to simplify libraries
|
# See to replace hashers to simplify libraries
|
||||||
plain_hasher = "0.2"
|
plain_hasher = "0.2"
|
||||||
hash-db = "~0.15"
|
hash-db = "~0.15"
|
||||||
@ -87,6 +86,7 @@ proptest.workspace = true
|
|||||||
proptest-derive.workspace = true
|
proptest-derive.workspace = true
|
||||||
assert_matches.workspace = true
|
assert_matches.workspace = true
|
||||||
toml = "0.7.4"
|
toml = "0.7.4"
|
||||||
|
triehash = "0.8"
|
||||||
|
|
||||||
# necessary so we don't hit a "undeclared 'std'":
|
# necessary so we don't hit a "undeclared 'std'":
|
||||||
# https://github.com/paradigmxyz/reth/pull/177#discussion_r1021172198
|
# https://github.com/paradigmxyz/reth/pull/177#discussion_r1021172198
|
||||||
@ -105,4 +105,5 @@ harness = false
|
|||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "trie_root"
|
name = "trie_root"
|
||||||
|
required-features = ["arbitrary"]
|
||||||
harness = false
|
harness = false
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
keccak256,
|
keccak256,
|
||||||
proofs::{KeccakHasher, EMPTY_ROOT},
|
proofs::EMPTY_ROOT,
|
||||||
serde_helper::{deserialize_json_u256, deserialize_json_u256_opt, deserialize_storage_map},
|
serde_helper::{deserialize_json_u256, deserialize_json_u256_opt, deserialize_storage_map},
|
||||||
|
trie::{HashBuilder, Nibbles},
|
||||||
utils::serde_helpers::{deserialize_stringified_u64, deserialize_stringified_u64_opt},
|
utils::serde_helpers::{deserialize_stringified_u64, deserialize_stringified_u64_opt},
|
||||||
Account, Address, Bytes, H256, KECCAK_EMPTY, U256,
|
Account, Address, Bytes, H256, KECCAK_EMPTY, U256,
|
||||||
};
|
};
|
||||||
|
use itertools::Itertools;
|
||||||
use reth_rlp::{encode_fixed_size, length_of_length, Encodable, Header as RlpHeader};
|
use reth_rlp::{encode_fixed_size, length_of_length, Encodable, Header as RlpHeader};
|
||||||
use revm_primitives::B160;
|
use revm_primitives::B160;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use triehash::sec_trie_root;
|
|
||||||
|
|
||||||
/// The genesis block specification.
|
/// The genesis block specification.
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
@ -214,12 +215,20 @@ impl Encodable for GenesisAccount {
|
|||||||
if storage.is_empty() {
|
if storage.is_empty() {
|
||||||
return EMPTY_ROOT
|
return EMPTY_ROOT
|
||||||
}
|
}
|
||||||
let storage_values =
|
|
||||||
storage.iter().filter(|(_k, &v)| v != H256::zero()).map(|(&k, v)| {
|
let storage_with_sorted_hashed_keys = storage
|
||||||
let value = U256::from_be_bytes(**v);
|
.iter()
|
||||||
(k, encode_fixed_size(&value))
|
.filter(|(_k, &v)| v != H256::zero())
|
||||||
});
|
.map(|(slot, value)| (keccak256(slot), value))
|
||||||
sec_trie_root::<KeccakHasher, _, _, _>(storage_values)
|
.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);
|
.encode(out);
|
||||||
self.code.as_ref().map_or(KECCAK_EMPTY, keccak256).encode(out);
|
self.code.as_ref().map_or(KECCAK_EMPTY, keccak256).encode(out);
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
keccak256,
|
keccak256,
|
||||||
trie::{HashBuilder, Nibbles},
|
trie::{HashBuilder, Nibbles},
|
||||||
Address, Bytes, GenesisAccount, Header, Log, ReceiptWithBloom, ReceiptWithBloomRef,
|
Address, GenesisAccount, Header, Log, ReceiptWithBloom, ReceiptWithBloomRef, TransactionSigned,
|
||||||
TransactionSigned, Withdrawal, H256,
|
Withdrawal, H256,
|
||||||
};
|
};
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
use hex_literal::hex;
|
use hex_literal::hex;
|
||||||
|
use itertools::Itertools;
|
||||||
use plain_hasher::PlainHasher;
|
use plain_hasher::PlainHasher;
|
||||||
use reth_rlp::Encodable;
|
use reth_rlp::Encodable;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use triehash::sec_trie_root;
|
|
||||||
|
|
||||||
/// Keccak-256 hash of the RLP of an empty list, KEC("\xc0").
|
/// Keccak-256 hash of the RLP of an empty list, KEC("\xc0").
|
||||||
pub const EMPTY_LIST_HASH: H256 =
|
pub const EMPTY_LIST_HASH: H256 =
|
||||||
@ -128,29 +128,33 @@ pub fn calculate_ommers_root(ommers: &[Header]) -> H256 {
|
|||||||
/// Calculates the root hash for the state, this corresponds to [geth's
|
/// 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).
|
/// `deriveHash`](https://github.com/ethereum/go-ethereum/blob/6c149fd4ad063f7c24d726a73bc0546badd1bc73/core/genesis.go#L119).
|
||||||
pub fn genesis_state_root(genesis_alloc: &HashMap<Address, GenesisAccount>) -> H256 {
|
pub fn genesis_state_root(genesis_alloc: &HashMap<Address, GenesisAccount>) -> H256 {
|
||||||
let encoded_accounts = genesis_alloc.iter().map(|(address, account)| {
|
let accounts_with_sorted_hashed_keys = genesis_alloc
|
||||||
let mut acc_rlp = BytesMut::new();
|
.iter()
|
||||||
account.encode(&mut acc_rlp);
|
.map(|(address, account)| (keccak256(address), account))
|
||||||
(address, Bytes::from(acc_rlp.freeze()))
|
.sorted_by_key(|(key, _)| *key);
|
||||||
});
|
|
||||||
|
|
||||||
H256(sec_trie_root::<KeccakHasher, _, _, _>(encoded_accounts).0)
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
hb.root()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::{calculate_withdrawals_root, EMPTY_ROOT};
|
||||||
use std::{collections::HashMap, str::FromStr};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hex_literal::hex,
|
hex_literal::hex,
|
||||||
proofs::{calculate_receipt_root, calculate_transaction_root, genesis_state_root},
|
proofs::{calculate_receipt_root, calculate_transaction_root, genesis_state_root},
|
||||||
Address, Block, Bloom, GenesisAccount, Log, Receipt, ReceiptWithBloom, TxType, H160, H256,
|
Address, Block, Bloom, GenesisAccount, Log, Receipt, ReceiptWithBloom, TxType, GOERLI,
|
||||||
U256,
|
H160, H256, HOLESKY, MAINNET, SEPOLIA, U256,
|
||||||
};
|
};
|
||||||
use reth_rlp::Decodable;
|
use reth_rlp::Decodable;
|
||||||
|
use std::collections::HashMap;
|
||||||
use super::{calculate_withdrawals_root, EMPTY_ROOT};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_transaction_root() {
|
fn check_transaction_root() {
|
||||||
@ -243,119 +247,37 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sepolia_state_root() {
|
fn test_chain_state_roots() {
|
||||||
let expected_root =
|
let expected_mainnet_state_root =
|
||||||
hex!("5eb6e371a698b8d68f665192350ffcecbbbf322916f4b51bd79bb6887da3f494").into();
|
H256::from(hex!("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"));
|
||||||
let alloc = HashMap::from([
|
let calculated_mainnet_state_root = genesis_state_root(&MAINNET.genesis.alloc);
|
||||||
(
|
assert_eq!(
|
||||||
hex!("a2A6d93439144FFE4D27c9E088dCD8b783946263").into(),
|
expected_mainnet_state_root, calculated_mainnet_state_root,
|
||||||
GenesisAccount {
|
"mainnet state root mismatch"
|
||||||
balance: U256::from_str("1000000000000000000000000").unwrap(),
|
);
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("Bc11295936Aa79d594139de1B2e12629414F3BDB").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("1000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("7cF5b79bfe291A67AB02b393E456cCc4c266F753").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("1000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("aaec86394441f915bce3e6ab399977e9906f3b69").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("1000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("F47CaE1CF79ca6758Bfc787dbD21E6bdBe7112B8").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("1000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("d7eDDB78ED295B3C9629240E8924fb8D8874ddD8").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("1000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("8b7F0977Bb4f0fBE7076FA22bC24acA043583F5e").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("1000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("e2e2659028143784d557bcec6ff3a0721048880a").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("1000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("d9a5179f091d85051d3c982785efd1455cec8699").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("1000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("beef32ca5b9a198d27B4e02F4c70439fE60356Cf").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("1000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("0000006916a87b82333f4245046623b23794c65c").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("10000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("b21c33de1fab3fa15499c62b59fe0cc3250020d1").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("100000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("10F5d45854e038071485AC9e402308cF80D2d2fE").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("100000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("d7d76c58b3a519e9fA6Cc4D22dC017259BC49F1E").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("100000000000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
hex!("799D329e5f583419167cD722962485926E338F4a").into(),
|
|
||||||
GenesisAccount {
|
|
||||||
balance: U256::from_str("1000000000000000000").unwrap(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let root = genesis_state_root(&alloc);
|
let expected_goerli_state_root =
|
||||||
|
H256::from(hex!("5d6cded585e73c4e322c30c2f782a336316f17dd85a4863b9d838d2d4b8b3008"));
|
||||||
|
let calculated_goerli_state_root = genesis_state_root(&GOERLI.genesis.alloc);
|
||||||
|
assert_eq!(
|
||||||
|
expected_goerli_state_root, calculated_goerli_state_root,
|
||||||
|
"goerli state root mismatch"
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(root, expected_root);
|
let expected_sepolia_state_root =
|
||||||
|
H256::from(hex!("5eb6e371a698b8d68f665192350ffcecbbbf322916f4b51bd79bb6887da3f494"));
|
||||||
|
let calculated_sepolia_state_root = genesis_state_root(&SEPOLIA.genesis.alloc);
|
||||||
|
assert_eq!(
|
||||||
|
expected_sepolia_state_root, calculated_sepolia_state_root,
|
||||||
|
"sepolia state root mismatch"
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected_holesky_state_root =
|
||||||
|
H256::from(hex!("69d8c9d72f6fa4ad42d4702b433707212f90db395eb54dc20bc85de253788783"));
|
||||||
|
let calculated_holesky_state_root = genesis_state_root(&HOLESKY.genesis.alloc);
|
||||||
|
assert_eq!(
|
||||||
|
expected_holesky_state_root, calculated_holesky_state_root,
|
||||||
|
"holesky state root mismatch"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -295,7 +295,7 @@ where
|
|||||||
// We assume we can always calculate a storage root without
|
// We assume we can always calculate a storage root without
|
||||||
// OOMing. This opens us up to a potential DOS vector if
|
// OOMing. This opens us up to a potential DOS vector if
|
||||||
// a contract had too many storage entries and they were
|
// a contract had too many storage entries and they were
|
||||||
// all buffered w/o us returning and committing our intermeditate
|
// all buffered w/o us returning and committing our intermediate
|
||||||
// progress.
|
// progress.
|
||||||
// TODO: We can consider introducing the TrieProgress::Progress/Complete
|
// TODO: We can consider introducing the TrieProgress::Progress/Complete
|
||||||
// abstraction inside StorageRoot, but let's give it a try as-is for now.
|
// abstraction inside StorageRoot, but let's give it a try as-is for now.
|
||||||
|
|||||||
Reference in New Issue
Block a user