Skip to content

Commit 00cd239

Browse files
authored
fix: preload non-existent proof targets (#706)
## 📝 Summary Previously, generating proofs for accounts missing from bundle state did not work, because the state root algorithm requires account info to be present and does not have access to state provider to be able to fetch. Impose a requirement on the caller to pre-load proof target accounts into bundle state. Document the change in the behavior. ## ✅ I have completed the following steps: * [x] Run `make lint` * [x] Run `make test` * [ ] Added tests (if applicable)
1 parent 5c905e4 commit 00cd239

File tree

3 files changed

+38
-20
lines changed

3 files changed

+38
-20
lines changed

crates/eth-sparse-mpt/src/v2/mod.rs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ impl RootHashCalculator {
286286
.bundle_accounts_iter()
287287
.par_bridge()
288288
.for_each(|(address, bundle_account)| {
289-
if bundle_account.status.is_not_modified() {
289+
if bundle_account.status.is_not_modified() && !proof_targets.contains(&address) {
290290
return;
291291
}
292292

@@ -357,19 +357,6 @@ impl RootHashCalculator {
357357
applied_storage_ops_previous_iteration;
358358
});
359359

360-
for proof_target in proof_targets {
361-
if outcome
362-
.bundle
363-
.state
364-
.get(proof_target)
365-
.is_none_or(|acc| !acc.status.is_not_modified())
366-
{
367-
self.changed_account
368-
.write()
369-
.push((*proof_target, StorageTrieStatus::Hashed));
370-
}
371-
}
372-
373360
Ok(())
374361
}
375362

crates/rbuilder/src/building/mod.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::{
2+
building::cached_reads::CachedDB,
23
live_builder::{
34
block_list_provider::BlockList, order_input::mempool_txs_detector::MempoolTxsDetector,
45
payload_events::InternalPayloadId,
@@ -39,6 +40,7 @@ use reth::{
3940
payload::PayloadId,
4041
primitives::{Block, SealedBlock},
4142
providers::ExecutionOutcome,
43+
revm::database::StateProviderDatabase,
4244
};
4345
use reth_chainspec::{ChainSpec, EthChainSpec, EthereumHardforks};
4446
use reth_errors::{BlockExecutionError, BlockValidationError, ProviderError};
@@ -48,15 +50,17 @@ use reth_node_api::{EngineApiMessageVersion, PayloadBuilderAttributes};
4850
use reth_payload_builder::EthPayloadBuilderAttributes;
4951
use reth_primitives::BlockBody;
5052
use reth_primitives_traits::{proofs, Block as _};
53+
use reth_provider::StateProvider;
5154
use revm::{
5255
context::BlockEnv,
5356
context_interface::{block::BlobExcessGasAndPrice, result::InvalidTransaction},
54-
database::states::bundle_state::BundleRetention,
57+
database::{states::bundle_state::BundleRetention, BundleAccount},
5558
primitives::hardfork::SpecId,
59+
Database as _,
5660
};
5761
use serde::Deserialize;
5862
use std::{
59-
collections::{HashMap, HashSet},
63+
collections::{hash_map, HashMap, HashSet},
6064
hash::Hash,
6165
ops::{Add, AddAssign},
6266
str::FromStr,
@@ -1028,9 +1032,10 @@ impl<Tracer: SimulationTracer, PartialBlockExecutionTracerType: PartialBlockExec
10281032
let step_start = Instant::now();
10291033

10301034
// calculate the state root
1031-
let (bundle, _) = state.into_parts();
1035+
let (bundle, state_provider) = state.into_parts();
10321036
// we use execution outcome here only for interface compatibility, its just a wrapper around bundle
1033-
let execution_outcome = ExecutionOutcome::new(bundle, Vec::new(), block_number, Vec::new());
1037+
let mut execution_outcome =
1038+
ExecutionOutcome::new(bundle, Vec::new(), block_number, Vec::new());
10341039
let state_root = ctx.root_hasher.state_root(&execution_outcome, local_ctx)?;
10351040
let root_hash_time = step_start.elapsed();
10361041

@@ -1138,7 +1143,8 @@ impl<Tracer: SimulationTracer, PartialBlockExecutionTracerType: PartialBlockExec
11381143

11391144
let bid_adjustments = Self::generate_bid_adjustments(
11401145
&block.header,
1141-
&execution_outcome,
1146+
&state_provider,
1147+
&mut execution_outcome,
11421148
ctx,
11431149
local_ctx,
11441150
placeholder_transaction_proof,
@@ -1180,7 +1186,8 @@ impl<Tracer: SimulationTracer, PartialBlockExecutionTracerType: PartialBlockExec
11801186

11811187
fn generate_bid_adjustments(
11821188
header: &Header,
1183-
outcome: &ExecutionOutcome,
1189+
state_provider: &impl StateProvider,
1190+
outcome: &mut ExecutionOutcome,
11841191
ctx: &BlockBuildingContext,
11851192
local_ctx: &mut ThreadBlockBuildingContext,
11861193
placeholder_transaction_proof: Vec<Bytes>,
@@ -1209,6 +1216,28 @@ impl<Tracer: SimulationTracer, PartialBlockExecutionTracerType: PartialBlockExec
12091216
.into_iter()
12101217
.chain(ctx.adjustment_fee_payers.clone()),
12111218
);
1219+
1220+
// Pre-load all proof targets that are missing from the bundle state.
1221+
// This is a requirement for accounts to become a part of the trie and be able to generate proofs for them.
1222+
let mut cachedb = CachedDB::new(
1223+
StateProviderDatabase::new(state_provider),
1224+
&mut local_ctx.cached_reads,
1225+
&ctx.shared_cached_reads,
1226+
);
1227+
for fee_payer in &ctx.adjustment_fee_payers {
1228+
if let hash_map::Entry::Vacant(entry) = outcome.bundle.state.entry(*fee_payer) {
1229+
let account_info = cachedb
1230+
.basic(*fee_payer)
1231+
.map_err(|error| FinalizeError::Other(error.into()))?;
1232+
entry.insert(BundleAccount {
1233+
original_info: account_info.clone(),
1234+
info: account_info,
1235+
status: revm::database::AccountStatus::Loaded,
1236+
storage: Default::default(),
1237+
});
1238+
}
1239+
}
1240+
12121241
let mut account_proofs =
12131242
ctx.root_hasher
12141243
.account_proofs(outcome, &proof_targets, local_ctx)?;

crates/rbuilder/src/provider/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ pub trait RootHasher: std::fmt::Debug + Send + Sync {
6060
) -> Result<B256, RootHashError>;
6161

6262
/// Generate the account proof for the target address.
63+
/// NOTE: Proof targets are required to be loaded in the bundle state of [`ExecutionOutcome`].
64+
/// If the accounts are missing from the bundle state, the method will return "KeyNotFound" error.
6365
fn account_proofs(
6466
&self,
6567
outcome: &ExecutionOutcome,

0 commit comments

Comments
 (0)