refactor: rename BundleStateWithReceipts to BlockExecutionOutcome (#8730)

This commit is contained in:
Thomas Coratger
2024-06-11 18:06:49 +02:00
committed by GitHub
parent 95719da049
commit a5d825edb3
43 changed files with 443 additions and 409 deletions

View File

@ -11,11 +11,12 @@ use revm::{
};
use std::collections::HashMap;
/// Bundle state of post execution changes and reverts.
/// Represents the outcome of block execution, including post-execution changes and reverts.
///
/// Aggregates the changes over an arbitrary number of blocks.
/// The `ExecutionOutcome` structure aggregates the state changes over an arbitrary number of
/// blocks, capturing the resulting state, receipts, and requests following the execution.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct BundleStateWithReceipts {
pub struct ExecutionOutcome {
/// Bundle state with reverts.
pub bundle: BundleState,
/// The collection of receipts.
@ -45,8 +46,11 @@ pub type AccountRevertInit = (Option<Option<Account>>, Vec<StorageEntry>);
/// Type used to initialize revms reverts.
pub type RevertsInit = HashMap<BlockNumber, HashMap<Address, AccountRevertInit>>;
impl BundleStateWithReceipts {
/// Create Bundle State.
impl ExecutionOutcome {
/// Creates a new `ExecutionOutcome`.
///
/// This constructor initializes a new `ExecutionOutcome` instance with the provided
/// bundle state, receipts, first block number, and EIP-7685 requests.
pub const fn new(
bundle: BundleState,
receipts: Receipts,
@ -56,7 +60,10 @@ impl BundleStateWithReceipts {
Self { bundle, receipts, first_block, requests }
}
/// Create new bundle state with receipts.
/// Creates a new `ExecutionOutcome` from initialization parameters.
///
/// This constructor initializes a new `ExecutionOutcome` instance using detailed
/// initialization parameters.
pub fn new_init(
state_init: BundleStateInit,
revert_init: RevertsInit,
@ -137,7 +144,7 @@ impl BundleStateWithReceipts {
self.bundle.bytecode(code_hash).map(Bytecode)
}
/// Returns [`HashedPostState`] for this bundle state.
/// Returns [`HashedPostState`] for this execution outcome.
/// See [`HashedPostState::from_bundle_state`] for more info.
pub fn hash_state_slow(&self) -> HashedPostState {
HashedPostState::from_bundle_state(&self.bundle.state)
@ -298,6 +305,18 @@ impl BundleStateWithReceipts {
// swap bundles
std::mem::swap(&mut self.bundle, &mut other)
}
/// Create a new instance with updated receipts.
pub fn with_receipts(mut self, receipts: Receipts) -> Self {
self.receipts = receipts;
self
}
/// Create a new instance with updated requests.
pub fn with_requests(mut self, requests: Vec<Requests>) -> Self {
self.requests = requests;
self
}
}
#[cfg(test)]
@ -358,18 +377,18 @@ mod tests {
// Define the first block number
let first_block = 123;
// Create a BundleStateWithReceipts object with the created bundle, receipts, requests, and
// Create a ExecutionOutcome object with the created bundle, receipts, requests, and
// first_block
let exec_res = BundleStateWithReceipts {
let exec_res = ExecutionOutcome {
bundle: bundle.clone(),
receipts: receipts.clone(),
requests: requests.clone(),
first_block,
};
// Assert that creating a new BundleStateWithReceipts using the constructor matches exec_res
// Assert that creating a new ExecutionOutcome using the constructor matches exec_res
assert_eq!(
BundleStateWithReceipts::new(bundle, receipts.clone(), first_block, requests.clone()),
ExecutionOutcome::new(bundle, receipts.clone(), first_block, requests.clone()),
exec_res
);
@ -386,10 +405,10 @@ mod tests {
let mut revert_init: RevertsInit = HashMap::new();
revert_init.insert(123, revert_inner);
// Assert that creating a new BundleStateWithReceipts using the new_init method matches
// Assert that creating a new ExecutionOutcome using the new_init method matches
// exec_res
assert_eq!(
BundleStateWithReceipts::new_init(
ExecutionOutcome::new_init(
state_init,
revert_init,
vec![],
@ -420,9 +439,9 @@ mod tests {
// Define the first block number
let first_block = 123;
// Create a BundleStateWithReceipts object with the created bundle, receipts, requests, and
// Create a ExecutionOutcome object with the created bundle, receipts, requests, and
// first_block
let exec_res = BundleStateWithReceipts {
let exec_res = ExecutionOutcome {
bundle: Default::default(),
receipts,
requests: vec![],
@ -458,9 +477,9 @@ mod tests {
// Define the first block number
let first_block = 123;
// Create a BundleStateWithReceipts object with the created bundle, receipts, requests, and
// Create a ExecutionOutcome object with the created bundle, receipts, requests, and
// first_block
let exec_res = BundleStateWithReceipts {
let exec_res = ExecutionOutcome {
bundle: Default::default(),
receipts,
requests: vec![],
@ -493,9 +512,9 @@ mod tests {
// Define the first block number
let first_block = 123;
// Create a BundleStateWithReceipts object with the created bundle, receipts, requests, and
// Create a ExecutionOutcome object with the created bundle, receipts, requests, and
// first_block
let exec_res = BundleStateWithReceipts {
let exec_res = ExecutionOutcome {
bundle: Default::default(), // Default value for bundle
receipts, // Include the created receipts
requests: vec![], // Empty vector for requests
@ -543,9 +562,9 @@ mod tests {
// Define the first block number
let first_block = 123;
// Create a BundleStateWithReceipts object with the created bundle, receipts, requests, and
// Create a ExecutionOutcome object with the created bundle, receipts, requests, and
// first_block
let exec_res = BundleStateWithReceipts {
let exec_res = ExecutionOutcome {
bundle: Default::default(), // Default value for bundle
receipts, // Include the created receipts
requests: vec![], // Empty vector for requests
@ -558,8 +577,8 @@ mod tests {
// Assert that exec_res is not empty
assert!(!exec_res.is_empty());
// Create a BundleStateWithReceipts object with an empty Receipts object
let exec_res_empty_receipts = BundleStateWithReceipts {
// Create a ExecutionOutcome object with an empty Receipts object
let exec_res_empty_receipts = ExecutionOutcome {
bundle: Default::default(), // Default value for bundle
receipts: receipts_empty, // Include the empty receipts
requests: vec![], // Empty vector for requests

View File

@ -1,6 +1,6 @@
//! Contains [Chain], a chain of blocks and their final state.
use crate::BundleStateWithReceipts;
use crate::ExecutionOutcome;
use reth_execution_errors::BlockExecutionError;
use reth_primitives::{
Address, BlockHash, BlockNumHash, BlockNumber, ForkBlock, Receipt, SealedBlock,
@ -24,11 +24,13 @@ use std::{borrow::Cow, collections::BTreeMap, fmt, ops::RangeInclusive};
pub struct Chain {
/// All blocks in this chain.
blocks: BTreeMap<BlockNumber, SealedBlockWithSenders>,
/// The state of all accounts after execution of the _all_ blocks in this chain's range from
/// [`Chain::first`] to [`Chain::tip`], inclusive.
/// The outcome of block execution for this chain.
///
/// This state also contains the individual changes that lead to the current state.
state: BundleStateWithReceipts,
/// This field contains the state of all accounts after the execution of all blocks in this
/// chain, ranging from the [`Chain::first`] block to the [`Chain::tip`] block, inclusive.
///
/// Additionally, it includes the individual state changes that led to the current state.
execution_outcome: ExecutionOutcome,
/// State trie updates after block is added to the chain.
/// NOTE: Currently, trie updates are present only for
/// single-block chains that extend the canonical chain.
@ -43,22 +45,22 @@ impl Chain {
/// A chain of blocks should not be empty.
pub fn new(
blocks: impl IntoIterator<Item = SealedBlockWithSenders>,
state: BundleStateWithReceipts,
execution_outcome: ExecutionOutcome,
trie_updates: Option<TrieUpdates>,
) -> Self {
let blocks = BTreeMap::from_iter(blocks.into_iter().map(|b| (b.number, b)));
debug_assert!(!blocks.is_empty(), "Chain should have at least one block");
Self { blocks, state, trie_updates }
Self { blocks, execution_outcome, trie_updates }
}
/// Create new Chain from a single block and its state.
pub fn from_block(
block: SealedBlockWithSenders,
state: BundleStateWithReceipts,
execution_outcome: ExecutionOutcome,
trie_updates: Option<TrieUpdates>,
) -> Self {
Self::new([block], state, trie_updates)
Self::new([block], execution_outcome, trie_updates)
}
/// Get the blocks in this chain.
@ -86,14 +88,14 @@ impl Chain {
self.trie_updates.take();
}
/// Get post state of this chain
pub const fn state(&self) -> &BundleStateWithReceipts {
&self.state
/// Get execution outcome of this chain
pub const fn execution_outcome(&self) -> &ExecutionOutcome {
&self.execution_outcome
}
/// Prepends the given state to the current state.
pub fn prepend_state(&mut self, state: BundleState) {
self.state.prepend_state(state);
self.execution_outcome.prepend_state(state);
self.trie_updates.take(); // invalidate cached trie updates
}
@ -117,37 +119,41 @@ impl Chain {
self.blocks.iter().find_map(|(_num, block)| (block.hash() == block_hash).then_some(block))
}
/// Return post state of the block at the `block_number` or None if block is not known
pub fn state_at_block(&self, block_number: BlockNumber) -> Option<BundleStateWithReceipts> {
/// Return execution outcome at the `block_number` or None if block is not known
pub fn execution_outcome_at_block(
&self,
block_number: BlockNumber,
) -> Option<ExecutionOutcome> {
if self.tip().number == block_number {
return Some(self.state.clone())
return Some(self.execution_outcome.clone())
}
if self.blocks.contains_key(&block_number) {
let mut state = self.state.clone();
state.revert_to(block_number);
return Some(state)
let mut execution_outcome = self.execution_outcome.clone();
execution_outcome.revert_to(block_number);
return Some(execution_outcome)
}
None
}
/// Destructure the chain into its inner components, the blocks and the state at the tip of the
/// chain.
pub fn into_inner(
self,
) -> (ChainBlocks<'static>, BundleStateWithReceipts, Option<TrieUpdates>) {
(ChainBlocks { blocks: Cow::Owned(self.blocks) }, self.state, self.trie_updates)
/// Destructure the chain into its inner components:
/// 1. The blocks contained in the chain.
/// 2. The execution outcome representing the final state.
/// 3. The optional trie updates.
pub fn into_inner(self) -> (ChainBlocks<'static>, ExecutionOutcome, Option<TrieUpdates>) {
(ChainBlocks { blocks: Cow::Owned(self.blocks) }, self.execution_outcome, self.trie_updates)
}
/// Destructure the chain into its inner components, the blocks and the state at the tip of the
/// chain.
pub const fn inner(&self) -> (ChainBlocks<'_>, &BundleStateWithReceipts) {
(ChainBlocks { blocks: Cow::Borrowed(&self.blocks) }, &self.state)
/// Destructure the chain into its inner components:
/// 1. A reference to the blocks contained in the chain.
/// 2. A reference to the execution outcome representing the final state.
pub const fn inner(&self) -> (ChainBlocks<'_>, &ExecutionOutcome) {
(ChainBlocks { blocks: Cow::Borrowed(&self.blocks) }, &self.execution_outcome)
}
/// Returns an iterator over all the receipts of the blocks in the chain.
pub fn block_receipts_iter(&self) -> impl Iterator<Item = &Vec<Option<Receipt>>> + '_ {
self.state.receipts().iter()
self.execution_outcome.receipts().iter()
}
/// Returns an iterator over all blocks in the chain with increasing block number.
@ -206,7 +212,7 @@ impl Chain {
/// Get all receipts for the given block.
pub fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option<Vec<&Receipt>> {
let num = self.block_number(block_hash)?;
self.state.receipts_by_block(num).iter().map(Option::as_ref).collect()
self.execution_outcome.receipts_by_block(num).iter().map(Option::as_ref).collect()
}
/// Get all receipts with attachment.
@ -214,7 +220,8 @@ impl Chain {
/// Attachment includes block number, block hash, transaction hash and transaction index.
pub fn receipts_with_attachment(&self) -> Vec<BlockReceipts> {
let mut receipt_attach = Vec::new();
for ((block_num, block), receipts) in self.blocks().iter().zip(self.state.receipts().iter())
for ((block_num, block), receipts) in
self.blocks().iter().zip(self.execution_outcome.receipts().iter())
{
let mut tx_receipts = Vec::new();
for (tx, receipt) in block.body.iter().zip(receipts.iter()) {
@ -231,9 +238,13 @@ impl Chain {
/// Append a single block with state to the chain.
/// This method assumes that blocks attachment to the chain has already been validated.
pub fn append_block(&mut self, block: SealedBlockWithSenders, state: BundleStateWithReceipts) {
pub fn append_block(
&mut self,
block: SealedBlockWithSenders,
execution_outcome: ExecutionOutcome,
) {
self.blocks.insert(block.number, block);
self.state.extend(state);
self.execution_outcome.extend(execution_outcome);
self.trie_updates.take(); // reset
}
@ -252,7 +263,7 @@ impl Chain {
// Insert blocks from other chain
self.blocks.extend(other.blocks);
self.state.extend(other.state);
self.execution_outcome.extend(other.execution_outcome);
self.trie_updates.take(); // reset
Ok(())
@ -309,19 +320,20 @@ impl Chain {
let split_at = block_number + 1;
let higher_number_blocks = self.blocks.split_off(&split_at);
let state = std::mem::take(&mut self.state);
let (canonical_state, pending_state) = state.split_at(split_at);
let execution_outcome = std::mem::take(&mut self.execution_outcome);
let (canonical_block_exec_outcome, pending_block_exec_outcome) =
execution_outcome.split_at(split_at);
// TODO: Currently, trie updates are reset on chain split.
// Add tests ensuring that it is valid to leave updates in the pending chain.
ChainSplit::Split {
canonical: Self {
state: canonical_state.expect("split in range"),
execution_outcome: canonical_block_exec_outcome.expect("split in range"),
blocks: self.blocks,
trie_updates: None,
},
pending: Self {
state: pending_state,
execution_outcome: pending_block_exec_outcome,
blocks: higher_number_blocks,
trie_updates: None,
},
@ -513,7 +525,7 @@ mod tests {
#[test]
fn test_number_split() {
let block_state1 = BundleStateWithReceipts::new(
let execution_outcome1 = ExecutionOutcome::new(
BundleState::new(
vec![(
Address::new([2; 20]),
@ -529,7 +541,7 @@ mod tests {
vec![],
);
let block_state2 = BundleStateWithReceipts::new(
let execution_outcome2 = ExecutionOutcome::new(
BundleState::new(
vec![(
Address::new([3; 20]),
@ -557,30 +569,37 @@ mod tests {
block2.set_hash(block2_hash);
block2.senders.push(Address::new([4; 20]));
let mut block_state_extended = block_state1;
block_state_extended.extend(block_state2);
let mut block_state_extended = execution_outcome1;
block_state_extended.extend(execution_outcome2);
let chain = Chain::new(vec![block1.clone(), block2.clone()], block_state_extended, None);
let (split1_state, split2_state) = chain.state.clone().split_at(2);
let (split1_execution_outcome, split2_execution_outcome) =
chain.execution_outcome.clone().split_at(2);
let chain_split1 = Chain {
state: split1_state.unwrap(),
execution_outcome: split1_execution_outcome.unwrap(),
blocks: BTreeMap::from([(1, block1.clone())]),
trie_updates: None,
};
let chain_split2 = Chain {
state: split2_state,
execution_outcome: split2_execution_outcome,
blocks: BTreeMap::from([(2, block2.clone())]),
trie_updates: None,
};
// return tip state
assert_eq!(chain.state_at_block(block2.number), Some(chain.state.clone()));
assert_eq!(chain.state_at_block(block1.number), Some(chain_split1.state.clone()));
assert_eq!(
chain.execution_outcome_at_block(block2.number),
Some(chain.execution_outcome.clone())
);
assert_eq!(
chain.execution_outcome_at_block(block1.number),
Some(chain_split1.execution_outcome.clone())
);
// state at unknown block
assert_eq!(chain.state_at_block(100), None);
assert_eq!(chain.execution_outcome_at_block(100), None);
// split in two
assert_eq!(

View File

@ -4,7 +4,7 @@ use crate::execute::{
BatchExecutor, BlockExecutionInput, BlockExecutionOutput, BlockExecutorProvider, Executor,
};
use reth_execution_errors::BlockExecutionError;
use reth_execution_types::BundleStateWithReceipts;
use reth_execution_types::ExecutionOutcome;
use reth_primitives::{BlockNumber, BlockWithSenders, Receipt};
use reth_prune_types::PruneModes;
use reth_storage_errors::provider::ProviderError;
@ -76,19 +76,19 @@ where
A: for<'a> BatchExecutor<
DB,
Input<'a> = BlockExecutionInput<'a, BlockWithSenders>,
Output = BundleStateWithReceipts,
Output = ExecutionOutcome,
Error = BlockExecutionError,
>,
B: for<'a> BatchExecutor<
DB,
Input<'a> = BlockExecutionInput<'a, BlockWithSenders>,
Output = BundleStateWithReceipts,
Output = ExecutionOutcome,
Error = BlockExecutionError,
>,
DB: Database<Error = ProviderError>,
{
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = BundleStateWithReceipts;
type Output = ExecutionOutcome;
type Error = BlockExecutionError;
fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> {

View File

@ -1,6 +1,6 @@
//! Traits for execution.
use reth_execution_types::BundleStateWithReceipts;
use reth_execution_types::ExecutionOutcome;
use reth_primitives::{BlockNumber, BlockWithSenders, Receipt, Request, U256};
use reth_prune_types::PruneModes;
use revm::db::BundleState;
@ -91,7 +91,7 @@ pub trait BatchExecutor<DB> {
///
/// Contains the state changes, transaction receipts, and total gas used in the block.
///
/// TODO(mattsse): combine with `BundleStateWithReceipts`
/// TODO(mattsse): combine with `ExecutionOutcome`
#[derive(Debug)]
pub struct BlockExecutionOutput<T> {
/// The changed state of the block after execution.
@ -150,7 +150,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static {
type BatchExecutor<DB: Database<Error = ProviderError>>: for<'a> BatchExecutor<
DB,
Input<'a> = BlockExecutionInput<'a, BlockWithSenders>,
Output = BundleStateWithReceipts,
Output = ExecutionOutcome,
Error = BlockExecutionError,
>;
@ -216,7 +216,7 @@ mod tests {
impl<DB> BatchExecutor<DB> for TestExecutor<DB> {
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = BundleStateWithReceipts;
type Output = ExecutionOutcome;
type Error = BlockExecutionError;
fn execute_and_verify_one(&mut self, _input: Self::Input<'_>) -> Result<(), Self::Error> {

View File

@ -1,7 +1,7 @@
//! A no operation block executor implementation.
use reth_execution_errors::BlockExecutionError;
use reth_execution_types::BundleStateWithReceipts;
use reth_execution_types::ExecutionOutcome;
use reth_primitives::{BlockNumber, BlockWithSenders, Receipt};
use reth_prune_types::PruneModes;
use reth_storage_errors::provider::ProviderError;
@ -50,7 +50,7 @@ impl<DB> Executor<DB> for NoopBlockExecutorProvider {
impl<DB> BatchExecutor<DB> for NoopBlockExecutorProvider {
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = BundleStateWithReceipts;
type Output = ExecutionOutcome;
type Error = BlockExecutionError;
fn execute_and_verify_one(&mut self, _: Self::Input<'_>) -> Result<(), Self::Error> {

View File

@ -5,7 +5,7 @@ use crate::execute::{
};
use parking_lot::Mutex;
use reth_execution_errors::BlockExecutionError;
use reth_execution_types::BundleStateWithReceipts;
use reth_execution_types::ExecutionOutcome;
use reth_primitives::{BlockNumber, BlockWithSenders, Receipt};
use reth_prune_types::PruneModes;
use reth_storage_errors::provider::ProviderError;
@ -15,12 +15,12 @@ use std::sync::Arc;
/// A [`BlockExecutorProvider`] that returns mocked execution results.
#[derive(Clone, Debug, Default)]
pub struct MockExecutorProvider {
exec_results: Arc<Mutex<Vec<BundleStateWithReceipts>>>,
exec_results: Arc<Mutex<Vec<ExecutionOutcome>>>,
}
impl MockExecutorProvider {
/// Extend the mocked execution results
pub fn extend(&self, results: impl IntoIterator<Item = impl Into<BundleStateWithReceipts>>) {
pub fn extend(&self, results: impl IntoIterator<Item = impl Into<ExecutionOutcome>>) {
self.exec_results.lock().extend(results.into_iter().map(Into::into));
}
}
@ -51,7 +51,7 @@ impl<DB> Executor<DB> for MockExecutorProvider {
type Error = BlockExecutionError;
fn execute(self, _: Self::Input<'_>) -> Result<Self::Output, Self::Error> {
let BundleStateWithReceipts { bundle, receipts, requests, first_block: _ } =
let ExecutionOutcome { bundle, receipts, requests, first_block: _ } =
self.exec_results.lock().pop().unwrap();
Ok(BlockExecutionOutput {
state: bundle,
@ -64,7 +64,7 @@ impl<DB> Executor<DB> for MockExecutorProvider {
impl<DB> BatchExecutor<DB> for MockExecutorProvider {
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = BundleStateWithReceipts;
type Output = ExecutionOutcome;
type Error = BlockExecutionError;
fn execute_and_verify_one(&mut self, _: Self::Input<'_>) -> Result<(), Self::Error> {