mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
refactor: Execution Stage owns Executor (#1568)
Co-authored-by: Roman Krasiuk <rokrassyuk@gmail.com> Co-authored-by: Oliver Nordbjerg <hi@notbjerg.me>
This commit is contained in:
committed by
GitHub
parent
71bc1451af
commit
4285186dbd
@ -27,6 +27,7 @@ use reth_staged_sync::{
|
||||
use reth_stages::{
|
||||
prelude::*,
|
||||
stages::{ExecutionStage, SenderRecoveryStage, TotalDifficultyStage},
|
||||
DefaultDB,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use tracing::{debug, info};
|
||||
@ -156,9 +157,11 @@ impl ImportCommand {
|
||||
.set(SenderRecoveryStage {
|
||||
commit_threshold: config.stages.sender_recovery.commit_threshold,
|
||||
})
|
||||
.set(ExecutionStage {
|
||||
chain_spec: self.chain.clone(),
|
||||
commit_threshold: config.stages.execution.commit_threshold,
|
||||
.set({
|
||||
let mut stage: ExecutionStage<'_, DefaultDB<'_>> =
|
||||
ExecutionStage::from(self.chain.clone());
|
||||
stage.commit_threshold = config.stages.execution.commit_threshold;
|
||||
stage
|
||||
}),
|
||||
)
|
||||
.with_max_block(0)
|
||||
|
||||
@ -7,8 +7,9 @@ use eyre::Result;
|
||||
use reth_db::{
|
||||
cursor::DbCursorRO, database::Database, table::TableImporter, tables, transaction::DbTx,
|
||||
};
|
||||
use reth_primitives::MAINNET;
|
||||
use reth_provider::Transaction;
|
||||
use reth_stages::{stages::ExecutionStage, Stage, StageId, UnwindInput};
|
||||
use reth_stages::{stages::ExecutionStage, DefaultDB, Stage, StageId, UnwindInput};
|
||||
use std::ops::DerefMut;
|
||||
use tracing::info;
|
||||
|
||||
@ -96,7 +97,7 @@ async fn unwind_and_copy<DB: Database>(
|
||||
output_db: &reth_db::mdbx::Env<reth_db::mdbx::WriteMap>,
|
||||
) -> eyre::Result<()> {
|
||||
let mut unwind_tx = Transaction::new(db_tool.db)?;
|
||||
let mut exec_stage = ExecutionStage::default();
|
||||
let mut exec_stage: ExecutionStage<'_, DefaultDB<'_>> = ExecutionStage::from(MAINNET.clone());
|
||||
|
||||
exec_stage
|
||||
.unwind(
|
||||
@ -125,7 +126,7 @@ async fn dry_run(
|
||||
info!(target: "reth::cli", "Executing stage. [dry-run]");
|
||||
|
||||
let mut tx = Transaction::new(&output_db)?;
|
||||
let mut exec_stage = ExecutionStage::default();
|
||||
let mut exec_stage: ExecutionStage<'_, DefaultDB<'_>> = ExecutionStage::from(MAINNET.clone());
|
||||
|
||||
exec_stage
|
||||
.execute(
|
||||
|
||||
@ -50,6 +50,7 @@ use reth_staged_sync::{
|
||||
use reth_stages::{
|
||||
prelude::*,
|
||||
stages::{ExecutionStage, SenderRecoveryStage, TotalDifficultyStage, FINISH},
|
||||
DefaultDB,
|
||||
};
|
||||
use reth_tasks::TaskExecutor;
|
||||
use std::{net::SocketAddr, path::PathBuf, sync::Arc};
|
||||
@ -448,9 +449,11 @@ impl Command {
|
||||
.set(SenderRecoveryStage {
|
||||
commit_threshold: stage_conf.sender_recovery.commit_threshold,
|
||||
})
|
||||
.set(ExecutionStage {
|
||||
chain_spec: self.chain.clone(),
|
||||
commit_threshold: stage_conf.execution.commit_threshold,
|
||||
.set({
|
||||
let mut stage: ExecutionStage<'_, DefaultDB<'_>> =
|
||||
ExecutionStage::from(self.chain.clone());
|
||||
stage.commit_threshold = stage_conf.execution.commit_threshold;
|
||||
stage
|
||||
}),
|
||||
)
|
||||
.build();
|
||||
|
||||
@ -17,7 +17,7 @@ use reth_staged_sync::{
|
||||
};
|
||||
use reth_stages::{
|
||||
stages::{BodyStage, ExecutionStage, SenderRecoveryStage},
|
||||
ExecInput, Stage, StageId, UnwindInput,
|
||||
DefaultDB, ExecInput, Stage, StageId, UnwindInput,
|
||||
};
|
||||
use std::{net::SocketAddr, sync::Arc};
|
||||
use tracing::*;
|
||||
@ -171,8 +171,8 @@ impl Command {
|
||||
stage.execute(&mut tx, input).await?;
|
||||
}
|
||||
StageEnum::Execution => {
|
||||
let mut stage =
|
||||
ExecutionStage { chain_spec: self.chain.clone(), commit_threshold: num_blocks };
|
||||
let mut stage = ExecutionStage::<DefaultDB<'_>>::from(self.chain.clone());
|
||||
stage.commit_threshold = num_blocks;
|
||||
if !self.skip_unwind {
|
||||
stage.unwind(&mut tx, unwind).await?;
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ use reth_primitives::{
|
||||
};
|
||||
use reth_provider::Transaction;
|
||||
use reth_rlp::Decodable;
|
||||
use reth_stages::{stages::ExecutionStage, ExecInput, Stage, StageId};
|
||||
use reth_stages::{stages::ExecutionStage, DefaultDB, ExecInput, Stage, StageId};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::OsStr,
|
||||
@ -193,7 +193,7 @@ pub async fn run_test(path: PathBuf) -> eyre::Result<TestOutcome> {
|
||||
|
||||
// Initialize the execution stage
|
||||
// Hardcode the chain_id to Ethereum 1.
|
||||
let mut stage = ExecutionStage::new(chain_spec, 1000);
|
||||
let mut stage = ExecutionStage::<DefaultDB<'_>>::from(chain_spec);
|
||||
|
||||
// Call execution stage
|
||||
let input = ExecInput {
|
||||
|
||||
@ -21,26 +21,47 @@ use revm::{
|
||||
primitives::{Account as RevmAccount, AccountInfo, Bytecode, ResultAndState},
|
||||
EVM,
|
||||
};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
/// Main block executor
|
||||
pub struct Executor<'a, DB>
|
||||
where
|
||||
DB: StateProvider,
|
||||
{
|
||||
chain_spec: &'a ChainSpec,
|
||||
/// The configured chain-spec
|
||||
pub chain_spec: Arc<ChainSpec>,
|
||||
evm: EVM<&'a mut SubState<DB>>,
|
||||
stack: InspectorStack,
|
||||
}
|
||||
|
||||
impl<'a, DB> From<ChainSpec> for Executor<'a, DB>
|
||||
where
|
||||
DB: StateProvider,
|
||||
{
|
||||
/// Instantiates a new executor from the chainspec. Must call
|
||||
/// `with_db` to set the database before executing.
|
||||
fn from(chain_spec: ChainSpec) -> Self {
|
||||
let evm = EVM::new();
|
||||
Executor {
|
||||
chain_spec: Arc::new(chain_spec),
|
||||
evm,
|
||||
stack: InspectorStack::new(InspectorStackConfig::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, DB> Executor<'a, DB>
|
||||
where
|
||||
DB: StateProvider,
|
||||
{
|
||||
/// Creates a new executor from the given chain spec and database.
|
||||
pub fn new(chain_spec: &'a ChainSpec, db: &'a mut SubState<DB>) -> Self {
|
||||
pub fn new(chain_spec: Arc<ChainSpec>, db: &'a mut SubState<DB>) -> Self {
|
||||
let mut evm = EVM::new();
|
||||
evm.database(db);
|
||||
|
||||
Executor { chain_spec, evm, stack: InspectorStack::new(InspectorStackConfig::default()) }
|
||||
}
|
||||
|
||||
@ -50,10 +71,21 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
fn db(&mut self) -> &mut SubState<DB> {
|
||||
/// Gives a reference to the database
|
||||
pub fn db(&mut self) -> &mut SubState<DB> {
|
||||
self.evm.db().expect("db to not be moved")
|
||||
}
|
||||
|
||||
/// Overrides the database
|
||||
pub fn with_db<OtherDB: StateProvider>(
|
||||
&self,
|
||||
db: &'a mut SubState<OtherDB>,
|
||||
) -> Executor<'a, OtherDB> {
|
||||
let mut evm = EVM::new();
|
||||
evm.database(db);
|
||||
Executor { chain_spec: self.chain_spec.clone(), evm, stack: self.stack.clone() }
|
||||
}
|
||||
|
||||
fn recover_senders(
|
||||
&self,
|
||||
body: &[TransactionSigned],
|
||||
@ -75,7 +107,7 @@ where
|
||||
fill_cfg_and_block_env(
|
||||
&mut self.evm.env.cfg,
|
||||
&mut self.evm.env.block,
|
||||
self.chain_spec,
|
||||
&self.chain_spec,
|
||||
header,
|
||||
total_difficulty,
|
||||
);
|
||||
@ -341,6 +373,30 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute and verify block
|
||||
pub fn execute_and_verify_receipt(
|
||||
&mut self,
|
||||
block: &Block,
|
||||
total_difficulty: U256,
|
||||
senders: Option<Vec<Address>>,
|
||||
) -> Result<ExecutionResult, Error> {
|
||||
let execution_result = self.execute(block, total_difficulty, senders)?;
|
||||
|
||||
let receipts_iter =
|
||||
execution_result.tx_changesets.iter().map(|changeset| &changeset.receipt);
|
||||
|
||||
if self.chain_spec.fork(Hardfork::Byzantium).active_at_block(block.header.number) {
|
||||
verify_receipt(block.header.receipts_root, block.header.logs_bloom, receipts_iter)?;
|
||||
}
|
||||
|
||||
// TODO Before Byzantium, receipts contained state root that would mean that expensive
|
||||
// operation as hashing that is needed for state root got calculated in every
|
||||
// transaction This was replaced with is_success flag.
|
||||
// See more about EIP here: https://eips.ethereum.org/EIPS/eip-658
|
||||
|
||||
Ok(execution_result)
|
||||
}
|
||||
|
||||
/// Runs a single transaction in the configured environment and proceeds
|
||||
/// to return the result and state diff (without applying it).
|
||||
///
|
||||
@ -464,30 +520,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute and verify block
|
||||
pub fn execute_and_verify_receipt<DB: StateProvider>(
|
||||
block: &Block,
|
||||
total_difficulty: U256,
|
||||
senders: Option<Vec<Address>>,
|
||||
chain_spec: &ChainSpec,
|
||||
db: &mut SubState<DB>,
|
||||
) -> Result<ExecutionResult, Error> {
|
||||
let execution_result = execute(block, total_difficulty, senders, chain_spec, db)?;
|
||||
|
||||
let receipts_iter = execution_result.tx_changesets.iter().map(|changeset| &changeset.receipt);
|
||||
|
||||
if chain_spec.fork(Hardfork::Byzantium).active_at_block(block.header.number) {
|
||||
verify_receipt(block.header.receipts_root, block.header.logs_bloom, receipts_iter)?;
|
||||
}
|
||||
|
||||
// TODO Before Byzantium, receipts contained state root that would mean that expensive operation
|
||||
// as hashing that is needed for state root got calculated in every transaction
|
||||
// This was replaced with is_success flag.
|
||||
// See more about EIP here: https://eips.ethereum.org/EIPS/eip-658
|
||||
|
||||
Ok(execution_result)
|
||||
}
|
||||
|
||||
/// Verify receipts
|
||||
pub fn verify_receipt<'a>(
|
||||
expected_receipts_root: H256,
|
||||
@ -511,22 +543,6 @@ pub fn verify_receipt<'a>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify block. Execute all transaction and compare results.
|
||||
/// Returns ChangeSet on transaction granularity.
|
||||
/// NOTE: If block reward is still active (Before Paris/Merge) we would return
|
||||
/// additional TransactionStatechangeset for account that receives the reward.
|
||||
pub fn execute<DB: StateProvider>(
|
||||
block: &Block,
|
||||
total_difficulty: U256,
|
||||
senders: Option<Vec<Address>>,
|
||||
chain_spec: &ChainSpec,
|
||||
db: &mut SubState<DB>,
|
||||
) -> Result<ExecutionResult, Error> {
|
||||
let mut executor = Executor::new(chain_spec, db)
|
||||
.with_stack(InspectorStack::new(InspectorStackConfig::default()));
|
||||
executor.execute(block, total_difficulty, senders)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -640,13 +656,13 @@ mod tests {
|
||||
);
|
||||
|
||||
// spec at berlin fork
|
||||
let chain_spec = ChainSpecBuilder::mainnet().berlin_activated().build();
|
||||
let chain_spec = Arc::new(ChainSpecBuilder::mainnet().berlin_activated().build());
|
||||
|
||||
let mut db = SubState::new(State::new(db));
|
||||
|
||||
// execute chain and verify receipts
|
||||
let out =
|
||||
execute_and_verify_receipt(&block, U256::ZERO, None, &chain_spec, &mut db).unwrap();
|
||||
let mut executor = Executor::new(chain_spec, &mut db);
|
||||
let out = executor.execute_and_verify_receipt(&block, U256::ZERO, None).unwrap();
|
||||
|
||||
assert_eq!(out.tx_changesets.len(), 1, "Should executed one transaction");
|
||||
|
||||
@ -765,21 +781,23 @@ mod tests {
|
||||
beneficiary_balance += i;
|
||||
}
|
||||
|
||||
let chain_spec = ChainSpecBuilder::from(&*MAINNET)
|
||||
.homestead_activated()
|
||||
.with_fork(Hardfork::Dao, ForkCondition::Block(1))
|
||||
.build();
|
||||
let chain_spec = Arc::new(
|
||||
ChainSpecBuilder::from(&*MAINNET)
|
||||
.homestead_activated()
|
||||
.with_fork(Hardfork::Dao, ForkCondition::Block(1))
|
||||
.build(),
|
||||
);
|
||||
|
||||
let mut db = SubState::new(State::new(db));
|
||||
// execute chain and verify receipts
|
||||
let out = execute_and_verify_receipt(
|
||||
&Block { header, body: vec![], ommers: vec![], withdrawals: None },
|
||||
U256::ZERO,
|
||||
None,
|
||||
&chain_spec,
|
||||
&mut db,
|
||||
)
|
||||
.unwrap();
|
||||
let mut executor = Executor::new(chain_spec, &mut db);
|
||||
let out = executor
|
||||
.execute_and_verify_receipt(
|
||||
&Block { header, body: vec![], ommers: vec![], withdrawals: None },
|
||||
U256::ZERO,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(out.tx_changesets.len(), 0, "No tx");
|
||||
|
||||
// Check if cache is set
|
||||
@ -858,13 +876,13 @@ mod tests {
|
||||
);
|
||||
|
||||
// spec at berlin fork
|
||||
let chain_spec = ChainSpecBuilder::mainnet().berlin_activated().build();
|
||||
let chain_spec = Arc::new(ChainSpecBuilder::mainnet().berlin_activated().build());
|
||||
|
||||
let mut db = SubState::new(State::new(db));
|
||||
|
||||
// execute chain and verify receipts
|
||||
let out =
|
||||
execute_and_verify_receipt(&block, U256::ZERO, None, &chain_spec, &mut db).unwrap();
|
||||
let mut executor = Executor::new(chain_spec, &mut db);
|
||||
let out = executor.execute_and_verify_receipt(&block, U256::ZERO, None).unwrap();
|
||||
|
||||
assert_eq!(out.tx_changesets.len(), 1, "Should executed one transaction");
|
||||
|
||||
@ -907,17 +925,17 @@ mod tests {
|
||||
Address::from_str("c94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap();
|
||||
|
||||
// spec at shanghai fork
|
||||
let chain_spec = ChainSpecBuilder::mainnet().shanghai_activated().build();
|
||||
let chain_spec = Arc::new(ChainSpecBuilder::mainnet().shanghai_activated().build());
|
||||
|
||||
let mut db = SubState::new(State::new(StateProviderTest::default()));
|
||||
|
||||
// execute chain and verify receipts
|
||||
let out =
|
||||
execute_and_verify_receipt(&block, U256::ZERO, None, &chain_spec, &mut db).unwrap();
|
||||
let mut executor = Executor::new(chain_spec, &mut db);
|
||||
let out = executor.execute_and_verify_receipt(&block, U256::ZERO, None).unwrap();
|
||||
assert_eq!(out.tx_changesets.len(), 0, "No tx");
|
||||
|
||||
let withdrawal_sum = withdrawals.iter().fold(U256::ZERO, |sum, w| sum + w.amount_wei());
|
||||
let beneficiary_account = db.accounts.get(&withdrawal_beneficiary).unwrap();
|
||||
let beneficiary_account = executor.db().accounts.get(&withdrawal_beneficiary).unwrap();
|
||||
assert_eq!(beneficiary_account.info.balance, withdrawal_sum);
|
||||
assert_eq!(beneficiary_account.info.nonce, 0);
|
||||
assert_eq!(beneficiary_account.account_state, AccountState::StorageCleared);
|
||||
@ -931,8 +949,7 @@ mod tests {
|
||||
);
|
||||
|
||||
// Execute same block again
|
||||
let out =
|
||||
execute_and_verify_receipt(&block, U256::ZERO, None, &chain_spec, &mut db).unwrap();
|
||||
let out = executor.execute_and_verify_receipt(&block, U256::ZERO, None).unwrap();
|
||||
assert_eq!(out.tx_changesets.len(), 0, "No tx");
|
||||
|
||||
assert_eq!(out.block_changesets.len(), 1);
|
||||
|
||||
@ -10,7 +10,7 @@ use revm::{
|
||||
/// - Block: Hook on block execution
|
||||
/// - BlockWithIndex: Hook on block execution transaction index
|
||||
/// - Transaction: Hook on a specific transaction hash
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Clone)]
|
||||
pub enum Hook {
|
||||
#[default]
|
||||
/// No hook.
|
||||
@ -23,7 +23,7 @@ pub enum Hook {
|
||||
All,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Clone)]
|
||||
/// An inspector that calls multiple inspectors in sequence.
|
||||
///
|
||||
/// If a call to an inspector returns a value other than [InstructionResult::Continue] (or
|
||||
|
||||
@ -12,3 +12,6 @@ pub mod database;
|
||||
|
||||
/// reexport for convenience
|
||||
pub use reth_revm_primitives::*;
|
||||
|
||||
/// Re-export everything
|
||||
pub use revm;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use crate::{message::EngineApiMessageVersion, EngineApiError, EngineApiMessage, EngineApiResult};
|
||||
use futures::StreamExt;
|
||||
use reth_executor::executor;
|
||||
use reth_interfaces::consensus::ForkchoiceState;
|
||||
use reth_primitives::{
|
||||
proofs::{self, EMPTY_LIST_HASH},
|
||||
@ -17,6 +16,7 @@ use reth_rpc_types::engine::{
|
||||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
task::{ready, Context, Poll},
|
||||
};
|
||||
use tokio::sync::{mpsc, oneshot, watch};
|
||||
@ -37,7 +37,7 @@ const MAX_PAYLOAD_BODIES_LIMIT: u64 = 1024;
|
||||
pub struct EngineApi<Client> {
|
||||
client: Client,
|
||||
/// Consensus configuration
|
||||
chain_spec: ChainSpec,
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
message_rx: UnboundedReceiverStream<EngineApiMessage>,
|
||||
forkchoice_state_tx: watch::Sender<ForkchoiceState>,
|
||||
// TODO: Placeholder for storing future blocks. Make cache bounded. Use lru
|
||||
@ -57,7 +57,7 @@ impl<Client: HeaderProvider + BlockProvider + StateProviderFactory + EvmEnvProvi
|
||||
) -> Self {
|
||||
Self {
|
||||
client,
|
||||
chain_spec,
|
||||
chain_spec: Arc::new(chain_spec),
|
||||
message_rx: UnboundedReceiverStream::new(message_rx),
|
||||
forkchoice_state_tx,
|
||||
}
|
||||
@ -304,13 +304,10 @@ impl<Client: HeaderProvider + BlockProvider + StateProviderFactory + EvmEnvProvi
|
||||
|
||||
let state_provider = self.client.latest()?;
|
||||
let total_difficulty = parent_td + block.header.difficulty;
|
||||
match executor::execute_and_verify_receipt(
|
||||
&block.unseal(),
|
||||
total_difficulty,
|
||||
None,
|
||||
&self.chain_spec,
|
||||
&mut SubState::new(State::new(&state_provider)),
|
||||
) {
|
||||
|
||||
let mut db = SubState::new(State::new(&state_provider));
|
||||
let mut executor = reth_executor::executor::Executor::new(self.chain_spec.clone(), &mut db);
|
||||
match executor.execute_and_verify_receipt(&block.unseal(), total_difficulty, None) {
|
||||
Ok(_) => Ok(PayloadStatus::new(PayloadStatusEnum::Valid, block_hash)),
|
||||
Err(err) => Ok(PayloadStatus::new(
|
||||
PayloadStatusEnum::Invalid { validation_error: err.to_string() },
|
||||
@ -443,7 +440,7 @@ mod tests {
|
||||
};
|
||||
|
||||
fn setup_engine_api() -> (EngineApiTestHandle, EngineApi<Arc<MockEthProvider>>) {
|
||||
let chain_spec = MAINNET.clone();
|
||||
let chain_spec = Arc::new(MAINNET.clone());
|
||||
let client = Arc::new(MockEthProvider::default());
|
||||
let (msg_tx, msg_rx) = unbounded_channel();
|
||||
let (forkchoice_state_tx, forkchoice_state_rx) = watch::channel(ForkchoiceState::default());
|
||||
@ -458,7 +455,7 @@ mod tests {
|
||||
}
|
||||
|
||||
struct EngineApiTestHandle {
|
||||
chain_spec: ChainSpec,
|
||||
chain_spec: Arc<ChainSpec>,
|
||||
client: Arc<MockEthProvider>,
|
||||
msg_tx: UnboundedSender<EngineApiMessage>,
|
||||
forkchoice_state_rx: WatchReceiver<ForkchoiceState>,
|
||||
|
||||
@ -56,6 +56,11 @@ mod stage;
|
||||
mod trie;
|
||||
mod util;
|
||||
|
||||
/// The real database type we use in Reth using MDBX.
|
||||
pub type DefaultDB<'a> = LatestStateProviderRef<'a, 'a, Tx<'a, RW, WriteMap>>;
|
||||
use reth_db::mdbx::{tx::Tx, WriteMap, RW};
|
||||
use reth_provider::LatestStateProviderRef;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[cfg(any(test, feature = "test-utils"))]
|
||||
pub mod test_utils;
|
||||
|
||||
@ -170,7 +170,7 @@ impl<DB: Database> StageSet<DB> for ExecutionStages {
|
||||
fn builder(self) -> StageSetBuilder<DB> {
|
||||
StageSetBuilder::default()
|
||||
.add_stage(SenderRecoveryStage::default())
|
||||
.add_stage(ExecutionStage { chain_spec: self.chain_spec, ..Default::default() })
|
||||
.add_stage(ExecutionStage::<crate::DefaultDB<'_>>::from(self.chain_spec))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
exec_or_return, ExecAction, ExecInput, ExecOutput, Stage, StageError, StageId, UnwindInput,
|
||||
UnwindOutput,
|
||||
exec_or_return, DefaultDB, ExecAction, ExecInput, ExecOutput, Stage, StageError, StageId,
|
||||
UnwindInput, UnwindOutput,
|
||||
};
|
||||
use reth_db::{
|
||||
cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO},
|
||||
@ -9,12 +9,11 @@ use reth_db::{
|
||||
tables,
|
||||
transaction::{DbTx, DbTxMut},
|
||||
};
|
||||
use reth_executor::execution_result::AccountChangeSet;
|
||||
use reth_executor::{execution_result::AccountChangeSet, executor::Executor};
|
||||
use reth_interfaces::provider::ProviderError;
|
||||
use reth_primitives::{Address, Block, ChainSpec, Hardfork, StorageEntry, H256, MAINNET, U256};
|
||||
use reth_provider::{LatestStateProviderRef, Transaction};
|
||||
use reth_primitives::{Address, Block, ChainSpec, Hardfork, StorageEntry, H256, U256};
|
||||
use reth_provider::{LatestStateProviderRef, StateProvider, Transaction};
|
||||
use reth_revm::database::{State, SubState};
|
||||
use std::fmt::Debug;
|
||||
use tracing::*;
|
||||
|
||||
/// The [`StageId`] of the execution stage.
|
||||
@ -48,24 +47,35 @@ pub const EXECUTION: StageId = StageId("Execution");
|
||||
/// - [tables::AccountHistory] to remove change set and apply old values to
|
||||
/// - [tables::PlainAccountState] [tables::StorageHistory] to remove change set and apply old values
|
||||
/// to [tables::PlainStorageState]
|
||||
#[derive(Debug)]
|
||||
pub struct ExecutionStage {
|
||||
/// Executor configuration.
|
||||
pub chain_spec: ChainSpec,
|
||||
// false positive, we cannot derive it if !DB: Debug.
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct ExecutionStage<'a, DB = DefaultDB<'a>>
|
||||
where
|
||||
DB: StateProvider,
|
||||
{
|
||||
/// The stage's internal executor
|
||||
pub executor: Executor<'a, DB>,
|
||||
/// Commit threshold
|
||||
pub commit_threshold: u64,
|
||||
}
|
||||
|
||||
impl Default for ExecutionStage {
|
||||
fn default() -> Self {
|
||||
Self { chain_spec: MAINNET.clone(), commit_threshold: 1_000 }
|
||||
impl<'a, DB: StateProvider> From<Executor<'a, DB>> for ExecutionStage<'a, DB> {
|
||||
fn from(executor: Executor<'a, DB>) -> Self {
|
||||
Self { executor, commit_threshold: 1_000 }
|
||||
}
|
||||
}
|
||||
|
||||
impl ExecutionStage {
|
||||
impl<'a, DB: StateProvider> From<ChainSpec> for ExecutionStage<'a, DB> {
|
||||
fn from(chain_spec: ChainSpec) -> Self {
|
||||
let executor = Executor::from(chain_spec);
|
||||
Self::from(executor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: StateProvider> ExecutionStage<'a, S> {
|
||||
/// Execute the stage.
|
||||
pub fn execute_inner<DB: Database>(
|
||||
&self,
|
||||
&mut self,
|
||||
tx: &mut Transaction<'_, DB>,
|
||||
input: ExecInput,
|
||||
) -> Result<ExecOutput, StageError> {
|
||||
@ -87,7 +97,6 @@ impl ExecutionStage {
|
||||
let mut tx_cursor = tx.cursor_read::<tables::Transactions>()?;
|
||||
// Skip sender recovery and load signer from database.
|
||||
let mut tx_sender = tx.cursor_read::<tables::TxSenders>()?;
|
||||
|
||||
// Get block headers and bodies
|
||||
let block_batch = headers_cursor
|
||||
.walk_range(start_block..=end_block)?
|
||||
@ -106,6 +115,7 @@ impl ExecutionStage {
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
// Create state provider with cached state
|
||||
|
||||
let mut state_provider = SubState::new(State::new(LatestStateProviderRef::new(&**tx)));
|
||||
|
||||
// Fetch transactions, execute them and generate results
|
||||
@ -143,14 +153,15 @@ impl ExecutionStage {
|
||||
|
||||
trace!(target: "sync::stages::execution", number = block_number, txs = transactions.len(), "Executing block");
|
||||
|
||||
let changeset = reth_executor::executor::execute_and_verify_receipt(
|
||||
&Block { header, body: transactions, ommers, withdrawals },
|
||||
td,
|
||||
Some(signers),
|
||||
&self.chain_spec,
|
||||
&mut state_provider,
|
||||
)
|
||||
.map_err(|error| StageError::ExecutionError { block: block_number, error })?;
|
||||
// Configure the executor to use the current state.
|
||||
let mut executor = self.executor.with_db(&mut state_provider);
|
||||
let changeset = executor
|
||||
.execute_and_verify_receipt(
|
||||
&Block { header, body: transactions, ommers, withdrawals },
|
||||
td,
|
||||
Some(signers),
|
||||
)
|
||||
.map_err(|error| StageError::ExecutionError { block: block_number, error })?;
|
||||
block_change_patches.push((changeset, block_number));
|
||||
}
|
||||
|
||||
@ -160,8 +171,11 @@ impl ExecutionStage {
|
||||
|
||||
// apply changes to plain database.
|
||||
for (results, block_number) in block_change_patches.into_iter() {
|
||||
let spurious_dragon_active =
|
||||
self.chain_spec.fork(Hardfork::SpuriousDragon).active_at_block(block_number);
|
||||
let spurious_dragon_active = self
|
||||
.executor
|
||||
.chain_spec
|
||||
.fork(Hardfork::SpuriousDragon)
|
||||
.active_at_block(block_number);
|
||||
// insert state change set
|
||||
for result in results.tx_changesets.into_iter() {
|
||||
for (address, account_change_set) in result.changeset.into_iter() {
|
||||
@ -266,15 +280,15 @@ impl ExecutionStage {
|
||||
}
|
||||
}
|
||||
|
||||
impl ExecutionStage {
|
||||
impl<'a, DB: StateProvider> ExecutionStage<'a, DB> {
|
||||
/// Create new execution stage with specified config.
|
||||
pub fn new(chain_spec: ChainSpec, commit_threshold: u64) -> Self {
|
||||
Self { chain_spec, commit_threshold }
|
||||
pub fn new(executor: Executor<'a, DB>, commit_threshold: u64) -> Self {
|
||||
Self { executor, commit_threshold }
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<DB: Database> Stage<DB> for ExecutionStage {
|
||||
impl<State: StateProvider, DB: Database> Stage<DB> for ExecutionStage<'_, State> {
|
||||
/// Return the id of the stage
|
||||
fn id(&self) -> StageId {
|
||||
EXECUTION
|
||||
@ -392,20 +406,18 @@ impl<DB: Database> Stage<DB> for ExecutionStage {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::test_utils::{TestTransaction, PREV_STAGE_ID};
|
||||
|
||||
use super::*;
|
||||
use crate::test_utils::{TestTransaction, PREV_STAGE_ID};
|
||||
use reth_db::{
|
||||
mdbx::{test_utils::create_test_db, EnvKind, WriteMap},
|
||||
models::AccountBeforeTx,
|
||||
};
|
||||
use reth_primitives::{
|
||||
hex_literal::hex, keccak256, Account, ChainSpecBuilder, SealedBlock, H160, U256,
|
||||
hex_literal::hex, keccak256, Account, ChainSpecBuilder, SealedBlock, H160, MAINNET, U256,
|
||||
};
|
||||
use reth_provider::insert_canonical_block;
|
||||
use reth_rlp::Decodable;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
#[tokio::test]
|
||||
async fn sanity_execution_of_block() {
|
||||
@ -448,11 +460,8 @@ mod tests {
|
||||
db_tx.put::<tables::Bytecodes>(code_hash, code.to_vec()).unwrap();
|
||||
tx.commit().unwrap();
|
||||
|
||||
// execute
|
||||
let mut execution_stage = ExecutionStage {
|
||||
chain_spec: ChainSpecBuilder::mainnet().berlin_activated().build(),
|
||||
..Default::default()
|
||||
};
|
||||
let chain_spec = ChainSpecBuilder::mainnet().berlin_activated().build();
|
||||
let mut execution_stage = ExecutionStage::<DefaultDB<'_>>::from(chain_spec);
|
||||
let output = execution_stage.execute(&mut tx, input).await.unwrap();
|
||||
tx.commit().unwrap();
|
||||
assert_eq!(output, ExecOutput { stage_progress: 1, done: true });
|
||||
@ -536,14 +545,12 @@ mod tests {
|
||||
tx.commit().unwrap();
|
||||
|
||||
// execute
|
||||
let mut execution_stage = ExecutionStage {
|
||||
chain_spec: ChainSpecBuilder::mainnet().berlin_activated().build(),
|
||||
..Default::default()
|
||||
};
|
||||
let chain_spec = ChainSpecBuilder::mainnet().berlin_activated().build();
|
||||
let mut execution_stage = ExecutionStage::<DefaultDB<'_>>::from(chain_spec);
|
||||
let _ = execution_stage.execute(&mut tx, input).await.unwrap();
|
||||
tx.commit().unwrap();
|
||||
|
||||
let o = ExecutionStage::default()
|
||||
let o = ExecutionStage::<DefaultDB<'_>>::from(MAINNET.clone())
|
||||
.unwind(&mut tx, UnwindInput { stage_progress: 1, unwind_to: 0, bad_block: None })
|
||||
.await
|
||||
.unwrap();
|
||||
@ -624,10 +631,8 @@ mod tests {
|
||||
tx.commit().unwrap();
|
||||
|
||||
// execute
|
||||
let mut execution_stage = ExecutionStage {
|
||||
chain_spec: ChainSpecBuilder::mainnet().berlin_activated().build(),
|
||||
..Default::default()
|
||||
};
|
||||
let chain_spec = ChainSpecBuilder::mainnet().berlin_activated().build();
|
||||
let mut execution_stage = ExecutionStage::<DefaultDB<'_>>::from(chain_spec);
|
||||
let _ = execution_stage.execute(&mut tx, input).await.unwrap();
|
||||
tx.commit().unwrap();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user