Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions crates/optimism/payload/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,10 +381,15 @@ impl<Txs> OpBuilder<'_, Txs> {
ctx.execute_sequencer_transactions(&mut builder)?;
builder.into_executor().apply_post_execution_changes()?;

let ExecutionWitnessRecord { hashed_state, codes, keys } =
let ExecutionWitnessRecord { hashed_state, codes, keys, lowest_block_number: _ } =
ExecutionWitnessRecord::from_executed_state(&db);
let state = state_provider.witness(Default::default(), hashed_state)?;
Ok(ExecutionWitness { state: state.into_iter().collect(), codes, keys, headers: vec![] })
Ok(ExecutionWitness {
state: state.into_iter().collect(),
codes,
keys,
..Default::default()
})
}
}

Expand Down
10 changes: 10 additions & 0 deletions crates/revm/src/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ pub struct ExecutionWitnessRecord {
///
/// `keccak(address|slot) => address|slot`
pub keys: Vec<Bytes>,
/// The lowest block number referenced by any BLOCKHASH opcode call during transaction
/// execution.
///
/// This helps determine which ancestor block headers must be included in the
/// `ExecutionWitness`.
///
/// `None` - when the BLOCKHASH opcode was not called during execution
pub lowest_block_number: Option<u64>,
}

impl ExecutionWitnessRecord {
Expand Down Expand Up @@ -62,6 +70,8 @@ impl ExecutionWitnessRecord {
}
}
}
// BTreeMap keys are ordered, so the first key is the smallest
self.lowest_block_number = statedb.block_hashes.keys().next().copied()
}

/// Creates the record from the state after execution.
Expand Down
40 changes: 36 additions & 4 deletions crates/rpc/rpc/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,10 @@ where
block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
) -> Result<ExecutionWitness, Eth::Error> {
let this = self.clone();
self.eth_api()
let block_number = block.header().number();

let (mut exec_witness, lowest_block_number) = self
.eth_api()
.spawn_with_state_at_block(block.parent_hash().into(), move |state_provider| {
let db = StateProviderDatabase::new(&state_provider);
let block_executor = this.inner.block_executor.executor(db);
Expand All @@ -644,14 +647,43 @@ where
})
.map_err(|err| EthApiError::Internal(err.into()))?;

let ExecutionWitnessRecord { hashed_state, codes, keys } = witness_record;
let ExecutionWitnessRecord { hashed_state, codes, keys, lowest_block_number } =
witness_record;

let state = state_provider
.witness(Default::default(), hashed_state)
.map_err(EthApiError::from)?;
Ok(ExecutionWitness { state, codes, keys, headers: vec![] })
Ok((
ExecutionWitness { state, codes, keys, ..Default::default() },
lowest_block_number,
))
})
.await
.await?;

let smallest = match lowest_block_number {
Some(smallest) => smallest,
None => {
// Return only the parent header, if there were no calls to the
// BLOCKHASH opcode.
block_number.saturating_sub(1)
}
};

let range = smallest..block_number;
// TODO: Check if headers_range errors when one of the headers in the range is missing
exec_witness.headers = self
.provider()
.headers_range(range)
.map_err(EthApiError::from)?
.into_iter()
.map(|header| {
let mut serialized_header = Vec::new();
header.encode(&mut serialized_header);
serialized_header.into()
})
.collect();

Ok(exec_witness)
}

/// Returns the code associated with a given hash at the specified block ID. If no code is
Expand Down
Loading