refactor: replace BatchBlockExecutionOutput by BundleStateWithReceipts (#8709)

This commit is contained in:
Thomas Coratger
2024-06-10 18:46:39 +02:00
committed by GitHub
parent 3a8baa0106
commit ad0be4ca06
27 changed files with 138 additions and 120 deletions

View File

@ -214,7 +214,12 @@ impl AppendableChain {
.consensus
.validate_block_post_execution(&block, PostExecutionInput::new(&receipts, &requests))?;
let bundle_state = BundleStateWithReceipts::new(state, receipts.into(), block.number);
let bundle_state = BundleStateWithReceipts::new(
state,
receipts.into(),
block.number,
vec![requests.into()],
);
// check state root if the block extends the canonical chain __and__ if state root
// validation was requested.

View File

@ -389,9 +389,14 @@ impl StorageInner {
);
// execute the block
let BlockExecutionOutput { state, receipts, .. } =
let BlockExecutionOutput { state, receipts, requests: block_execution_requests, .. } =
executor.executor(&mut db).execute((&block, U256::ZERO).into())?;
let bundle_state = BundleStateWithReceipts::new(state, receipts.into(), block.number);
let bundle_state = BundleStateWithReceipts::new(
state,
receipts.into(),
block.number,
vec![block_execution_requests.into()],
);
// todo(onbjerg): we should not pass requests around as this is building a block, which
// means we need to extract the requests from the execution output and compute the requests

View File

@ -17,6 +17,7 @@ reth-primitives.workspace = true
reth-revm.workspace = true
reth-ethereum-consensus.workspace = true
reth-prune-types.workspace = true
reth-execution-types.workspace = true
# Ethereum
revm-primitives.workspace = true

View File

@ -7,11 +7,12 @@ use crate::{
use reth_ethereum_consensus::validate_block_post_execution;
use reth_evm::{
execute::{
BatchBlockExecutionOutput, BatchExecutor, BlockExecutionError, BlockExecutionInput,
BlockExecutionOutput, BlockExecutorProvider, BlockValidationError, Executor, ProviderError,
BatchExecutor, BlockExecutionError, BlockExecutionInput, BlockExecutionOutput,
BlockExecutorProvider, BlockValidationError, Executor, ProviderError,
},
ConfigureEvm,
};
use reth_execution_types::BundleStateWithReceipts;
use reth_primitives::{
BlockNumber, BlockWithSenders, ChainSpec, Hardfork, Header, Receipt, Request, Withdrawals,
MAINNET, U256,
@ -405,7 +406,7 @@ where
DB: Database<Error = ProviderError>,
{
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = BatchBlockExecutionOutput;
type Output = BundleStateWithReceipts;
type Error = BlockExecutionError;
fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> {
@ -435,11 +436,11 @@ where
fn finalize(mut self) -> Self::Output {
self.stats.log_debug();
BatchBlockExecutionOutput::new(
BundleStateWithReceipts::new(
self.executor.state.take_bundle(),
self.batch_record.take_receipts(),
self.batch_record.take_requests(),
self.batch_record.first_block().unwrap_or_default(),
self.batch_record.take_requests(),
)
}

View File

@ -444,8 +444,12 @@ where
// and 4788 contract call
db.merge_transitions(BundleRetention::PlainState);
let bundle =
BundleStateWithReceipts::new(db.take_bundle(), vec![receipts].into(), block_number);
let bundle = BundleStateWithReceipts::new(
db.take_bundle(),
vec![receipts].into(),
block_number,
vec![requests.clone().unwrap_or_default()],
);
let receipts_root = bundle.receipts_root_slow(block_number).expect("Number is in range");
let logs_bloom = bundle.block_logs_bloom(block_number).expect("Number is in range");

View File

@ -17,6 +17,7 @@ reth-primitives.workspace = true
revm-primitives.workspace = true
reth-prune-types.workspace = true
reth-storage-errors.workspace = true
reth-execution-types.workspace = true
revm.workspace = true

View File

@ -14,7 +14,6 @@ workspace = true
reth-primitives.workspace = true
reth-execution-errors.workspace = true
reth-trie.workspace = true
reth-evm.workspace = true
revm.workspace = true

View File

@ -1,9 +1,8 @@
use reth_evm::execute::BatchBlockExecutionOutput;
use reth_primitives::{
logs_bloom,
revm::compat::{into_reth_acc, into_revm_acc},
Account, Address, BlockNumber, Bloom, Bytecode, Log, Receipt, Receipts, StorageEntry, B256,
U256,
Account, Address, BlockNumber, Bloom, Bytecode, Log, Receipt, Receipts, Requests, StorageEntry,
B256, U256,
};
use reth_trie::HashedPostState;
use revm::{
@ -27,23 +26,13 @@ pub struct BundleStateWithReceipts {
pub receipts: Receipts,
/// First block of bundle state.
pub first_block: BlockNumber,
}
// TODO(mattsse): unify the types, currently there's a cyclic dependency between
impl From<BatchBlockExecutionOutput> for BundleStateWithReceipts {
fn from(value: BatchBlockExecutionOutput) -> Self {
let BatchBlockExecutionOutput { bundle, receipts, requests: _, first_block } = value;
Self { bundle, receipts, first_block }
}
}
// TODO(mattsse): unify the types, currently there's a cyclic dependency between
impl From<BundleStateWithReceipts> for BatchBlockExecutionOutput {
fn from(value: BundleStateWithReceipts) -> Self {
let BundleStateWithReceipts { bundle, receipts, first_block } = value;
// TODO(alexey): add requests
Self { bundle, receipts, requests: Vec::default(), first_block }
}
/// The collection of EIP-7685 requests.
/// Outer vector stores requests for each block sequentially.
/// The inner vector stores requests ordered by transaction number.
///
/// A transaction may have zero or more requests, so the length of the inner vector is not
/// guaranteed to be the same as the number of transactions.
pub requests: Vec<Requests>,
}
/// Type used to initialize revms bundle state.
@ -58,8 +47,13 @@ pub type RevertsInit = HashMap<BlockNumber, HashMap<Address, AccountRevertInit>>
impl BundleStateWithReceipts {
/// Create Bundle State.
pub const fn new(bundle: BundleState, receipts: Receipts, first_block: BlockNumber) -> Self {
Self { bundle, receipts, first_block }
pub const fn new(
bundle: BundleState,
receipts: Receipts,
first_block: BlockNumber,
requests: Vec<Requests>,
) -> Self {
Self { bundle, receipts, first_block, requests }
}
/// Create new bundle state with receipts.
@ -69,6 +63,7 @@ impl BundleStateWithReceipts {
contracts_init: Vec<(B256, Bytecode)>,
receipts: Receipts,
first_block: BlockNumber,
requests: Vec<Requests>,
) -> Self {
// sort reverts by block number
let mut reverts = revert_init.into_iter().collect::<Vec<_>>();
@ -97,7 +92,7 @@ impl BundleStateWithReceipts {
contracts_init.into_iter().map(|(code_hash, bytecode)| (code_hash, bytecode.0)),
);
Self { bundle, receipts, first_block }
Self { bundle, receipts, first_block, requests }
}
/// Return revm bundle state.

View File

@ -526,6 +526,7 @@ mod tests {
),
vec![vec![]].into(),
1,
vec![],
);
let block_state2 = BundleStateWithReceipts::new(
@ -541,6 +542,7 @@ mod tests {
),
vec![vec![]].into(),
2,
vec![],
);
let mut block1 = SealedBlockWithSenders::default();

View File

@ -1,10 +1,10 @@
//! Helper type that represents one of two possible executor types
use crate::execute::{
BatchBlockExecutionOutput, BatchExecutor, BlockExecutionInput, BlockExecutionOutput,
BlockExecutorProvider, Executor,
BatchExecutor, BlockExecutionInput, BlockExecutionOutput, BlockExecutorProvider, Executor,
};
use reth_execution_errors::BlockExecutionError;
use reth_execution_types::BundleStateWithReceipts;
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 = BatchBlockExecutionOutput,
Output = BundleStateWithReceipts,
Error = BlockExecutionError,
>,
B: for<'a> BatchExecutor<
DB,
Input<'a> = BlockExecutionInput<'a, BlockWithSenders>,
Output = BatchBlockExecutionOutput,
Output = BundleStateWithReceipts,
Error = BlockExecutionError,
>,
DB: Database<Error = ProviderError>,
{
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = BatchBlockExecutionOutput;
type Output = BundleStateWithReceipts;
type Error = BlockExecutionError;
fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> {

View File

@ -1,6 +1,7 @@
//! Traits for execution.
use reth_primitives::{BlockNumber, BlockWithSenders, Receipt, Receipts, Request, Requests, U256};
use reth_execution_types::BundleStateWithReceipts;
use reth_primitives::{BlockNumber, BlockWithSenders, Receipt, Request, U256};
use reth_prune_types::PruneModes;
use revm::db::BundleState;
use revm_primitives::db::Database;
@ -103,40 +104,6 @@ pub struct BlockExecutionOutput<T> {
pub gas_used: u64,
}
/// The output of a batch of ethereum blocks.
#[derive(Debug)]
pub struct BatchBlockExecutionOutput {
/// Bundle state with reverts.
pub bundle: BundleState,
/// The collection of receipts.
/// Outer vector stores receipts for each block sequentially.
/// The inner vector stores receipts ordered by transaction number.
///
/// If receipt is None it means it is pruned.
pub receipts: Receipts,
/// The collection of EIP-7685 requests.
/// Outer vector stores requests for each block sequentially.
/// The inner vector stores requests ordered by transaction number.
///
/// A transaction may have zero or more requests, so the length of the inner vector is not
/// guaranteed to be the same as the number of transactions.
pub requests: Vec<Requests>,
/// First block of bundle state.
pub first_block: BlockNumber,
}
impl BatchBlockExecutionOutput {
/// Create Bundle State.
pub fn new(
bundle: BundleState,
receipts: Receipts,
requests: Vec<Requests>,
first_block: BlockNumber,
) -> Self {
Self { bundle, receipts, requests, first_block }
}
}
/// A helper type for ethereum block inputs that consists of a block and the total difficulty.
#[derive(Debug)]
pub struct BlockExecutionInput<'a, Block> {
@ -183,8 +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>,
// TODO: change to bundle state with receipts
Output = BatchBlockExecutionOutput,
Output = BundleStateWithReceipts,
Error = BlockExecutionError,
>;
@ -250,7 +216,7 @@ mod tests {
impl<DB> BatchExecutor<DB> for TestExecutor<DB> {
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = BatchBlockExecutionOutput;
type Output = BundleStateWithReceipts;
type Error = BlockExecutionError;
fn execute_and_verify_one(&mut self, _input: Self::Input<'_>) -> Result<(), Self::Error> {

View File

@ -1,14 +1,14 @@
//! A no operation block executor implementation.
use reth_execution_errors::BlockExecutionError;
use reth_execution_types::BundleStateWithReceipts;
use reth_primitives::{BlockNumber, BlockWithSenders, Receipt};
use reth_prune_types::PruneModes;
use reth_storage_errors::provider::ProviderError;
use revm_primitives::db::Database;
use crate::execute::{
BatchBlockExecutionOutput, BatchExecutor, BlockExecutionInput, BlockExecutionOutput,
BlockExecutorProvider, Executor,
BatchExecutor, BlockExecutionInput, BlockExecutionOutput, BlockExecutorProvider, Executor,
};
const UNAVAILABLE_FOR_NOOP: &str = "execution unavailable for noop";
@ -50,7 +50,7 @@ impl<DB> Executor<DB> for NoopBlockExecutorProvider {
impl<DB> BatchExecutor<DB> for NoopBlockExecutorProvider {
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = BatchBlockExecutionOutput;
type Output = BundleStateWithReceipts;
type Error = BlockExecutionError;
fn execute_and_verify_one(&mut self, _: Self::Input<'_>) -> Result<(), Self::Error> {

View File

@ -1,11 +1,11 @@
//! Helpers for testing.
use crate::execute::{
BatchBlockExecutionOutput, BatchExecutor, BlockExecutionInput, BlockExecutionOutput,
BlockExecutorProvider, Executor,
BatchExecutor, BlockExecutionInput, BlockExecutionOutput, BlockExecutorProvider, Executor,
};
use parking_lot::Mutex;
use reth_execution_errors::BlockExecutionError;
use reth_execution_types::BundleStateWithReceipts;
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<BatchBlockExecutionOutput>>>,
exec_results: Arc<Mutex<Vec<BundleStateWithReceipts>>>,
}
impl MockExecutorProvider {
/// Extend the mocked execution results
pub fn extend(&self, results: impl IntoIterator<Item = impl Into<BatchBlockExecutionOutput>>) {
pub fn extend(&self, results: impl IntoIterator<Item = impl Into<BundleStateWithReceipts>>) {
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 BatchBlockExecutionOutput { bundle, receipts, requests, first_block: _ } =
let BundleStateWithReceipts { 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 = BatchBlockExecutionOutput;
type Output = BundleStateWithReceipts;
type Error = BlockExecutionError;
fn execute_and_verify_one(&mut self, _: Self::Input<'_>) -> Result<(), Self::Error> {

View File

@ -3,8 +3,8 @@
use crate::{l1::ensure_create2_deployer, OptimismBlockExecutionError, OptimismEvmConfig};
use reth_evm::{
execute::{
BatchBlockExecutionOutput, BatchExecutor, BlockExecutionError, BlockExecutionInput,
BlockExecutionOutput, BlockExecutorProvider, BlockValidationError, Executor, ProviderError,
BatchExecutor, BlockExecutionError, BlockExecutionInput, BlockExecutionOutput,
BlockExecutorProvider, BlockValidationError, Executor, ProviderError,
},
ConfigureEvm,
};
@ -13,6 +13,7 @@ use reth_primitives::{
BlockNumber, BlockWithSenders, ChainSpec, Hardfork, Header, Receipt, Receipts, TxType,
Withdrawals, U256,
};
use reth_provider::BundleStateWithReceipts;
use reth_prune_types::PruneModes;
use reth_revm::{
batch::{BlockBatchRecord, BlockExecutorStats},
@ -396,7 +397,7 @@ where
DB: Database<Error = ProviderError>,
{
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = BatchBlockExecutionOutput;
type Output = BundleStateWithReceipts;
type Error = BlockExecutionError;
fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> {
@ -423,11 +424,11 @@ where
fn finalize(mut self) -> Self::Output {
self.stats.log_debug();
BatchBlockExecutionOutput::new(
BundleStateWithReceipts::new(
self.executor.state.take_bundle(),
self.batch_record.take_receipts(),
self.batch_record.take_requests(),
self.batch_record.first_block().unwrap_or_default(),
self.batch_record.take_requests(),
)
}

View File

@ -506,8 +506,12 @@ where
// and 4788 contract call
db.merge_transitions(BundleRetention::PlainState);
let bundle =
BundleStateWithReceipts::new(db.take_bundle(), vec![receipts].into(), block_number);
let bundle = BundleStateWithReceipts::new(
db.take_bundle(),
vec![receipts].into(),
block_number,
Vec::new(),
);
let receipts_root = bundle
.optimism_receipts_root_slow(
block_number,

View File

@ -220,8 +220,12 @@ impl PendingBlockEnv {
// merge all transitions into bundle state.
db.merge_transitions(BundleRetention::PlainState);
let bundle =
BundleStateWithReceipts::new(db.take_bundle(), vec![receipts].into(), block_number);
let bundle = BundleStateWithReceipts::new(
db.take_bundle(),
vec![receipts].into(),
block_number,
Vec::new(),
);
#[cfg(feature = "optimism")]
let receipts_root = bundle

View File

@ -3,7 +3,7 @@ use num_traits::Zero;
use reth_config::config::ExecutionConfig;
use reth_db::{static_file::HeaderMask, tables};
use reth_db_api::{cursor::DbCursorRO, database::Database, transaction::DbTx};
use reth_evm::execute::{BatchBlockExecutionOutput, BatchExecutor, BlockExecutorProvider};
use reth_evm::execute::{BatchExecutor, BlockExecutorProvider};
use reth_exex::{ExExManagerHandle, ExExNotification};
use reth_primitives::{
stage::{
@ -289,9 +289,9 @@ where
}
}
let time = Instant::now();
let BatchBlockExecutionOutput { bundle, receipts, requests: _, first_block } =
let BundleStateWithReceipts { bundle, receipts, requests, first_block } =
executor.finalize();
let state = BundleStateWithReceipts::new(bundle, receipts, first_block);
let state = BundleStateWithReceipts::new(bundle, receipts, first_block, requests);
let write_preparation_duration = time.elapsed();
// Check if we should send a [`ExExNotification`] to execution extensions.

View File

@ -199,6 +199,7 @@ pub fn insert_state<'a, 'b, DB: Database>(
contracts.into_iter().collect(),
Receipts::default(),
block,
Vec::new(),
);
bundle.write_to_storage(tx, None, OriginalValuesKnown::Yes)?;

View File

@ -288,7 +288,7 @@ mod tests {
state.merge_transitions(BundleRetention::Reverts);
BundleStateWithReceipts::new(state.take_bundle(), Receipts::default(), 1)
BundleStateWithReceipts::new(state.take_bundle(), Receipts::default(), 1, Vec::new())
.write_to_storage(provider.tx_ref(), None, OriginalValuesKnown::Yes)
.expect("Could not write bundle state to DB");
@ -386,7 +386,7 @@ mod tests {
)]));
state.merge_transitions(BundleRetention::Reverts);
BundleStateWithReceipts::new(state.take_bundle(), Receipts::default(), 2)
BundleStateWithReceipts::new(state.take_bundle(), Receipts::default(), 2, Vec::new())
.write_to_storage(provider.tx_ref(), None, OriginalValuesKnown::Yes)
.expect("Could not write bundle state to DB");
@ -450,7 +450,7 @@ mod tests {
},
)]));
init_state.merge_transitions(BundleRetention::Reverts);
BundleStateWithReceipts::new(init_state.take_bundle(), Receipts::default(), 0)
BundleStateWithReceipts::new(init_state.take_bundle(), Receipts::default(), 0, Vec::new())
.write_to_storage(provider.tx_ref(), None, OriginalValuesKnown::Yes)
.expect("Could not write init bundle state to DB");
@ -592,7 +592,7 @@ mod tests {
let bundle = state.take_bundle();
BundleStateWithReceipts::new(bundle, Receipts::default(), 1)
BundleStateWithReceipts::new(bundle, Receipts::default(), 1, Vec::new())
.write_to_storage(provider.tx_ref(), None, OriginalValuesKnown::Yes)
.expect("Could not write bundle state to DB");
@ -755,7 +755,7 @@ mod tests {
},
)]));
init_state.merge_transitions(BundleRetention::Reverts);
BundleStateWithReceipts::new(init_state.take_bundle(), Receipts::default(), 0)
BundleStateWithReceipts::new(init_state.take_bundle(), Receipts::default(), 0, Vec::new())
.write_to_storage(provider.tx_ref(), None, OriginalValuesKnown::Yes)
.expect("Could not write init bundle state to DB");
@ -800,7 +800,7 @@ mod tests {
// Commit block #1 changes to the database.
state.merge_transitions(BundleRetention::Reverts);
BundleStateWithReceipts::new(state.take_bundle(), Receipts::default(), 1)
BundleStateWithReceipts::new(state.take_bundle(), Receipts::default(), 1, Vec::new())
.write_to_storage(provider.tx_ref(), None, OriginalValuesKnown::Yes)
.expect("Could not write bundle state to DB");
@ -834,6 +834,7 @@ mod tests {
bundle: BundleState::default(),
receipts: vec![vec![Some(Receipt::default()); 2]; 7].into(),
first_block: 10,
requests: Vec::new(),
};
let mut this = base.clone();
@ -895,10 +896,15 @@ mod tests {
let assert_state_root = |state: &State<EmptyDB>, expected: &PreState, msg| {
assert_eq!(
BundleStateWithReceipts::new(state.bundle_state.clone(), Receipts::default(), 0)
.hash_state_slow()
.state_root(&tx)
.unwrap(),
BundleStateWithReceipts::new(
state.bundle_state.clone(),
Receipts::default(),
0,
Vec::new()
)
.hash_state_slow()
.state_root(&tx)
.unwrap(),
state_root(expected.clone().into_iter().map(|(address, (account, storage))| (
address,
(account, storage.into_iter())
@ -1045,6 +1051,7 @@ mod tests {
bundle: present_state,
receipts: vec![vec![Some(Receipt::default()); 2]; 1].into(),
first_block: 2,
requests: Vec::new(),
};
test.prepend_state(previous_state);

View File

@ -539,6 +539,7 @@ impl<TX: DbTxMut + DbTx> DatabaseProvider<TX> {
Vec::new(),
receipts.into(),
start_block_number,
Vec::new(),
))
}

View File

@ -166,6 +166,7 @@ fn block1(number: BlockNumber) -> (SealedBlockWithSenders, BundleStateWithReceip
})]]
.into(),
number,
Vec::new(),
);
let state_root = bundle_state_root(&bundle);
@ -225,6 +226,7 @@ fn block2(
})]]
.into(),
number,
Vec::new(),
);
let mut extended = prev_state.clone();
@ -294,6 +296,7 @@ fn block3(
})]]
.into(),
number,
Vec::new(),
);
let mut extended = prev_state.clone();
@ -384,6 +387,7 @@ fn block4(
})]]
.into(),
number,
Vec::new(),
);
let mut extended = prev_state.clone();
@ -469,6 +473,7 @@ fn block5(
})]]
.into(),
number,
Vec::new(),
);
let mut extended = prev_state.clone();