mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
perf(proofs): root calculation using hash builder (#2517)
This commit is contained in:
@ -153,7 +153,7 @@ where
|
||||
header.transactions_root = if transactions.is_empty() {
|
||||
EMPTY_TRANSACTIONS
|
||||
} else {
|
||||
proofs::calculate_transaction_root(transactions.iter())
|
||||
proofs::calculate_transaction_root(&transactions)
|
||||
};
|
||||
|
||||
let block =
|
||||
@ -186,7 +186,7 @@ where
|
||||
.iter()
|
||||
.map(|r| r.clone().into())
|
||||
.collect::<Vec<ReceiptWithBloom>>();
|
||||
proofs::calculate_receipt_root(receipts_with_bloom.iter())
|
||||
proofs::calculate_receipt_root(&receipts_with_bloom)
|
||||
};
|
||||
let transactions = body.clone();
|
||||
let body =
|
||||
|
||||
@ -192,7 +192,7 @@ pub fn validate_block_standalone(
|
||||
|
||||
// Check transaction root
|
||||
// TODO(onbjerg): This should probably be accessible directly on [Block]
|
||||
let transaction_root = reth_primitives::proofs::calculate_transaction_root(block.body.iter());
|
||||
let transaction_root = reth_primitives::proofs::calculate_transaction_root(&block.body);
|
||||
if block.header.transactions_root != transaction_root {
|
||||
return Err(ConsensusError::BodyTransactionRootDiff {
|
||||
got: transaction_root,
|
||||
@ -204,8 +204,7 @@ pub fn validate_block_standalone(
|
||||
if chain_spec.fork(Hardfork::Shanghai).active_at_timestamp(block.timestamp) {
|
||||
let withdrawals =
|
||||
block.withdrawals.as_ref().ok_or(ConsensusError::BodyWithdrawalsMissing)?;
|
||||
let withdrawals_root =
|
||||
reth_primitives::proofs::calculate_withdrawals_root(withdrawals.iter());
|
||||
let withdrawals_root = reth_primitives::proofs::calculate_withdrawals_root(withdrawals);
|
||||
let header_withdrawals_root =
|
||||
block.withdrawals_root.as_ref().ok_or(ConsensusError::WithdrawalsRootMissing)?;
|
||||
if withdrawals_root != *header_withdrawals_root {
|
||||
@ -626,7 +625,7 @@ mod tests {
|
||||
.collect::<Vec<_>>();
|
||||
SealedBlock {
|
||||
header: Header {
|
||||
withdrawals_root: Some(proofs::calculate_withdrawals_root(withdrawals.iter())),
|
||||
withdrawals_root: Some(proofs::calculate_withdrawals_root(&withdrawals)),
|
||||
..Default::default()
|
||||
}
|
||||
.seal_slow(),
|
||||
|
||||
@ -110,7 +110,7 @@ pub fn random_block(
|
||||
(0..ommers_count).map(|_| random_header(number, parent).unseal()).collect::<Vec<_>>();
|
||||
|
||||
// Calculate roots
|
||||
let transactions_root = proofs::calculate_transaction_root(transactions.iter());
|
||||
let transactions_root = proofs::calculate_transaction_root(&transactions);
|
||||
let ommers_hash = proofs::calculate_ommers_root(&ommers);
|
||||
|
||||
SealedBlock {
|
||||
|
||||
@ -661,7 +661,7 @@ fn build_payload<Pool, Client>(
|
||||
let state_root = db.db.0.state_root(post_state)?;
|
||||
|
||||
// create the block header
|
||||
let transactions_root = proofs::calculate_transaction_root(executed_txs.iter());
|
||||
let transactions_root = proofs::calculate_transaction_root(&executed_txs);
|
||||
|
||||
let header = Header {
|
||||
parent_hash: parent_block.hash,
|
||||
@ -807,7 +807,7 @@ where
|
||||
increment_account_balance(db, post_state, block_number, address, increment)?;
|
||||
}
|
||||
|
||||
let withdrawals_root = proofs::calculate_withdrawals_root(withdrawals.iter());
|
||||
let withdrawals_root = proofs::calculate_withdrawals_root(&withdrawals);
|
||||
|
||||
// calculate withdrawals root
|
||||
Ok(WithdrawalsOutcome {
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
use crate::{
|
||||
keccak256, Address, Bytes, GenesisAccount, Header, Log, ReceiptWithBloom, ReceiptWithBloomRef,
|
||||
keccak256,
|
||||
trie::{HashBuilder, Nibbles},
|
||||
Address, Bytes, GenesisAccount, Header, Log, ReceiptWithBloom, ReceiptWithBloomRef,
|
||||
TransactionSigned, Withdrawal, H256,
|
||||
};
|
||||
use bytes::BytesMut;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use hash_db::Hasher;
|
||||
use hex_literal::hex;
|
||||
use plain_hasher::PlainHasher;
|
||||
use reth_rlp::Encodable;
|
||||
use std::collections::HashMap;
|
||||
use triehash::{ordered_trie_root, sec_trie_root};
|
||||
use triehash::sec_trie_root;
|
||||
|
||||
/// Keccak-256 hash of the RLP of an empty list, KEC("\xc0").
|
||||
pub const EMPTY_LIST_HASH: H256 =
|
||||
@ -44,50 +46,66 @@ pub const fn adjust_index_for_rlp(i: usize, len: usize) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute a trie root of the collection of rlp encodable items.
|
||||
pub fn ordered_trie_root<T: Encodable>(items: &[T]) -> H256 {
|
||||
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<T, F>(items: &[T], mut encode: F) -> H256
|
||||
where
|
||||
F: FnMut(&T, &mut dyn BufMut),
|
||||
{
|
||||
let mut index_buffer = BytesMut::new();
|
||||
let mut value_buffer = BytesMut::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);
|
||||
|
||||
index_buffer.clear();
|
||||
index.encode(&mut index_buffer);
|
||||
|
||||
value_buffer.clear();
|
||||
encode(&items[index], &mut value_buffer);
|
||||
|
||||
hb.add_leaf(Nibbles::unpack(&index_buffer), &value_buffer);
|
||||
}
|
||||
|
||||
hb.root()
|
||||
}
|
||||
|
||||
/// Calculate a transaction root.
|
||||
///
|
||||
/// `(rlp(index), encoded(tx))` pairs.
|
||||
pub fn calculate_transaction_root<I, T>(transactions: I) -> H256
|
||||
pub fn calculate_transaction_root<T>(transactions: &[T]) -> H256
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: AsRef<TransactionSigned>,
|
||||
{
|
||||
ordered_trie_root::<KeccakHasher, _>(transactions.into_iter().map(|tx| {
|
||||
let mut tx_rlp = Vec::new();
|
||||
tx.as_ref().encode_inner(&mut tx_rlp, false);
|
||||
tx_rlp
|
||||
}))
|
||||
ordered_trie_root_with_encoder(transactions, |tx: &T, buf| tx.as_ref().encode_inner(buf, false))
|
||||
}
|
||||
|
||||
/// Calculates the root hash of the withdrawals.
|
||||
pub fn calculate_withdrawals_root<'a>(
|
||||
withdrawals: impl IntoIterator<Item = &'a Withdrawal>,
|
||||
) -> H256 {
|
||||
ordered_trie_root::<KeccakHasher, _>(withdrawals.into_iter().map(|withdrawal| {
|
||||
let mut withdrawal_rlp = Vec::new();
|
||||
withdrawal.encode(&mut withdrawal_rlp);
|
||||
withdrawal_rlp
|
||||
}))
|
||||
pub fn calculate_withdrawals_root(withdrawals: &[Withdrawal]) -> H256 {
|
||||
ordered_trie_root(withdrawals)
|
||||
}
|
||||
|
||||
/// Calculates the receipt root for a header.
|
||||
pub fn calculate_receipt_root<'a>(receipts: impl Iterator<Item = &'a ReceiptWithBloom>) -> H256 {
|
||||
ordered_trie_root::<KeccakHasher, _>(receipts.into_iter().map(|receipt| {
|
||||
let mut receipt_rlp = Vec::new();
|
||||
receipt.encode_inner(&mut receipt_rlp, false);
|
||||
receipt_rlp
|
||||
}))
|
||||
pub fn calculate_receipt_root(receipts: &[ReceiptWithBloom]) -> H256 {
|
||||
ordered_trie_root_with_encoder(receipts, |r, buf| r.encode_inner(buf, false))
|
||||
}
|
||||
|
||||
/// Calculates the receipt root for a header for the reference type of [ReceiptWithBloom].
|
||||
pub fn calculate_receipt_root_ref<'a>(
|
||||
receipts: impl Iterator<Item = ReceiptWithBloomRef<'a>>,
|
||||
) -> H256 {
|
||||
ordered_trie_root::<KeccakHasher, _>(receipts.into_iter().map(|receipt| {
|
||||
let mut receipt_rlp = Vec::new();
|
||||
receipt.encode_inner(&mut receipt_rlp, false);
|
||||
receipt_rlp
|
||||
}))
|
||||
///
|
||||
/// NOTE: Prefer [calculate_receipt_root] if you have log blooms memoized.
|
||||
pub fn calculate_receipt_root_ref<T>(receipts: &[T]) -> H256
|
||||
where
|
||||
for<'a> ReceiptWithBloomRef<'a>: From<&'a T>,
|
||||
{
|
||||
ordered_trie_root_with_encoder(receipts, |r, buf| {
|
||||
ReceiptWithBloomRef::from(r).encode_inner(buf, false)
|
||||
})
|
||||
}
|
||||
|
||||
/// Calculates the log root for headers.
|
||||
@ -139,7 +157,7 @@ mod tests {
|
||||
let block_rlp = &mut data.as_slice();
|
||||
let block: Block = Block::decode(block_rlp).unwrap();
|
||||
|
||||
let tx_root = calculate_transaction_root(block.body.iter());
|
||||
let tx_root = calculate_transaction_root(&block.body);
|
||||
assert_eq!(block.transactions_root, tx_root, "Must be the same");
|
||||
}
|
||||
|
||||
@ -157,7 +175,7 @@ mod tests {
|
||||
bloom,
|
||||
};
|
||||
let receipt = vec![receipt];
|
||||
let root = calculate_receipt_root(receipt.iter());
|
||||
let root = calculate_receipt_root(&receipt);
|
||||
assert_eq!(
|
||||
root,
|
||||
H256(hex!("fe70ae4a136d98944951b2123859698d59ad251a381abc9960fa81cae3d0d4a0"))
|
||||
@ -173,7 +191,7 @@ mod tests {
|
||||
assert!(block.withdrawals.is_some());
|
||||
let withdrawals = block.withdrawals.as_ref().unwrap();
|
||||
assert_eq!(withdrawals.len(), 1);
|
||||
let withdrawals_root = calculate_withdrawals_root(withdrawals.iter());
|
||||
let withdrawals_root = calculate_withdrawals_root(withdrawals);
|
||||
assert_eq!(block.withdrawals_root, Some(withdrawals_root));
|
||||
|
||||
// 4 withdrawals, identical indices
|
||||
@ -183,7 +201,7 @@ mod tests {
|
||||
assert!(block.withdrawals.is_some());
|
||||
let withdrawals = block.withdrawals.as_ref().unwrap();
|
||||
assert_eq!(withdrawals.len(), 4);
|
||||
let withdrawals_root = calculate_withdrawals_root(withdrawals.iter());
|
||||
let withdrawals_root = calculate_withdrawals_root(withdrawals);
|
||||
assert_eq!(block.withdrawals_root, Some(withdrawals_root));
|
||||
}
|
||||
|
||||
|
||||
@ -492,7 +492,7 @@ pub fn verify_receipt<'a>(
|
||||
) -> Result<(), Error> {
|
||||
// Check receipts root.
|
||||
let receipts_with_bloom = receipts.map(|r| r.clone().into()).collect::<Vec<ReceiptWithBloom>>();
|
||||
let receipts_root = reth_primitives::proofs::calculate_receipt_root(receipts_with_bloom.iter());
|
||||
let receipts_root = reth_primitives::proofs::calculate_receipt_root(&receipts_with_bloom);
|
||||
if receipts_root != expected_receipts_root {
|
||||
return Err(Error::ReceiptRootDiff { got: receipts_root, expected: expected_receipts_root })
|
||||
}
|
||||
|
||||
@ -139,10 +139,10 @@ impl TryFrom<ExecutionPayload> for SealedBlock {
|
||||
.iter()
|
||||
.map(|tx| TransactionSigned::decode(&mut tx.as_ref()))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let transactions_root = proofs::calculate_transaction_root(transactions.iter());
|
||||
let transactions_root = proofs::calculate_transaction_root(&transactions);
|
||||
|
||||
let withdrawals_root =
|
||||
payload.withdrawals.as_ref().map(|w| proofs::calculate_withdrawals_root(w.iter()));
|
||||
payload.withdrawals.as_ref().map(|w| proofs::calculate_withdrawals_root(w));
|
||||
|
||||
let header = Header {
|
||||
parent_hash: payload.parent_hash,
|
||||
@ -411,7 +411,7 @@ mod tests {
|
||||
let mut transformed: Block = f(unsealed);
|
||||
// Recalculate roots
|
||||
transformed.header.transactions_root =
|
||||
proofs::calculate_transaction_root(transformed.body.iter());
|
||||
proofs::calculate_transaction_root(&transformed.body);
|
||||
transformed.header.ommers_hash = proofs::calculate_ommers_root(&transformed.ommers);
|
||||
SealedBlock {
|
||||
header: transformed.header.seal_slow(),
|
||||
|
||||
@ -197,8 +197,10 @@ impl PostState {
|
||||
}
|
||||
|
||||
/// Returns the receipt root for all recorded receipts.
|
||||
/// TODO: This function hides an expensive operation (bloom). We should probably make it more
|
||||
/// explicit.
|
||||
pub fn receipts_root(&self) -> H256 {
|
||||
calculate_receipt_root_ref(self.receipts().iter().map(Into::into))
|
||||
calculate_receipt_root_ref(self.receipts())
|
||||
}
|
||||
|
||||
/// Hash all changed accounts and storage entries that are currently stored in the post state.
|
||||
|
||||
Reference in New Issue
Block a user