Skip to content

Commit 6033b3a

Browse files
authored
Fix withdrawals accesses in state trie (#176)
1 parent baec0f2 commit 6033b3a

File tree

2 files changed

+51
-42
lines changed

2 files changed

+51
-42
lines changed

trace_decoder/src/decoding.rs

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -270,14 +270,13 @@ impl ProcessedBlockTrace {
270270
e
271271
})?;
272272

273-
let dummies_added = Self::pad_gen_inputs_with_dummy_inputs_if_needed(
273+
Self::pad_gen_inputs_with_dummy_inputs_if_needed(
274274
&mut txn_gen_inputs,
275275
&other_data,
276276
&extra_data,
277277
&extra_data_for_dummies,
278278
&initial_tries_for_dummies,
279279
&curr_block_tries,
280-
!self.withdrawals.is_empty(),
281280
);
282281

283282
if !self.withdrawals.is_empty() {
@@ -515,19 +514,15 @@ impl ProcessedBlockTrace {
515514
/// that we have two entries in total. These dummy entries serve only to
516515
/// allow the proof generation process to finish. Specifically, we need
517516
/// at least two entries to generate an agg proof, and we need an agg
518-
/// proof to generate a block proof. These entries do not mutate state
519-
/// (unless there are withdrawals in the block (see
520-
/// `[add_withdrawals_to_txns]`), where the final one will mutate the
521-
/// state trie.
517+
/// proof to generate a block proof. These entries do not mutate state.
522518
fn pad_gen_inputs_with_dummy_inputs_if_needed(
523519
gen_inputs: &mut Vec<GenerationInputs>,
524520
other_data: &OtherBlockData,
525521
final_extra_data: &ExtraBlockData,
526522
initial_extra_data: &ExtraBlockData,
527523
initial_tries: &PartialTrieState,
528524
final_tries: &PartialTrieState,
529-
has_withdrawals: bool,
530-
) -> bool {
525+
) {
531526
match gen_inputs.len() {
532527
0 => {
533528
debug_assert!(initial_tries.state == final_tries.state);
@@ -538,42 +533,19 @@ impl ProcessedBlockTrace {
538533
final_extra_data,
539534
initial_tries,
540535
));
541-
542-
true
543536
}
544537
1 => {
545538
// We just need one dummy entry.
546-
// If there are withdrawals, we will need to append them at the end of the block
547-
// execution, in which case we directly append the dummy proof
548-
// after the only txn of this block.
549-
// If there are no withdrawals, then the dummy proof will be prepended to the
550-
// actual txn.
551-
match has_withdrawals {
552-
false => {
553-
let dummy_txn =
554-
create_dummy_gen_input(other_data, initial_extra_data, initial_tries);
555-
gen_inputs.insert(0, dummy_txn)
556-
}
557-
true => {
558-
let dummy_txn =
559-
create_dummy_gen_input(other_data, final_extra_data, final_tries);
560-
gen_inputs.push(dummy_txn)
561-
}
562-
};
563-
564-
true
539+
// The dummy proof will be prepended to the actual txn.
540+
let dummy_txn =
541+
create_dummy_gen_input(other_data, initial_extra_data, initial_tries);
542+
gen_inputs.insert(0, dummy_txn)
565543
}
566-
_ => false,
544+
_ => (),
567545
}
568546
}
569547

570-
/// The withdrawals are always in the final ir payload. How they are placed
571-
/// differs based on whether or not there are already dummy proofs present
572-
/// in the IR. The rules for adding withdrawals to the IR list are:
573-
/// - If dummy proofs are already present, then the withdrawals are added to
574-
/// the last dummy proof (always index `1`).
575-
/// - If no dummy proofs are already present, then a dummy proof that just
576-
/// contains the withdrawals is appended to the end of the IR vec.
548+
/// The withdrawals are always in the final ir payload.
577549
fn add_withdrawals_to_txns(
578550
txn_ir: &mut [GenerationInputs],
579551
final_trie_state: &mut PartialTrieState,
@@ -585,15 +557,27 @@ impl ProcessedBlockTrace {
585557
.map(|(addr, v)| (*addr, hash(addr.as_bytes()), *v))
586558
};
587559

560+
let last_inputs = txn_ir
561+
.last_mut()
562+
.expect("We cannot have an empty list of payloads.");
563+
564+
if last_inputs.signed_txn.is_none() {
565+
// This is a dummy payload, hence it does not contain yet
566+
// state accesses to the withdrawal addresses.
567+
let withdrawal_addrs =
568+
withdrawals_with_hashed_addrs_iter().map(|(_, h_addr, _)| h_addr);
569+
last_inputs.tries.state_trie = create_minimal_state_partial_trie(
570+
&last_inputs.tries.state_trie,
571+
withdrawal_addrs,
572+
iter::empty(),
573+
)?;
574+
}
575+
588576
Self::update_trie_state_from_withdrawals(
589577
withdrawals_with_hashed_addrs_iter(),
590578
&mut final_trie_state.state,
591579
)?;
592580

593-
let last_inputs = txn_ir
594-
.last_mut()
595-
.expect("We cannot have an empty list of payloads.");
596-
597581
last_inputs.withdrawals = withdrawals;
598582
last_inputs.trie_roots_after.state_root = final_trie_state.state.hash();
599583

trace_decoder/src/processed_block_trace.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,30 @@ impl BlockTrace {
8989
extra_code_hash_mappings: pre_image_data.extra_code_hash_mappings.unwrap_or_default(),
9090
};
9191

92+
let last_tx_idx = self.txn_info.len().saturating_sub(1);
93+
9294
let txn_info = self
9395
.txn_info
9496
.into_iter()
95-
.map(|t| t.into_processed_txn_info(&all_accounts_in_pre_image, &mut code_hash_resolver))
97+
.enumerate()
98+
.map(|(i, t)| {
99+
let extra_state_accesses = if last_tx_idx == i {
100+
// If this is the last transaction, we mark the withdrawal addresses
101+
// as accessed in the state trie.
102+
withdrawals
103+
.iter()
104+
.map(|(addr, _)| hash(addr.as_bytes()))
105+
.collect::<Vec<_>>()
106+
} else {
107+
Vec::new()
108+
};
109+
110+
t.into_processed_txn_info(
111+
&all_accounts_in_pre_image,
112+
&extra_state_accesses,
113+
&mut code_hash_resolver,
114+
)
115+
})
96116
.collect::<Vec<_>>();
97117

98118
ProcessedBlockTrace {
@@ -245,6 +265,7 @@ impl TxnInfo {
245265
fn into_processed_txn_info<F: CodeHashResolveFunc>(
246266
self,
247267
all_accounts_in_pre_image: &[(HashedAccountAddr, AccountRlp)],
268+
extra_state_accesses: &[HashedAccountAddr],
248269
code_hash_resolver: &mut CodeHashResolving<F>,
249270
) -> ProcessedTxnInfo {
250271
let mut nodes_used_by_txn = NodesUsedByTxn::default();
@@ -325,6 +346,10 @@ impl TxnInfo {
325346
}
326347
}
327348

349+
for &hashed_addr in extra_state_accesses {
350+
nodes_used_by_txn.state_accesses.push(hashed_addr);
351+
}
352+
328353
let accounts_with_storage_accesses: HashSet<_> = HashSet::from_iter(
329354
nodes_used_by_txn
330355
.storage_accesses

0 commit comments

Comments
 (0)