From 3d699ac9c6676ca7af669dd41819f53bfa779285 Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Sun, 1 Feb 2026 07:20:11 -0800 Subject: [PATCH] perf(trie): reuse account RLP buffer in SparseTrieCacheTask (#21644) Co-authored-by: Amp --- .../src/tree/payload_processor/sparse_trie.rs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/crates/engine/tree/src/tree/payload_processor/sparse_trie.rs b/crates/engine/tree/src/tree/payload_processor/sparse_trie.rs index b84e9bdcf0..b80fe2d8ee 100644 --- a/crates/engine/tree/src/tree/payload_processor/sparse_trie.rs +++ b/crates/engine/tree/src/tree/payload_processor/sparse_trie.rs @@ -5,7 +5,7 @@ use crate::tree::{ payload_processor::multiproof::{MultiProofTaskMetrics, SparseTrieUpdate}, }; use alloy_primitives::B256; -use alloy_rlp::Decodable; +use alloy_rlp::{Decodable, Encodable}; use crossbeam_channel::{Receiver as CrossbeamReceiver, Sender as CrossbeamSender}; use rayon::iter::{ParallelBridge, ParallelIterator}; use reth_errors::ProviderError; @@ -13,6 +13,7 @@ use reth_primitives_traits::Account; use reth_revm::state::EvmState; use reth_trie::{ proof_v2::Target, updates::TrieUpdates, HashedPostState, Nibbles, TrieAccount, EMPTY_ROOT_HASH, + TRIE_ACCOUNT_RLP_MAX_SIZE, }; use reth_trie_parallel::{ proof_task::{ @@ -239,6 +240,8 @@ pub(super) struct SparseTrieCacheTask slot -> lowest `min_len` requested. fetched_storage_targets: B256Map>, + /// Reusable buffer for RLP encoding of accounts. + account_rlp_buf: Vec, /// Metrics for the sparse trie. metrics: MultiProofTaskMetrics, } @@ -267,6 +270,7 @@ where pending_account_updates: Default::default(), fetched_account_targets: Default::default(), fetched_storage_targets: Default::default(), + account_rlp_buf: Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE), metrics, } } @@ -513,10 +517,12 @@ where { Vec::new() } else { - // TODO: optimize allocation - alloy_rlp::encode( - account.unwrap_or_default().into_trie_account(storage_root), - ) + self.account_rlp_buf.clear(); + account + .unwrap_or_default() + .into_trie_account(storage_root) + .encode(&mut self.account_rlp_buf); + self.account_rlp_buf.clone() }; self.account_updates.insert(*addr, LeafUpdate::Changed(encoded)); } @@ -524,6 +530,7 @@ where } // Now handle pending account updates that can be upgraded to a proper update. + let account_rlp_buf = &mut self.account_rlp_buf; self.pending_account_updates.retain(|addr, account| { // If account has pending storage updates, it is still pending. if self.storage_updates.get(addr).is_some_and(|updates| !updates.is_empty()) { @@ -557,10 +564,9 @@ where let encoded = if account.is_none_or(|account| account.is_empty()) && storage_root == EMPTY_ROOT_HASH { Vec::new() } else { - let account = account.unwrap_or_default().into_trie_account(storage_root); - - // TODO: optimize allocation - alloy_rlp::encode(account) + account_rlp_buf.clear(); + account.unwrap_or_default().into_trie_account(storage_root).encode(account_rlp_buf); + account_rlp_buf.clone() }; self.account_updates.insert(*addr, LeafUpdate::Changed(encoded));