From 69daeed81d3da12026d22760d096958609f6f17a Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Tue, 2 Jul 2024 17:56:08 +0200 Subject: [PATCH 1/4] add `into_single_block` + test --- crates/exex/exex/src/backfill.rs | 239 ++++++++++++++++++++++++------- 1 file changed, 186 insertions(+), 53 deletions(-) diff --git a/crates/exex/exex/src/backfill.rs b/crates/exex/exex/src/backfill.rs index 0c7208a9c229..2fb28f3d2296 100644 --- a/crates/exex/exex/src/backfill.rs +++ b/crates/exex/exex/src/backfill.rs @@ -3,7 +3,7 @@ use reth_evm::execute::{BatchExecutor, BlockExecutionError, BlockExecutorProvide use reth_node_api::FullNodeComponents; use reth_primitives::{Block, BlockNumber}; use reth_primitives_traits::format_gas_throughput; -use reth_provider::{Chain, FullProvider, ProviderError, TransactionVariant}; +use reth_provider::{Chain, ExecutionOutcome, FullProvider, ProviderError, TransactionVariant}; use reth_prune_types::PruneModes; use reth_revm::database::StateProviderDatabase; use reth_stages_api::ExecutionStageThresholds; @@ -193,6 +193,39 @@ where let chain = Chain::new(blocks, executor.finalize(), None); Ok(chain) } + + /// Returns an iterator that executes each block in the range separately and yields the + /// resulting [`Block`] and [`ExecutionOutcome`]. + pub fn into_single_blocks( + &self, + ) -> impl Iterator> + '_ { + self.range.clone().map(|block_number| { + let td = self + .provider + .header_td_by_number(block_number)? + .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?; + + // Fetch the block with senders for execution. + let block_with_senders = self + .provider + .block_with_senders(block_number.into(), TransactionVariant::WithHash)? + .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?; + + // Configure the executor to use the previous block's state. + let mut executor = self.executor.batch_executor( + StateProviderDatabase::new( + self.provider.history_by_block_number(block_number.saturating_sub(1))?, + ), + ); + + trace!(target: "exex::backfill", number = block_number, txs = block_with_senders.block.body.len(), "Executing block"); + + executor + .execute_and_verify_one((&block_with_senders, td).into())?; + + Ok((block_with_senders.block, executor.finalize())) + }) + } } #[cfg(test)] @@ -200,33 +233,28 @@ mod tests { use crate::BackfillJobFactory; use eyre::OptionExt; use reth_blockchain_tree::noop::NoopBlockchainTree; - use reth_chainspec::{ChainSpecBuilder, EthereumHardfork, MAINNET}; + use reth_chainspec::{ChainSpec, ChainSpecBuilder, EthereumHardfork, MAINNET}; use reth_db_common::init::init_genesis; - use reth_evm::execute::{BatchExecutor, BlockExecutorProvider}; + use reth_evm::execute::{BlockExecutionInput, BlockExecutorProvider, Executor}; use reth_evm_ethereum::execute::EthExecutorProvider; use reth_primitives::{ - b256, constants::ETH_TO_WEI, public_key_to_address, Address, Block, Genesis, - GenesisAccount, Header, Transaction, TxEip2930, TxKind, U256, + b256, constants::ETH_TO_WEI, public_key_to_address, Address, Block, BlockWithSenders, + Genesis, GenesisAccount, Header, Requests, SealedBlockWithSenders, Transaction, TxEip2930, + TxKind, U256, }; use reth_provider::{ providers::BlockchainProvider, test_utils::create_test_provider_factory_with_chain_spec, - BlockWriter, LatestStateProviderRef, + BlockWriter, ExecutionOutcome, LatestStateProviderRef, ProviderFactory, }; use reth_revm::database::StateProviderDatabase; use reth_testing_utils::generators::{self, sign_tx_with_key_pair}; use secp256k1::Keypair; use std::sync::Arc; - #[tokio::test] - async fn test_backfill() -> eyre::Result<()> { - reth_tracing::init_test_tracing(); - - // Create a key pair for the sender - let key_pair = Keypair::new_global(&mut generators::rng()); - let address = public_key_to_address(key_pair.public_key()); - - // Create a chain spec with a genesis state that contains the sender - let chain_spec = Arc::new( + fn chain_spec(address: Address) -> Arc { + // Create a chain spec with a genesis state that contains the + // provided sender + Arc::new( ChainSpecBuilder::default() .chain(MAINNET.chain) .genesis(Genesis { @@ -239,16 +267,58 @@ mod tests { }) .paris_activated() .build(), - ); + ) + } - let executor = EthExecutorProvider::ethereum(chain_spec.clone()); - let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec.clone()); - init_genesis(provider_factory.clone())?; - let blockchain_db = BlockchainProvider::new( - provider_factory.clone(), - Arc::new(NoopBlockchainTree::default()), + fn execute_block_and_commit_to_database( + provider_factory: &ProviderFactory, + chain_spec: Arc, + block: &BlockWithSenders, + ) -> eyre::Result + where + DB: reth_db_api::database::Database, + { + let provider = provider_factory.provider()?; + + // Execute both blocks on top of the genesis state + let block_execution_output = EthExecutorProvider::ethereum(chain_spec) + .executor(StateProviderDatabase::new(LatestStateProviderRef::new( + provider.tx_ref(), + provider.static_file_provider().clone(), + ))) + .execute(BlockExecutionInput { block, total_difficulty: U256::ZERO })?; + + // Convert the block execution output to an execution outcome + let mut execution_outcome = ExecutionOutcome { + bundle: block_execution_output.state, + receipts: block_execution_output.receipts.into(), + first_block: block.number, + requests: vec![Requests(block_execution_output.requests)], + }; + execution_outcome.bundle.reverts.sort(); + + // Commit the block to the database + let provider_rw = provider_factory.provider_rw()?; + let block = block.clone().seal_slow(); + provider_rw.append_blocks_with_state( + vec![block], + execution_outcome.clone(), + Default::default(), + Default::default(), )?; + provider_rw.commit()?; + Ok(execution_outcome) + } + + fn blocks_and_execution_outcomes( + provider_factory: ProviderFactory, + chain_spec: Arc, + key_pair: Keypair, + ) -> eyre::Result> + where + DB: reth_db_api::database::Database, + { // First block has a transaction that transfers some ETH to zero address let block1 = Block { header: Header { @@ -279,52 +349,68 @@ mod tests { .with_recovered_senders() .ok_or_eyre("failed to recover senders")?; - // Second block has no state changes + // Second block has resend the same transaction with increased nonce let block2 = Block { header: Header { - parent_hash: block1.hash_slow(), + parent_hash: block1.header.hash_slow(), + receipts_root: b256!( + "d3a6acf9a244d78b33831df95d472c4128ea85bf079a1d41e32ed0b7d2244c9e" + ), difficulty: chain_spec.fork(EthereumHardfork::Paris).ttd().expect("Paris TTD"), number: 2, + gas_limit: 21000, + gas_used: 21000, ..Default::default() }, + body: vec![sign_tx_with_key_pair( + key_pair, + Transaction::Eip2930(TxEip2930 { + chain_id: chain_spec.chain.id(), + nonce: 1, + gas_limit: 21000, + gas_price: 1_500_000_000, + to: TxKind::Call(Address::ZERO), + value: U256::from(0.1 * ETH_TO_WEI as f64), + ..Default::default() + }), + )], ..Default::default() } .with_recovered_senders() .ok_or_eyre("failed to recover senders")?; - let provider = provider_factory.provider()?; - // Execute only the first block on top of genesis state - let mut outcome_single = EthExecutorProvider::ethereum(chain_spec.clone()) - .batch_executor(StateProviderDatabase::new(LatestStateProviderRef::new( - provider.tx_ref(), - provider.static_file_provider().clone(), - ))) - .execute_and_verify_batch([(&block1, U256::ZERO).into()])?; - outcome_single.bundle.reverts.sort(); - // Execute both blocks on top of the genesis state - let outcome_batch = EthExecutorProvider::ethereum(chain_spec) - .batch_executor(StateProviderDatabase::new(LatestStateProviderRef::new( - provider.tx_ref(), - provider.static_file_provider().clone(), - ))) - .execute_and_verify_batch([ - (&block1, U256::ZERO).into(), - (&block2, U256::ZERO).into(), - ])?; - drop(provider); + let outcome1 = + execute_block_and_commit_to_database(&provider_factory, chain_spec.clone(), &block1)?; + let outcome2 = + execute_block_and_commit_to_database(&provider_factory, chain_spec, &block2)?; let block1 = block1.seal_slow(); let block2 = block2.seal_slow(); - // Update the state with the execution results of both blocks - let provider_rw = provider_factory.provider_rw()?; - provider_rw.append_blocks_with_state( - vec![block1.clone(), block2], - outcome_batch, - Default::default(), - Default::default(), + Ok(vec![(block1, outcome1), (block2, outcome2)]) + } + + #[test] + fn test_backfill() -> eyre::Result<()> { + reth_tracing::init_test_tracing(); + + // Create a key pair for the sender + let key_pair = Keypair::new_global(&mut generators::rng()); + let address = public_key_to_address(key_pair.public_key()); + + let chain_spec = chain_spec(address); + + let executor = EthExecutorProvider::ethereum(chain_spec.clone()); + let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec.clone()); + init_genesis(provider_factory.clone())?; + let blockchain_db = BlockchainProvider::new( + provider_factory.clone(), + Arc::new(NoopBlockchainTree::default()), )?; - provider_rw.commit()?; + + let blocks_and_execution_outcomes = + blocks_and_execution_outcomes(provider_factory, chain_spec, key_pair)?; + let (block1, outcome_single) = blocks_and_execution_outcomes.first().unwrap().clone(); // Backfill the first block let factory = BackfillJobFactory::new(executor, blockchain_db); @@ -341,4 +427,51 @@ mod tests { Ok(()) } + + #[test] + fn test_into_single_blocks() -> eyre::Result<()> { + reth_tracing::init_test_tracing(); + + // Create a key pair for the sender + let key_pair = Keypair::new_global(&mut generators::rng()); + let address = public_key_to_address(key_pair.public_key()); + + let chain_spec = chain_spec(address); + + let executor = EthExecutorProvider::ethereum(chain_spec.clone()); + let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec.clone()); + init_genesis(provider_factory.clone())?; + let blockchain_db = BlockchainProvider::new( + provider_factory.clone(), + Arc::new(NoopBlockchainTree::default()), + )?; + + let blocks_and_execution_outcomes = + blocks_and_execution_outcomes(provider_factory, chain_spec, key_pair)?; + + // Backfill the first block + let factory = BackfillJobFactory::new(executor, blockchain_db); + let job = factory.backfill(1..=1); + let block_execution_it = job.into_single_blocks(); + + // Assert that the backfill job only produces a single block + let blocks_and_outcomes = block_execution_it.collect::>(); + assert_eq!(blocks_and_outcomes.len(), 1); + + // Assert that the backfill job single block iterator produces the same output for each + // block + for (i, res) in blocks_and_outcomes.into_iter().enumerate() { + let (block, mut outcome) = res?; + outcome.bundle.reverts.sort(); + + let sealed_block_with_senders = blocks_and_execution_outcomes[i].0.clone(); + let expected_block = sealed_block_with_senders.unseal().block; + let expected_outcome = &blocks_and_execution_outcomes[i].1; + + assert_eq!(block, expected_block); + assert_eq!(outcome, expected_outcome.clone()); + } + + Ok(()) + } } From 1f5aa6725f7daaa0f94e2eecf3900f7752d54c0d Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Tue, 2 Jul 2024 17:56:27 +0200 Subject: [PATCH 2/4] fix documentation for `EthBlockExecutor::execute` --- crates/ethereum/evm/src/execute.rs | 4 +--- crates/exex/exex/src/backfill.rs | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index b4da027f88f1..199b25448f6f 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -363,13 +363,11 @@ where type Output = BlockExecutionOutput; type Error = BlockExecutionError; - /// Executes the block and commits the state changes. + /// Executes the block and commits the changes to the internal state. /// /// Returns the receipts of the transactions in the block. /// /// Returns an error if the block could not be executed or failed verification. - /// - /// State changes are committed to the database. fn execute(mut self, input: Self::Input<'_>) -> Result { let BlockExecutionInput { block, total_difficulty } = input; let EthExecuteOutput { receipts, requests, gas_used } = diff --git a/crates/exex/exex/src/backfill.rs b/crates/exex/exex/src/backfill.rs index 2fb28f3d2296..1bad901413aa 100644 --- a/crates/exex/exex/src/backfill.rs +++ b/crates/exex/exex/src/backfill.rs @@ -280,7 +280,7 @@ mod tests { { let provider = provider_factory.provider()?; - // Execute both blocks on top of the genesis state + // Execute the block to produce a block execution output let block_execution_output = EthExecutorProvider::ethereum(chain_spec) .executor(StateProviderDatabase::new(LatestStateProviderRef::new( provider.tx_ref(), @@ -297,7 +297,7 @@ mod tests { }; execution_outcome.bundle.reverts.sort(); - // Commit the block to the database + // Commit the block's execution outcome to the database let provider_rw = provider_factory.provider_rw()?; let block = block.clone().seal_slow(); provider_rw.append_blocks_with_state( @@ -349,7 +349,7 @@ mod tests { .with_recovered_senders() .ok_or_eyre("failed to recover senders")?; - // Second block has resend the same transaction with increased nonce + // Second block resends the same transaction with increased nonce let block2 = Block { header: Header { parent_hash: block1.header.hash_slow(), @@ -458,7 +458,7 @@ mod tests { let blocks_and_outcomes = block_execution_it.collect::>(); assert_eq!(blocks_and_outcomes.len(), 1); - // Assert that the backfill job single block iterator produces the same output for each + // Assert that the backfill job single block iterator produces the expected output for each // block for (i, res) in blocks_and_outcomes.into_iter().enumerate() { let (block, mut outcome) = res?; From e1d07f36beb820ba79372d46af9fb5f7fe074e78 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Wed, 3 Jul 2024 15:45:12 +0200 Subject: [PATCH 3/4] fix comments --- crates/evm/src/execute.rs | 2 +- crates/exex/exex/src/backfill.rs | 176 ++++++++++++++++++++----------- 2 files changed, 114 insertions(+), 64 deletions(-) diff --git a/crates/evm/src/execute.rs b/crates/evm/src/execute.rs index 586fed53d997..9d3fd0a5e824 100644 --- a/crates/evm/src/execute.rs +++ b/crates/evm/src/execute.rs @@ -101,7 +101,7 @@ pub trait BatchExecutor { /// Contains the state changes, transaction receipts, and total gas used in the block. /// /// TODO(mattsse): combine with `ExecutionOutcome` -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub struct BlockExecutionOutput { /// The changed state of the block after execution. pub state: BundleState, diff --git a/crates/exex/exex/src/backfill.rs b/crates/exex/exex/src/backfill.rs index 1bad901413aa..6fb7a3c8fe1e 100644 --- a/crates/exex/exex/src/backfill.rs +++ b/crates/exex/exex/src/backfill.rs @@ -1,9 +1,11 @@ use reth_db_api::database::Database; -use reth_evm::execute::{BatchExecutor, BlockExecutionError, BlockExecutorProvider}; +use reth_evm::execute::{ + BatchExecutor, BlockExecutionError, BlockExecutionOutput, BlockExecutorProvider, Executor, +}; use reth_node_api::FullNodeComponents; -use reth_primitives::{Block, BlockNumber}; +use reth_primitives::{Block, BlockNumber, BlockWithSenders, Receipt}; use reth_primitives_traits::format_gas_throughput; -use reth_provider::{Chain, ExecutionOutcome, FullProvider, ProviderError, TransactionVariant}; +use reth_provider::{Chain, FullProvider, ProviderError, TransactionVariant}; use reth_prune_types::PruneModes; use reth_revm::database::StateProviderDatabase; use reth_stages_api::ExecutionStageThresholds; @@ -193,54 +195,93 @@ where let chain = Chain::new(blocks, executor.finalize(), None); Ok(chain) } +} - /// Returns an iterator that executes each block in the range separately and yields the - /// resulting [`Block`] and [`ExecutionOutcome`]. - pub fn into_single_blocks( - &self, - ) -> impl Iterator> + '_ { - self.range.clone().map(|block_number| { - let td = self - .provider - .header_td_by_number(block_number)? - .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?; +impl From> for SingleBlockBackfillJob { + fn from(value: BackfillJob) -> Self { + Self { + executor: value.executor, + provider: value.provider, + range: value.range, + _db: PhantomData, + } + } +} - // Fetch the block with senders for execution. - let block_with_senders = self - .provider - .block_with_senders(block_number.into(), TransactionVariant::WithHash)? - .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?; +/// Single block Backfill job started for a specific range. +/// +/// It implements [`Iterator`] which executes a block each time the +/// iterator is advanced and yields ([`BlockWithSenders`], [`BlockExecutionOutput`]) +#[derive(Debug)] +pub struct SingleBlockBackfillJob { + executor: E, + provider: P, + range: RangeInclusive, + _db: PhantomData, +} - // Configure the executor to use the previous block's state. - let mut executor = self.executor.batch_executor( - StateProviderDatabase::new( - self.provider.history_by_block_number(block_number.saturating_sub(1))?, - ), - ); +impl Iterator for SingleBlockBackfillJob +where + E: BlockExecutorProvider, + DB: Database, + P: FullProvider, +{ + type Item = Result<(BlockWithSenders, BlockExecutionOutput), BlockExecutionError>; + + fn next(&mut self) -> Option { + self.range.next().map(|block_number| self.execute_block(block_number)) + } +} + +impl SingleBlockBackfillJob +where + E: BlockExecutorProvider, + DB: Database, + P: FullProvider, +{ + fn execute_block( + &self, + block_number: u64, + ) -> Result<(BlockWithSenders, BlockExecutionOutput), BlockExecutionError> { + let td = self + .provider + .header_td_by_number(block_number)? + .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?; + + // Fetch the block with senders for execution. + let block_with_senders = self + .provider + .block_with_senders(block_number.into(), TransactionVariant::WithHash)? + .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?; + + // Configure the executor to use the previous block's state. + let executor = self.executor.executor(StateProviderDatabase::new( + self.provider.history_by_block_number(block_number.saturating_sub(1))?, + )); - trace!(target: "exex::backfill", number = block_number, txs = block_with_senders.block.body.len(), "Executing block"); + trace!(target: "exex::backfill", number = block_number, txs = block_with_senders.block.body.len(), "Executing block"); - executor - .execute_and_verify_one((&block_with_senders, td).into())?; + let block_execution_output = executor.execute((&block_with_senders, td).into())?; - Ok((block_with_senders.block, executor.finalize())) - }) + Ok((block_with_senders, block_execution_output)) } } #[cfg(test)] mod tests { - use crate::BackfillJobFactory; + use crate::{BackfillJobFactory, SingleBlockBackfillJob}; use eyre::OptionExt; use reth_blockchain_tree::noop::NoopBlockchainTree; use reth_chainspec::{ChainSpec, ChainSpecBuilder, EthereumHardfork, MAINNET}; use reth_db_common::init::init_genesis; - use reth_evm::execute::{BlockExecutionInput, BlockExecutorProvider, Executor}; + use reth_evm::execute::{ + BlockExecutionInput, BlockExecutionOutput, BlockExecutorProvider, Executor, + }; use reth_evm_ethereum::execute::EthExecutorProvider; use reth_primitives::{ b256, constants::ETH_TO_WEI, public_key_to_address, Address, Block, BlockWithSenders, - Genesis, GenesisAccount, Header, Requests, SealedBlockWithSenders, Transaction, TxEip2930, - TxKind, U256, + Genesis, GenesisAccount, Header, Receipt, Requests, SealedBlockWithSenders, Transaction, + TxEip2930, TxKind, U256, }; use reth_provider::{ providers::BlockchainProvider, test_utils::create_test_provider_factory_with_chain_spec, @@ -251,6 +292,18 @@ mod tests { use secp256k1::Keypair; use std::sync::Arc; + fn to_execution_outcome( + block_number: u64, + block_execution_output: &BlockExecutionOutput, + ) -> ExecutionOutcome { + ExecutionOutcome { + bundle: block_execution_output.state.clone(), + receipts: block_execution_output.receipts.clone().into(), + first_block: block_number, + requests: vec![Requests(block_execution_output.requests.clone())], + } + } + fn chain_spec(address: Address) -> Arc { // Create a chain spec with a genesis state that contains the // provided sender @@ -274,48 +327,43 @@ mod tests { provider_factory: &ProviderFactory, chain_spec: Arc, block: &BlockWithSenders, - ) -> eyre::Result + ) -> eyre::Result> where DB: reth_db_api::database::Database, { let provider = provider_factory.provider()?; // Execute the block to produce a block execution output - let block_execution_output = EthExecutorProvider::ethereum(chain_spec) + let mut block_execution_output = EthExecutorProvider::ethereum(chain_spec) .executor(StateProviderDatabase::new(LatestStateProviderRef::new( provider.tx_ref(), provider.static_file_provider().clone(), ))) .execute(BlockExecutionInput { block, total_difficulty: U256::ZERO })?; + block_execution_output.state.reverts.sort(); - // Convert the block execution output to an execution outcome - let mut execution_outcome = ExecutionOutcome { - bundle: block_execution_output.state, - receipts: block_execution_output.receipts.into(), - first_block: block.number, - requests: vec![Requests(block_execution_output.requests)], - }; - execution_outcome.bundle.reverts.sort(); + // Convert the block execution output to an execution outcome for committing to the database + let execution_outcome = to_execution_outcome(block.number, &block_execution_output); // Commit the block's execution outcome to the database let provider_rw = provider_factory.provider_rw()?; let block = block.clone().seal_slow(); provider_rw.append_blocks_with_state( vec![block], - execution_outcome.clone(), + execution_outcome, Default::default(), Default::default(), )?; provider_rw.commit()?; - Ok(execution_outcome) + Ok(block_execution_output) } - fn blocks_and_execution_outcomes( + fn blocks_and_execution_outputs( provider_factory: ProviderFactory, chain_spec: Arc, key_pair: Keypair, - ) -> eyre::Result> + ) -> eyre::Result)>> where DB: reth_db_api::database::Database, { @@ -379,15 +427,15 @@ mod tests { .with_recovered_senders() .ok_or_eyre("failed to recover senders")?; - let outcome1 = + let block_output1 = execute_block_and_commit_to_database(&provider_factory, chain_spec.clone(), &block1)?; - let outcome2 = + let block_output2 = execute_block_and_commit_to_database(&provider_factory, chain_spec, &block2)?; let block1 = block1.seal_slow(); let block2 = block2.seal_slow(); - Ok(vec![(block1, outcome1), (block2, outcome2)]) + Ok(vec![(block1, block_output1), (block2, block_output2)]) } #[test] @@ -408,9 +456,10 @@ mod tests { Arc::new(NoopBlockchainTree::default()), )?; - let blocks_and_execution_outcomes = - blocks_and_execution_outcomes(provider_factory, chain_spec, key_pair)?; - let (block1, outcome_single) = blocks_and_execution_outcomes.first().unwrap().clone(); + let blocks_and_execution_outputs = + blocks_and_execution_outputs(provider_factory, chain_spec, key_pair)?; + let (block, block_execution_output) = blocks_and_execution_outputs.first().unwrap(); + let execution_outcome = to_execution_outcome(block.number, block_execution_output); // Backfill the first block let factory = BackfillJobFactory::new(executor, blockchain_db); @@ -422,14 +471,14 @@ mod tests { assert_eq!(chains.len(), 1); let mut chain = chains.into_iter().next().unwrap(); chain.execution_outcome_mut().bundle.reverts.sort(); - assert_eq!(chain.blocks(), &[(1, block1)].into()); - assert_eq!(chain.execution_outcome(), &outcome_single); + assert_eq!(chain.blocks(), &[(1, block.clone())].into()); + assert_eq!(chain.execution_outcome(), &execution_outcome); Ok(()) } #[test] - fn test_into_single_blocks() -> eyre::Result<()> { + fn test_single_block_backfill() -> eyre::Result<()> { reth_tracing::init_test_tracing(); // Create a key pair for the sender @@ -447,12 +496,13 @@ mod tests { )?; let blocks_and_execution_outcomes = - blocks_and_execution_outcomes(provider_factory, chain_spec, key_pair)?; + blocks_and_execution_outputs(provider_factory, chain_spec, key_pair)?; // Backfill the first block let factory = BackfillJobFactory::new(executor, blockchain_db); let job = factory.backfill(1..=1); - let block_execution_it = job.into_single_blocks(); + let single_job: SingleBlockBackfillJob<_, _, _> = job.into(); + let block_execution_it = single_job.into_iter(); // Assert that the backfill job only produces a single block let blocks_and_outcomes = block_execution_it.collect::>(); @@ -461,15 +511,15 @@ mod tests { // Assert that the backfill job single block iterator produces the expected output for each // block for (i, res) in blocks_and_outcomes.into_iter().enumerate() { - let (block, mut outcome) = res?; - outcome.bundle.reverts.sort(); + let (block, mut execution_output) = res?; + execution_output.state.reverts.sort(); let sealed_block_with_senders = blocks_and_execution_outcomes[i].0.clone(); - let expected_block = sealed_block_with_senders.unseal().block; - let expected_outcome = &blocks_and_execution_outcomes[i].1; + let expected_block = sealed_block_with_senders.unseal(); + let expected_output = &blocks_and_execution_outcomes[i].1; assert_eq!(block, expected_block); - assert_eq!(outcome, expected_outcome.clone()); + assert_eq!(&execution_output, expected_output); } Ok(()) From f24c950ab7520aaca9615d58de1fa4afab7786ee Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Wed, 3 Jul 2024 19:20:07 +0200 Subject: [PATCH 4/4] add `into_single_blocks` --- crates/exex/exex/src/backfill.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/exex/exex/src/backfill.rs b/crates/exex/exex/src/backfill.rs index 6fb7a3c8fe1e..0b5895643d7b 100644 --- a/crates/exex/exex/src/backfill.rs +++ b/crates/exex/exex/src/backfill.rs @@ -197,6 +197,13 @@ where } } +impl BackfillJob { + /// Converts the backfill job into a single block backfill job. + pub fn into_single_blocks(self) -> SingleBlockBackfillJob { + self.into() + } +} + impl From> for SingleBlockBackfillJob { fn from(value: BackfillJob) -> Self { Self { @@ -269,7 +276,7 @@ where #[cfg(test)] mod tests { - use crate::{BackfillJobFactory, SingleBlockBackfillJob}; + use crate::BackfillJobFactory; use eyre::OptionExt; use reth_blockchain_tree::noop::NoopBlockchainTree; use reth_chainspec::{ChainSpec, ChainSpecBuilder, EthereumHardfork, MAINNET}; @@ -501,7 +508,7 @@ mod tests { // Backfill the first block let factory = BackfillJobFactory::new(executor, blockchain_db); let job = factory.backfill(1..=1); - let single_job: SingleBlockBackfillJob<_, _, _> = job.into(); + let single_job = job.into_single_blocks(); let block_execution_it = single_job.into_iter(); // Assert that the backfill job only produces a single block