mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: re-use BlockExecutionStrategy in payload building (#14609)
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -6720,8 +6720,6 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"metrics",
|
"metrics",
|
||||||
"reth-chainspec",
|
|
||||||
"reth-evm",
|
|
||||||
"reth-metrics",
|
"reth-metrics",
|
||||||
"reth-payload-builder",
|
"reth-payload-builder",
|
||||||
"reth-payload-builder-primitives",
|
"reth-payload-builder-primitives",
|
||||||
@ -6731,7 +6729,6 @@ dependencies = [
|
|||||||
"reth-provider",
|
"reth-provider",
|
||||||
"reth-revm",
|
"reth-revm",
|
||||||
"reth-tasks",
|
"reth-tasks",
|
||||||
"revm",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@ -7776,7 +7773,6 @@ dependencies = [
|
|||||||
"alloy-genesis",
|
"alloy-genesis",
|
||||||
"alloy-primitives",
|
"alloy-primitives",
|
||||||
"alloy-sol-types",
|
"alloy-sol-types",
|
||||||
"derive_more 2.0.1",
|
|
||||||
"reth-chainspec",
|
"reth-chainspec",
|
||||||
"reth-ethereum-forks",
|
"reth-ethereum-forks",
|
||||||
"reth-evm",
|
"reth-evm",
|
||||||
|
|||||||
@ -21,8 +21,8 @@ use reth_chainspec::EthereumHardforks;
|
|||||||
/// - Definition: [Yellow Paper][yp] (page 15, 11.3)
|
/// - Definition: [Yellow Paper][yp] (page 15, 11.3)
|
||||||
///
|
///
|
||||||
/// [yp]: https://ethereum.github.io/yellowpaper/paper.pdf
|
/// [yp]: https://ethereum.github.io/yellowpaper/paper.pdf
|
||||||
pub fn base_block_reward<ChainSpec: EthereumHardforks>(
|
pub fn base_block_reward(
|
||||||
chain_spec: &ChainSpec,
|
chain_spec: impl EthereumHardforks,
|
||||||
block_number: BlockNumber,
|
block_number: BlockNumber,
|
||||||
) -> Option<u128> {
|
) -> Option<u128> {
|
||||||
if chain_spec.is_paris_active_at_block(block_number).is_some_and(|active| active) {
|
if chain_spec.is_paris_active_at_block(block_number).is_some_and(|active| active) {
|
||||||
|
|||||||
@ -29,8 +29,6 @@ alloy-evm.workspace = true
|
|||||||
alloy-sol-types.workspace = true
|
alloy-sol-types.workspace = true
|
||||||
alloy-consensus.workspace = true
|
alloy-consensus.workspace = true
|
||||||
|
|
||||||
derive_more.workspace = true
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
reth-testing-utils.workspace = true
|
reth-testing-utils.workspace = true
|
||||||
reth-evm = { workspace = true, features = ["test-utils"] }
|
reth-evm = { workspace = true, features = ["test-utils"] }
|
||||||
@ -58,5 +56,4 @@ std = [
|
|||||||
"alloy-evm/std",
|
"alloy-evm/std",
|
||||||
"reth-execution-types/std",
|
"reth-execution-types/std",
|
||||||
"reth-evm/std",
|
"reth-evm/std",
|
||||||
"derive_more/std",
|
|
||||||
]
|
]
|
||||||
|
|||||||
@ -5,8 +5,9 @@ use crate::{
|
|||||||
EthEvmConfig,
|
EthEvmConfig,
|
||||||
};
|
};
|
||||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||||
use alloy_consensus::{BlockHeader, Transaction};
|
use alloy_consensus::{Header, Transaction};
|
||||||
use alloy_eips::{eip6110, eip7685::Requests};
|
use alloy_eips::{eip4895::Withdrawals, eip6110, eip7685::Requests};
|
||||||
|
use alloy_primitives::{Address, B256};
|
||||||
use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks, MAINNET};
|
use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks, MAINNET};
|
||||||
use reth_evm::{
|
use reth_evm::{
|
||||||
execute::{
|
execute::{
|
||||||
@ -75,43 +76,83 @@ where
|
|||||||
DB: Database,
|
DB: Database,
|
||||||
{
|
{
|
||||||
let evm = self.evm_config.evm_for_block(db, block.header());
|
let evm = self.evm_config.evm_for_block(db, block.header());
|
||||||
EthExecutionStrategy::new(evm, block.sealed_block(), self)
|
EthExecutionStrategy::new(evm, block.sealed_block(), &self.chain_spec, &self.evm_config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Input for block execution.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct EthBlockExecutionInput<'a> {
|
||||||
|
/// Block number.
|
||||||
|
pub number: u64,
|
||||||
|
/// Block timestamp.
|
||||||
|
pub timestamp: u64,
|
||||||
|
/// Parent block hash.
|
||||||
|
pub parent_hash: B256,
|
||||||
|
/// Block gas limit.
|
||||||
|
pub gas_limit: u64,
|
||||||
|
/// Parent beacon block root.
|
||||||
|
pub parent_beacon_block_root: Option<B256>,
|
||||||
|
/// Block beneficiary.
|
||||||
|
pub beneficiary: Address,
|
||||||
|
/// Block ommers
|
||||||
|
pub ommers: &'a [Header],
|
||||||
|
/// Block withdrawals.
|
||||||
|
pub withdrawals: Option<&'a Withdrawals>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a SealedBlock> for EthBlockExecutionInput<'a> {
|
||||||
|
fn from(block: &'a SealedBlock) -> Self {
|
||||||
|
Self {
|
||||||
|
number: block.header().number,
|
||||||
|
timestamp: block.header().timestamp,
|
||||||
|
parent_hash: block.header().parent_hash,
|
||||||
|
gas_limit: block.header().gas_limit,
|
||||||
|
parent_beacon_block_root: block.header().parent_beacon_block_root,
|
||||||
|
beneficiary: block.header().beneficiary,
|
||||||
|
ommers: &block.body().ommers,
|
||||||
|
withdrawals: block.body().withdrawals.as_ref(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Block execution strategy for Ethereum.
|
/// Block execution strategy for Ethereum.
|
||||||
#[derive(Debug, derive_more::Deref)]
|
#[derive(Debug)]
|
||||||
pub struct EthExecutionStrategy<'a, Evm, EvmConfig> {
|
pub struct EthExecutionStrategy<'a, Evm, EvmConfig> {
|
||||||
/// Reference to the parent factory providing access to [`ChainSpec`].
|
/// Reference to the [`ChainSpec`].
|
||||||
#[deref]
|
chain_spec: &'a ChainSpec,
|
||||||
factory: &'a EthExecutionStrategyFactory<EvmConfig>,
|
/// How to configure the EVM.
|
||||||
|
evm_config: EvmConfig,
|
||||||
|
|
||||||
/// Block being executed.
|
/// Input for block execution.
|
||||||
block: &'a SealedBlock,
|
input: EthBlockExecutionInput<'a>,
|
||||||
/// The EVM used by strategy.
|
/// The EVM used by strategy.
|
||||||
evm: Evm,
|
evm: Evm,
|
||||||
|
/// Utility to call system smart contracts.
|
||||||
|
system_caller: SystemCaller<&'a ChainSpec>,
|
||||||
|
|
||||||
/// Receipts of executed transactions.
|
/// Receipts of executed transactions.
|
||||||
receipts: Vec<Receipt>,
|
receipts: Vec<Receipt>,
|
||||||
/// Total gas used by transactions in this block.
|
/// Total gas used by transactions in this block.
|
||||||
gas_used: u64,
|
gas_used: u64,
|
||||||
/// Utility to call system smart contracts.
|
|
||||||
system_caller: SystemCaller<&'a ChainSpec>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Evm, EvmConfig> EthExecutionStrategy<'a, Evm, EvmConfig> {
|
impl<'a, Evm, EvmConfig> EthExecutionStrategy<'a, Evm, EvmConfig> {
|
||||||
/// Creates a new [`EthExecutionStrategy`]
|
/// Creates a new [`EthExecutionStrategy`]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
evm: Evm,
|
evm: Evm,
|
||||||
block: &'a SealedBlock,
|
input: impl Into<EthBlockExecutionInput<'a>>,
|
||||||
factory: &'a EthExecutionStrategyFactory<EvmConfig>,
|
chain_spec: &'a ChainSpec,
|
||||||
|
evm_config: EvmConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
evm,
|
evm,
|
||||||
factory,
|
chain_spec,
|
||||||
block,
|
evm_config,
|
||||||
|
input: input.into(),
|
||||||
receipts: Vec::new(),
|
receipts: Vec::new(),
|
||||||
gas_used: 0,
|
gas_used: 0,
|
||||||
system_caller: SystemCaller::new(&factory.chain_spec),
|
system_caller: SystemCaller::new(chain_spec),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,9 +169,12 @@ where
|
|||||||
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error> {
|
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error> {
|
||||||
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
||||||
let state_clear_flag =
|
let state_clear_flag =
|
||||||
self.chain_spec.is_spurious_dragon_active_at_block(self.block.number());
|
self.chain_spec.is_spurious_dragon_active_at_block(self.input.number);
|
||||||
self.evm.db_mut().set_state_clear_flag(state_clear_flag);
|
self.evm.db_mut().set_state_clear_flag(state_clear_flag);
|
||||||
self.system_caller.apply_pre_execution_changes(self.block.header(), &mut self.evm)?;
|
self.system_caller
|
||||||
|
.apply_blockhashes_contract_call(self.input.parent_hash, &mut self.evm)?;
|
||||||
|
self.system_caller
|
||||||
|
.apply_beacon_root_contract_call(self.input.parent_beacon_block_root, &mut self.evm)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -138,10 +182,10 @@ where
|
|||||||
fn execute_transaction(
|
fn execute_transaction(
|
||||||
&mut self,
|
&mut self,
|
||||||
tx: Recovered<&TransactionSigned>,
|
tx: Recovered<&TransactionSigned>,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<u64, Self::Error> {
|
||||||
// The sum of the transaction's gas limit, Tg, and the gas utilized in this block prior,
|
// The sum of the transaction's gas limit, Tg, and the gas utilized in this block prior,
|
||||||
// must be no greater than the block's gasLimit.
|
// must be no greater than the block's gasLimit.
|
||||||
let block_available_gas = self.block.gas_limit() - self.gas_used;
|
let block_available_gas = self.input.gas_limit - self.gas_used;
|
||||||
if tx.gas_limit() > block_available_gas {
|
if tx.gas_limit() > block_available_gas {
|
||||||
return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
|
return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
|
||||||
transaction_gas_limit: tx.gas_limit(),
|
transaction_gas_limit: tx.gas_limit(),
|
||||||
@ -161,8 +205,10 @@ where
|
|||||||
let ResultAndState { result, state } = result_and_state;
|
let ResultAndState { result, state } = result_and_state;
|
||||||
self.evm.db_mut().commit(state);
|
self.evm.db_mut().commit(state);
|
||||||
|
|
||||||
|
let gas_used = result.gas_used();
|
||||||
|
|
||||||
// append gas used
|
// append gas used
|
||||||
self.gas_used += result.gas_used();
|
self.gas_used += gas_used;
|
||||||
|
|
||||||
// Push transaction changeset and calculate header bloom filter for receipt.
|
// Push transaction changeset and calculate header bloom filter for receipt.
|
||||||
self.receipts.push(Receipt {
|
self.receipts.push(Receipt {
|
||||||
@ -174,16 +220,16 @@ where
|
|||||||
logs: result.into_logs(),
|
logs: result.into_logs(),
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(gas_used)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_post_execution_changes(
|
fn apply_post_execution_changes(
|
||||||
mut self,
|
mut self,
|
||||||
) -> Result<BlockExecutionResult<Receipt>, Self::Error> {
|
) -> Result<BlockExecutionResult<Receipt>, Self::Error> {
|
||||||
let requests = if self.chain_spec.is_prague_active_at_timestamp(self.block.timestamp) {
|
let requests = if self.chain_spec.is_prague_active_at_timestamp(self.input.timestamp) {
|
||||||
// Collect all EIP-6110 deposits
|
// Collect all EIP-6110 deposits
|
||||||
let deposit_requests =
|
let deposit_requests =
|
||||||
crate::eip6110::parse_deposits_from_receipts(&self.chain_spec, &self.receipts)?;
|
crate::eip6110::parse_deposits_from_receipts(self.chain_spec, &self.receipts)?;
|
||||||
|
|
||||||
let mut requests = Requests::default();
|
let mut requests = Requests::default();
|
||||||
|
|
||||||
@ -197,10 +243,15 @@ where
|
|||||||
Requests::default()
|
Requests::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut balance_increments = post_block_balance_increments(&self.chain_spec, self.block);
|
let mut balance_increments = post_block_balance_increments(
|
||||||
|
self.chain_spec,
|
||||||
|
self.evm.block(),
|
||||||
|
self.input.ommers,
|
||||||
|
self.input.withdrawals,
|
||||||
|
);
|
||||||
|
|
||||||
// Irregular state change at Ethereum DAO hardfork
|
// Irregular state change at Ethereum DAO hardfork
|
||||||
if self.chain_spec.fork(EthereumHardfork::Dao).transitions_at_block(self.block.number()) {
|
if self.chain_spec.fork(EthereumHardfork::Dao).transitions_at_block(self.input.number) {
|
||||||
// drain balances from hardcoded addresses.
|
// drain balances from hardcoded addresses.
|
||||||
let drained_balance: u128 = self
|
let drained_balance: u128 = self
|
||||||
.evm
|
.evm
|
||||||
|
|||||||
@ -10,21 +10,20 @@
|
|||||||
#![allow(clippy::useless_let_if_seq)]
|
#![allow(clippy::useless_let_if_seq)]
|
||||||
|
|
||||||
use alloy_consensus::{BlockHeader, Header, Transaction, Typed2718, EMPTY_OMMER_ROOT_HASH};
|
use alloy_consensus::{BlockHeader, Header, Transaction, Typed2718, EMPTY_OMMER_ROOT_HASH};
|
||||||
use alloy_eips::{eip4844::DATA_GAS_PER_BLOB, eip6110, eip7685::Requests, merge::BEACON_NONCE};
|
use alloy_eips::{eip4844::DATA_GAS_PER_BLOB, merge::BEACON_NONCE};
|
||||||
use alloy_primitives::U256;
|
use alloy_primitives::U256;
|
||||||
use reth_basic_payload_builder::{
|
use reth_basic_payload_builder::{
|
||||||
commit_withdrawals, is_better_payload, BuildArguments, BuildOutcome, PayloadBuilder,
|
is_better_payload, BuildArguments, BuildOutcome, PayloadBuilder, PayloadConfig,
|
||||||
PayloadConfig,
|
|
||||||
};
|
};
|
||||||
use reth_chainspec::{ChainSpec, ChainSpecProvider, EthChainSpec, EthereumHardforks};
|
use reth_chainspec::{ChainSpec, ChainSpecProvider, EthChainSpec, EthereumHardforks};
|
||||||
use reth_errors::RethError;
|
use reth_errors::{BlockExecutionError, BlockValidationError};
|
||||||
use reth_ethereum_primitives::{Block, BlockBody, Receipt, TransactionSigned};
|
use reth_ethereum_primitives::{Block, BlockBody, TransactionSigned};
|
||||||
use reth_evm::{
|
use reth_evm::{execute::BlockExecutionStrategy, ConfigureEvm, NextBlockEnvAttributes};
|
||||||
system_calls::SystemCaller, ConfigureEvm, Evm, EvmEnv, EvmError, InvalidTxError,
|
use reth_evm_ethereum::{
|
||||||
NextBlockEnvAttributes,
|
execute::{EthBlockExecutionInput, EthExecutionStrategy},
|
||||||
|
EthEvmConfig,
|
||||||
};
|
};
|
||||||
use reth_evm_ethereum::{eip6110::parse_deposits_from_receipts, EthEvmConfig};
|
use reth_execution_types::{BlockExecutionResult, ExecutionOutcome};
|
||||||
use reth_execution_types::ExecutionOutcome;
|
|
||||||
use reth_payload_builder::{EthBuiltPayload, EthPayloadBuilderAttributes};
|
use reth_payload_builder::{EthBuiltPayload, EthPayloadBuilderAttributes};
|
||||||
use reth_payload_builder_primitives::PayloadBuilderError;
|
use reth_payload_builder_primitives::PayloadBuilderError;
|
||||||
use reth_payload_primitives::PayloadBuilderAttributes;
|
use reth_payload_primitives::PayloadBuilderAttributes;
|
||||||
@ -41,10 +40,7 @@ use reth_transaction_pool::{
|
|||||||
error::InvalidPoolTransactionError, BestTransactions, BestTransactionsAttributes,
|
error::InvalidPoolTransactionError, BestTransactions, BestTransactionsAttributes,
|
||||||
PoolTransaction, TransactionPool, ValidPoolTransaction,
|
PoolTransaction, TransactionPool, ValidPoolTransaction,
|
||||||
};
|
};
|
||||||
use revm::{
|
use revm::context_interface::Block as _;
|
||||||
context_interface::{result::ResultAndState, Block as _},
|
|
||||||
DatabaseCommit,
|
|
||||||
};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tracing::{debug, trace, warn};
|
use tracing::{debug, trace, warn};
|
||||||
|
|
||||||
@ -82,27 +78,6 @@ impl<Pool, Client, EvmConfig> EthereumPayloadBuilder<Pool, Client, EvmConfig> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Pool, Client, EvmConfig> EthereumPayloadBuilder<Pool, Client, EvmConfig>
|
|
||||||
where
|
|
||||||
EvmConfig: ConfigureEvm<Header = Header>,
|
|
||||||
{
|
|
||||||
/// Returns the configured [`EvmEnv`] for the targeted payload
|
|
||||||
/// (that has the `parent` as its parent).
|
|
||||||
fn evm_env(
|
|
||||||
&self,
|
|
||||||
config: &PayloadConfig<EthPayloadBuilderAttributes>,
|
|
||||||
parent: &Header,
|
|
||||||
) -> Result<EvmEnv<EvmConfig::Spec>, EvmConfig::Error> {
|
|
||||||
let next_attributes = NextBlockEnvAttributes {
|
|
||||||
timestamp: config.attributes.timestamp(),
|
|
||||||
suggested_fee_recipient: config.attributes.suggested_fee_recipient(),
|
|
||||||
prev_randao: config.attributes.prev_randao(),
|
|
||||||
gas_limit: self.builder_config.gas_limit(parent.gas_limit),
|
|
||||||
};
|
|
||||||
self.evm_config.next_evm_env(parent, next_attributes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default implementation of [PayloadBuilder] for unit type
|
// Default implementation of [PayloadBuilder] for unit type
|
||||||
impl<Pool, Client, EvmConfig> PayloadBuilder for EthereumPayloadBuilder<Pool, Client, EvmConfig>
|
impl<Pool, Client, EvmConfig> PayloadBuilder for EthereumPayloadBuilder<Pool, Client, EvmConfig>
|
||||||
where
|
where
|
||||||
@ -117,17 +92,12 @@ where
|
|||||||
&self,
|
&self,
|
||||||
args: BuildArguments<EthPayloadBuilderAttributes, EthBuiltPayload>,
|
args: BuildArguments<EthPayloadBuilderAttributes, EthBuiltPayload>,
|
||||||
) -> Result<BuildOutcome<EthBuiltPayload>, PayloadBuilderError> {
|
) -> Result<BuildOutcome<EthBuiltPayload>, PayloadBuilderError> {
|
||||||
let evm_env = self
|
|
||||||
.evm_env(&args.config, &args.config.parent_header)
|
|
||||||
.map_err(PayloadBuilderError::other)?;
|
|
||||||
|
|
||||||
default_ethereum_payload(
|
default_ethereum_payload(
|
||||||
self.evm_config.clone(),
|
self.evm_config.clone(),
|
||||||
self.client.clone(),
|
self.client.clone(),
|
||||||
self.pool.clone(),
|
self.pool.clone(),
|
||||||
self.builder_config.clone(),
|
self.builder_config.clone(),
|
||||||
args,
|
args,
|
||||||
evm_env,
|
|
||||||
|attributes| self.pool.best_transactions_with_attributes(attributes),
|
|attributes| self.pool.best_transactions_with_attributes(attributes),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -138,17 +108,12 @@ where
|
|||||||
) -> Result<EthBuiltPayload, PayloadBuilderError> {
|
) -> Result<EthBuiltPayload, PayloadBuilderError> {
|
||||||
let args = BuildArguments::new(Default::default(), config, Default::default(), None);
|
let args = BuildArguments::new(Default::default(), config, Default::default(), None);
|
||||||
|
|
||||||
let evm_env = self
|
|
||||||
.evm_env(&args.config, &args.config.parent_header)
|
|
||||||
.map_err(PayloadBuilderError::other)?;
|
|
||||||
|
|
||||||
default_ethereum_payload(
|
default_ethereum_payload(
|
||||||
self.evm_config.clone(),
|
self.evm_config.clone(),
|
||||||
self.client.clone(),
|
self.client.clone(),
|
||||||
self.pool.clone(),
|
self.pool.clone(),
|
||||||
self.builder_config.clone(),
|
self.builder_config.clone(),
|
||||||
args,
|
args,
|
||||||
evm_env,
|
|
||||||
|attributes| self.pool.best_transactions_with_attributes(attributes),
|
|attributes| self.pool.best_transactions_with_attributes(attributes),
|
||||||
)?
|
)?
|
||||||
.into_payload()
|
.into_payload()
|
||||||
@ -168,7 +133,6 @@ pub fn default_ethereum_payload<EvmConfig, Client, Pool, F>(
|
|||||||
pool: Pool,
|
pool: Pool,
|
||||||
builder_config: EthereumBuilderConfig,
|
builder_config: EthereumBuilderConfig,
|
||||||
args: BuildArguments<EthPayloadBuilderAttributes, EthBuiltPayload>,
|
args: BuildArguments<EthPayloadBuilderAttributes, EthBuiltPayload>,
|
||||||
evm_env: EvmEnv<EvmConfig::Spec>,
|
|
||||||
best_txs: F,
|
best_txs: F,
|
||||||
) -> Result<BuildOutcome<EthBuiltPayload>, PayloadBuilderError>
|
) -> Result<BuildOutcome<EthBuiltPayload>, PayloadBuilderError>
|
||||||
where
|
where
|
||||||
@ -178,13 +142,24 @@ where
|
|||||||
F: FnOnce(BestTransactionsAttributes) -> BestTransactionsIter<Pool>,
|
F: FnOnce(BestTransactionsAttributes) -> BestTransactionsIter<Pool>,
|
||||||
{
|
{
|
||||||
let BuildArguments { mut cached_reads, config, cancel, best_payload } = args;
|
let BuildArguments { mut cached_reads, config, cancel, best_payload } = args;
|
||||||
|
let PayloadConfig { parent_header, attributes } = config;
|
||||||
|
|
||||||
let chain_spec = client.chain_spec();
|
let state_provider = client.state_by_block_hash(parent_header.hash())?;
|
||||||
let state_provider = client.state_by_block_hash(config.parent_header.hash())?;
|
|
||||||
let state = StateProviderDatabase::new(state_provider);
|
let state = StateProviderDatabase::new(state_provider);
|
||||||
let mut db =
|
let mut db =
|
||||||
State::builder().with_database(cached_reads.as_db_mut(state)).with_bundle_update().build();
|
State::builder().with_database(cached_reads.as_db_mut(state)).with_bundle_update().build();
|
||||||
let PayloadConfig { parent_header, attributes } = config;
|
|
||||||
|
let next_attributes = NextBlockEnvAttributes {
|
||||||
|
timestamp: attributes.timestamp(),
|
||||||
|
suggested_fee_recipient: attributes.suggested_fee_recipient(),
|
||||||
|
prev_randao: attributes.prev_randao(),
|
||||||
|
gas_limit: builder_config.gas_limit(parent_header.gas_limit),
|
||||||
|
};
|
||||||
|
let evm_env = evm_config
|
||||||
|
.next_evm_env(&parent_header, next_attributes)
|
||||||
|
.map_err(PayloadBuilderError::other)?;
|
||||||
|
|
||||||
|
let chain_spec = client.chain_spec();
|
||||||
|
|
||||||
debug!(target: "payload_builder", id=%attributes.id, parent_header = ?parent_header.hash(), parent_number = parent_header.number, "building new payload");
|
debug!(target: "payload_builder", id=%attributes.id, parent_header = ?parent_header.hash(), parent_number = parent_header.number, "building new payload");
|
||||||
let mut cumulative_gas_used = 0;
|
let mut cumulative_gas_used = 0;
|
||||||
@ -202,32 +177,27 @@ where
|
|||||||
let block_number = evm_env.block_env.number;
|
let block_number = evm_env.block_env.number;
|
||||||
let beneficiary = evm_env.block_env.beneficiary;
|
let beneficiary = evm_env.block_env.beneficiary;
|
||||||
|
|
||||||
let mut evm = evm_config.evm_with_env(&mut db, evm_env);
|
let mut strategy = EthExecutionStrategy::new(
|
||||||
let mut system_caller = SystemCaller::new(chain_spec.clone());
|
evm_config.evm_with_env(&mut db, evm_env),
|
||||||
|
EthBlockExecutionInput {
|
||||||
// apply eip-4788 pre block contract call
|
number: parent_header.number + 1,
|
||||||
system_caller
|
timestamp: attributes.timestamp(),
|
||||||
.apply_beacon_root_contract_call(attributes.parent_beacon_block_root, &mut evm)
|
parent_hash: parent_header.hash(),
|
||||||
.map_err(|err| {
|
gas_limit: next_attributes.gas_limit,
|
||||||
warn!(target: "payload_builder",
|
parent_beacon_block_root: attributes.parent_beacon_block_root,
|
||||||
parent_hash=%parent_header.hash(),
|
beneficiary,
|
||||||
%err,
|
ommers: &[],
|
||||||
"failed to apply beacon root contract call for payload"
|
withdrawals: Some(&attributes.withdrawals),
|
||||||
|
},
|
||||||
|
&chain_spec,
|
||||||
|
&evm_config,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
strategy.apply_pre_execution_changes().map_err(|err| {
|
||||||
|
warn!(target: "payload_builder", %err, "failed to apply pre-execution changes");
|
||||||
PayloadBuilderError::Internal(err.into())
|
PayloadBuilderError::Internal(err.into())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// apply eip-2935 blockhashes update
|
|
||||||
system_caller.apply_blockhashes_contract_call(
|
|
||||||
parent_header.hash(),
|
|
||||||
&mut evm,
|
|
||||||
)
|
|
||||||
.map_err(|err| {
|
|
||||||
warn!(target: "payload_builder", parent_hash=%parent_header.hash(), %err, "failed to update parent header blockhashes for payload");
|
|
||||||
PayloadBuilderError::Internal(err.into())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let mut receipts = Vec::new();
|
|
||||||
let mut block_blob_count = 0;
|
let mut block_blob_count = 0;
|
||||||
let blob_params = chain_spec.blob_params_at_timestamp(attributes.timestamp);
|
let blob_params = chain_spec.blob_params_at_timestamp(attributes.timestamp);
|
||||||
let max_blob_count =
|
let max_blob_count =
|
||||||
@ -278,20 +248,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the environment for the tx.
|
let gas_used = match strategy.execute_transaction(tx.as_recovered_ref()) {
|
||||||
let tx_env = evm_config.tx_env(&tx);
|
Ok(gas_used) => gas_used,
|
||||||
|
Err(BlockExecutionError::Validation(BlockValidationError::InvalidTx {
|
||||||
let ResultAndState { result, state } = match evm.transact(tx_env) {
|
error, ..
|
||||||
Ok(res) => res,
|
})) => {
|
||||||
Err(err) => {
|
if error.is_nonce_too_low() {
|
||||||
if let Some(err) = err.as_invalid_tx_err() {
|
|
||||||
if err.is_nonce_too_low() {
|
|
||||||
// if the nonce is too low, we can skip this transaction
|
// if the nonce is too low, we can skip this transaction
|
||||||
trace!(target: "payload_builder", %err, ?tx, "skipping nonce too low transaction");
|
trace!(target: "payload_builder", %error, ?tx, "skipping nonce too low transaction");
|
||||||
} else {
|
} else {
|
||||||
// if the transaction is invalid, we can skip it and all of its
|
// if the transaction is invalid, we can skip it and all of its
|
||||||
// descendants
|
// descendants
|
||||||
trace!(target: "payload_builder", %err, ?tx, "skipping invalid transaction and its descendants");
|
trace!(target: "payload_builder", %error, ?tx, "skipping invalid transaction and its descendants");
|
||||||
best_txs.mark_invalid(
|
best_txs.mark_invalid(
|
||||||
&pool_tx,
|
&pool_tx,
|
||||||
InvalidPoolTransactionError::Consensus(
|
InvalidPoolTransactionError::Consensus(
|
||||||
@ -302,13 +270,9 @@ where
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// this is an error that we should treat as fatal for this attempt
|
// this is an error that we should treat as fatal for this attempt
|
||||||
return Err(PayloadBuilderError::evm(err))
|
Err(err) => return Err(PayloadBuilderError::evm(err)),
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// commit changes
|
|
||||||
evm.db_mut().commit(state);
|
|
||||||
|
|
||||||
// add to the total blob gas used if the transaction successfully executed
|
// add to the total blob gas used if the transaction successfully executed
|
||||||
if let Some(blob_tx) = tx.as_eip4844() {
|
if let Some(blob_tx) = tx.as_eip4844() {
|
||||||
block_blob_count += blob_tx.blob_versioned_hashes.len() as u64;
|
block_blob_count += blob_tx.blob_versioned_hashes.len() as u64;
|
||||||
@ -319,23 +283,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let gas_used = result.gas_used();
|
|
||||||
|
|
||||||
// add gas used by the transaction to cumulative gas used, before creating the receipt
|
|
||||||
cumulative_gas_used += gas_used;
|
|
||||||
|
|
||||||
// Push transaction changeset and calculate header bloom filter for receipt.
|
|
||||||
receipts.push(Receipt {
|
|
||||||
tx_type: tx.tx_type(),
|
|
||||||
success: result.is_success(),
|
|
||||||
cumulative_gas_used,
|
|
||||||
logs: result.into_logs().into_iter().collect(),
|
|
||||||
});
|
|
||||||
|
|
||||||
// update add to total fees
|
// update add to total fees
|
||||||
let miner_fee =
|
let miner_fee =
|
||||||
tx.effective_tip_per_gas(base_fee).expect("fee is always valid; execution succeeded");
|
tx.effective_tip_per_gas(base_fee).expect("fee is always valid; execution succeeded");
|
||||||
total_fees += U256::from(miner_fee) * U256::from(gas_used);
|
total_fees += U256::from(miner_fee) * U256::from(gas_used);
|
||||||
|
cumulative_gas_used += gas_used;
|
||||||
|
|
||||||
// append transaction to the block body
|
// append transaction to the block body
|
||||||
executed_txs.push(tx.into_tx());
|
executed_txs.push(tx.into_tx());
|
||||||
@ -344,39 +296,20 @@ where
|
|||||||
// check if we have a better block
|
// check if we have a better block
|
||||||
if !is_better_payload(best_payload.as_ref(), total_fees) {
|
if !is_better_payload(best_payload.as_ref(), total_fees) {
|
||||||
// Release db
|
// Release db
|
||||||
drop(evm);
|
drop(strategy);
|
||||||
|
|
||||||
// can skip building the block
|
// can skip building the block
|
||||||
return Ok(BuildOutcome::Aborted { fees: total_fees, cached_reads })
|
return Ok(BuildOutcome::Aborted { fees: total_fees, cached_reads })
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate the requests and the requests root
|
let BlockExecutionResult { receipts, requests, gas_used } = strategy
|
||||||
let requests = if chain_spec.is_prague_active_at_timestamp(attributes.timestamp) {
|
.apply_post_execution_changes()
|
||||||
let deposit_requests = parse_deposits_from_receipts(&chain_spec, receipts.iter())
|
.map_err(|err| PayloadBuilderError::Internal(err.into()))?;
|
||||||
.map_err(|err| PayloadBuilderError::Internal(RethError::Execution(err.into())))?;
|
|
||||||
|
|
||||||
let mut requests = Requests::default();
|
let requests =
|
||||||
|
chain_spec.is_prague_active_at_timestamp(attributes.timestamp).then_some(requests);
|
||||||
if !deposit_requests.is_empty() {
|
let withdrawals_root = chain_spec
|
||||||
requests.push_request_with_type(eip6110::DEPOSIT_REQUEST_TYPE, deposit_requests);
|
.is_shanghai_active_at_timestamp(attributes.timestamp)
|
||||||
}
|
.then_some(proofs::calculate_withdrawals_root(&attributes.withdrawals));
|
||||||
|
|
||||||
requests.extend(
|
|
||||||
system_caller
|
|
||||||
.apply_post_execution_changes(&mut evm)
|
|
||||||
.map_err(|err| PayloadBuilderError::Internal(err.into()))?,
|
|
||||||
);
|
|
||||||
|
|
||||||
Some(requests)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// Release db
|
|
||||||
drop(evm);
|
|
||||||
|
|
||||||
let withdrawals_root =
|
|
||||||
commit_withdrawals(&mut db, &chain_spec, attributes.timestamp, &attributes.withdrawals)?;
|
|
||||||
|
|
||||||
// merge all transitions into bundle state, this would apply the withdrawal balance changes
|
// merge all transitions into bundle state, this would apply the withdrawal balance changes
|
||||||
// and 4788 contract call
|
// and 4788 contract call
|
||||||
@ -449,7 +382,7 @@ where
|
|||||||
number: parent_header.number + 1,
|
number: parent_header.number + 1,
|
||||||
gas_limit: block_gas_limit,
|
gas_limit: block_gas_limit,
|
||||||
difficulty: U256::ZERO,
|
difficulty: U256::ZERO,
|
||||||
gas_used: cumulative_gas_used,
|
gas_used,
|
||||||
extra_data: builder_config.extra_data,
|
extra_data: builder_config.extra_data,
|
||||||
parent_beacon_block_root: attributes.parent_beacon_block_root,
|
parent_beacon_block_root: attributes.parent_beacon_block_root,
|
||||||
blob_gas_used,
|
blob_gas_used,
|
||||||
|
|||||||
@ -143,7 +143,7 @@ impl BlockExecutionError {
|
|||||||
matches!(self, Self::Validation(BlockValidationError::StateRoot(_)))
|
matches!(self, Self::Validation(BlockValidationError::StateRoot(_)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles an EVM error occured when executing a transaction.
|
/// Handles an EVM error occurred when executing a transaction.
|
||||||
///
|
///
|
||||||
/// If an error matches [`EvmError::InvalidTransaction`], it will be wrapped into
|
/// If an error matches [`EvmError::InvalidTransaction`], it will be wrapped into
|
||||||
/// [`BlockValidationError::InvalidTx`], otherwise into [`InternalBlockExecutionError::EVM`].
|
/// [`BlockValidationError::InvalidTx`], otherwise into [`InternalBlockExecutionError::EVM`].
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
use crate::{ConfigureEvm, ConfigureEvmEnv};
|
use crate::{ConfigureEvm, ConfigureEvmEnv};
|
||||||
use alloy_evm::{EvmEnv, EvmFactory};
|
use alloy_evm::{EvmEnv, EvmFactory};
|
||||||
use reth_primitives_traits::NodePrimitives;
|
use reth_primitives_traits::NodePrimitives;
|
||||||
|
use revm::inspector::NoOpInspector;
|
||||||
|
|
||||||
/// This is a type alias to make type bounds simpler when we have a [`NodePrimitives`] and need a
|
/// This is a type alias to make type bounds simpler when we have a [`NodePrimitives`] and need a
|
||||||
/// [`ConfigureEvmEnv`] whose associated types match the [`NodePrimitives`] associated types.
|
/// [`ConfigureEvmEnv`] whose associated types match the [`NodePrimitives`] associated types.
|
||||||
@ -43,3 +44,8 @@ pub type HaltReasonFor<Evm> = <<Evm as ConfigureEvm>::EvmFactory as EvmFactory<
|
|||||||
|
|
||||||
/// Helper to access [`ConfigureEvmEnv::Spec`] for a given [`ConfigureEvmEnv`].
|
/// Helper to access [`ConfigureEvmEnv::Spec`] for a given [`ConfigureEvmEnv`].
|
||||||
pub type SpecFor<Evm> = <Evm as ConfigureEvmEnv>::Spec;
|
pub type SpecFor<Evm> = <Evm as ConfigureEvmEnv>::Spec;
|
||||||
|
|
||||||
|
/// Helper to access [`EvmFactory::Evm`] for a given [`ConfigureEvm`].
|
||||||
|
pub type EvmFor<Evm, DB, I = NoOpInspector> = <<Evm as ConfigureEvm>::EvmFactory as EvmFactory<
|
||||||
|
EvmEnv<<Evm as ConfigureEvmEnv>::Spec>,
|
||||||
|
>>::Evm<DB, I>;
|
||||||
|
|||||||
@ -174,10 +174,12 @@ pub trait BlockExecutionStrategy {
|
|||||||
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error>;
|
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error>;
|
||||||
|
|
||||||
/// Executes a single transaction and applies execution result to internal state.
|
/// Executes a single transaction and applies execution result to internal state.
|
||||||
|
///
|
||||||
|
/// Returns the gas used by the transaction.
|
||||||
fn execute_transaction(
|
fn execute_transaction(
|
||||||
&mut self,
|
&mut self,
|
||||||
tx: Recovered<&<Self::Primitives as NodePrimitives>::SignedTx>,
|
tx: Recovered<&<Self::Primitives as NodePrimitives>::SignedTx>,
|
||||||
) -> Result<(), Self::Error>;
|
) -> Result<u64, Self::Error>;
|
||||||
|
|
||||||
/// Applies any necessary changes after executing the block's transactions.
|
/// Applies any necessary changes after executing the block's transactions.
|
||||||
fn apply_post_execution_changes(
|
fn apply_post_execution_changes(
|
||||||
@ -449,8 +451,8 @@ mod tests {
|
|||||||
fn execute_transaction(
|
fn execute_transaction(
|
||||||
&mut self,
|
&mut self,
|
||||||
_tx: Recovered<&TransactionSigned>,
|
_tx: Recovered<&TransactionSigned>,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<u64, Self::Error> {
|
||||||
Ok(())
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_post_execution_changes(
|
fn apply_post_execution_changes(
|
||||||
|
|||||||
@ -24,10 +24,7 @@ pub use alloy_evm::evm::EvmFactory;
|
|||||||
use alloy_primitives::{Address, B256};
|
use alloy_primitives::{Address, B256};
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use reth_primitives_traits::{BlockHeader, SignedTransaction};
|
use reth_primitives_traits::{BlockHeader, SignedTransaction};
|
||||||
use revm::{
|
use revm::{context::TxEnv, inspector::Inspector};
|
||||||
context::TxEnv,
|
|
||||||
inspector::{Inspector, NoOpInspector},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub mod batch;
|
pub mod batch;
|
||||||
pub mod either;
|
pub mod either;
|
||||||
@ -76,11 +73,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv {
|
|||||||
/// including the spec id and transaction environment.
|
/// including the spec id and transaction environment.
|
||||||
///
|
///
|
||||||
/// This will preserve any handler modifications
|
/// This will preserve any handler modifications
|
||||||
fn evm_with_env<DB: Database>(
|
fn evm_with_env<DB: Database>(&self, db: DB, evm_env: EvmEnv<Self::Spec>) -> EvmFor<Self, DB> {
|
||||||
&self,
|
|
||||||
db: DB,
|
|
||||||
evm_env: EvmEnv<Self::Spec>,
|
|
||||||
) -> <Self::EvmFactory as EvmFactory<EvmEnv<Self::Spec>>>::Evm<DB, NoOpInspector> {
|
|
||||||
self.evm_factory().create_evm(db, evm_env)
|
self.evm_factory().create_evm(db, evm_env)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,11 +84,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv {
|
|||||||
/// # Caution
|
/// # Caution
|
||||||
///
|
///
|
||||||
/// This does not initialize the tx environment.
|
/// This does not initialize the tx environment.
|
||||||
fn evm_for_block<DB: Database>(
|
fn evm_for_block<DB: Database>(&self, db: DB, header: &Self::Header) -> EvmFor<Self, DB> {
|
||||||
&self,
|
|
||||||
db: DB,
|
|
||||||
header: &Self::Header,
|
|
||||||
) -> <Self::EvmFactory as EvmFactory<EvmEnv<Self::Spec>>>::Evm<DB, NoOpInspector> {
|
|
||||||
let evm_env = self.evm_env(header);
|
let evm_env = self.evm_env(header);
|
||||||
self.evm_with_env(db, evm_env)
|
self.evm_with_env(db, evm_env)
|
||||||
}
|
}
|
||||||
@ -111,7 +100,7 @@ pub trait ConfigureEvm: ConfigureEvmEnv {
|
|||||||
db: DB,
|
db: DB,
|
||||||
evm_env: EvmEnv<Self::Spec>,
|
evm_env: EvmEnv<Self::Spec>,
|
||||||
inspector: I,
|
inspector: I,
|
||||||
) -> <Self::EvmFactory as EvmFactory<EvmEnv<Self::Spec>>>::Evm<DB, I>
|
) -> EvmFor<Self, DB, I>
|
||||||
where
|
where
|
||||||
DB: Database,
|
DB: Database,
|
||||||
I: InspectorFor<DB, Self>,
|
I: InspectorFor<DB, Self>,
|
||||||
@ -131,19 +120,11 @@ where
|
|||||||
(*self).evm_factory()
|
(*self).evm_factory()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evm_for_block<DB: Database>(
|
fn evm_for_block<DB: Database>(&self, db: DB, header: &Self::Header) -> EvmFor<Self, DB> {
|
||||||
&self,
|
|
||||||
db: DB,
|
|
||||||
header: &Self::Header,
|
|
||||||
) -> <Self::EvmFactory as EvmFactory<EvmEnv<Self::Spec>>>::Evm<DB, NoOpInspector> {
|
|
||||||
(*self).evm_for_block(db, header)
|
(*self).evm_for_block(db, header)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evm_with_env<DB: Database>(
|
fn evm_with_env<DB: Database>(&self, db: DB, evm_env: EvmEnv<Self::Spec>) -> EvmFor<Self, DB> {
|
||||||
&self,
|
|
||||||
db: DB,
|
|
||||||
evm_env: EvmEnv<Self::Spec>,
|
|
||||||
) -> <Self::EvmFactory as EvmFactory<EvmEnv<Self::Spec>>>::Evm<DB, NoOpInspector> {
|
|
||||||
(*self).evm_with_env(db, evm_env)
|
(*self).evm_with_env(db, evm_env)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +133,7 @@ where
|
|||||||
db: DB,
|
db: DB,
|
||||||
evm_env: EvmEnv<Self::Spec>,
|
evm_env: EvmEnv<Self::Spec>,
|
||||||
inspector: I,
|
inspector: I,
|
||||||
) -> <Self::EvmFactory as EvmFactory<EvmEnv<Self::Spec>>>::Evm<DB, I>
|
) -> EvmFor<Self, DB, I>
|
||||||
where
|
where
|
||||||
DB: Database,
|
DB: Database,
|
||||||
I: InspectorFor<DB, Self>,
|
I: InspectorFor<DB, Self>,
|
||||||
|
|||||||
@ -1,50 +1,46 @@
|
|||||||
//! State changes that are not related to transactions.
|
//! State changes that are not related to transactions.
|
||||||
|
|
||||||
use alloy_consensus::BlockHeader;
|
use alloy_consensus::BlockHeader;
|
||||||
use alloy_eips::eip4895::Withdrawal;
|
use alloy_eips::eip4895::{Withdrawal, Withdrawals};
|
||||||
use alloy_primitives::{map::HashMap, Address};
|
use alloy_primitives::{map::HashMap, Address};
|
||||||
use reth_chainspec::EthereumHardforks;
|
use reth_chainspec::EthereumHardforks;
|
||||||
use reth_consensus_common::calc;
|
use reth_consensus_common::calc;
|
||||||
use reth_primitives::SealedBlock;
|
use revm::context::BlockEnv;
|
||||||
use reth_primitives_traits::BlockBody;
|
|
||||||
|
|
||||||
/// Collect all balance changes at the end of the block.
|
/// Collect all balance changes at the end of the block.
|
||||||
///
|
///
|
||||||
/// Balance changes might include the block reward, uncle rewards, withdrawals, or irregular
|
/// Balance changes might include the block reward, uncle rewards, withdrawals, or irregular
|
||||||
/// state changes (DAO fork).
|
/// state changes (DAO fork).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn post_block_balance_increments<ChainSpec, Block>(
|
pub fn post_block_balance_increments<H>(
|
||||||
chain_spec: &ChainSpec,
|
chain_spec: impl EthereumHardforks,
|
||||||
block: &SealedBlock<Block>,
|
block_env: &BlockEnv,
|
||||||
|
ommers: &[H],
|
||||||
|
withdrawals: Option<&Withdrawals>,
|
||||||
) -> HashMap<Address, u128>
|
) -> HashMap<Address, u128>
|
||||||
where
|
where
|
||||||
ChainSpec: EthereumHardforks,
|
H: BlockHeader,
|
||||||
Block: reth_primitives_traits::Block,
|
|
||||||
{
|
{
|
||||||
let mut balance_increments = HashMap::default();
|
let mut balance_increments = HashMap::default();
|
||||||
|
|
||||||
// Add block rewards if they are enabled.
|
// Add block rewards if they are enabled.
|
||||||
if let Some(base_block_reward) = calc::base_block_reward(chain_spec, block.header().number()) {
|
if let Some(base_block_reward) = calc::base_block_reward(&chain_spec, block_env.number) {
|
||||||
// Ommer rewards
|
// Ommer rewards
|
||||||
if let Some(ommers) = block.body().ommers() {
|
|
||||||
for ommer in ommers {
|
for ommer in ommers {
|
||||||
*balance_increments.entry(ommer.beneficiary()).or_default() +=
|
*balance_increments.entry(ommer.beneficiary()).or_default() +=
|
||||||
calc::ommer_reward(base_block_reward, block.header().number(), ommer.number());
|
calc::ommer_reward(base_block_reward, block_env.number, ommer.number());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Full block reward
|
// Full block reward
|
||||||
*balance_increments.entry(block.header().beneficiary()).or_default() += calc::block_reward(
|
*balance_increments.entry(block_env.beneficiary).or_default() +=
|
||||||
base_block_reward,
|
calc::block_reward(base_block_reward, ommers.len());
|
||||||
block.body().ommers().map(|s| s.len()).unwrap_or(0),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// process withdrawals
|
// process withdrawals
|
||||||
insert_post_block_withdrawals_balance_increments(
|
insert_post_block_withdrawals_balance_increments(
|
||||||
chain_spec,
|
chain_spec,
|
||||||
block.header().timestamp(),
|
block_env.timestamp,
|
||||||
block.body().withdrawals().as_ref().map(|w| w.as_slice()),
|
withdrawals.map(|w| w.as_slice()),
|
||||||
&mut balance_increments,
|
&mut balance_increments,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -77,8 +73,8 @@ pub fn post_block_withdrawals_balance_increments<ChainSpec: EthereumHardforks>(
|
|||||||
///
|
///
|
||||||
/// Zero-valued withdrawals are filtered out.
|
/// Zero-valued withdrawals are filtered out.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn insert_post_block_withdrawals_balance_increments<ChainSpec: EthereumHardforks>(
|
pub fn insert_post_block_withdrawals_balance_increments(
|
||||||
chain_spec: &ChainSpec,
|
chain_spec: impl EthereumHardforks,
|
||||||
block_timestamp: u64,
|
block_timestamp: u64,
|
||||||
withdrawals: Option<&[Withdrawal]>,
|
withdrawals: Option<&[Withdrawal]>,
|
||||||
balance_increments: &mut HashMap<Address, u128>,
|
balance_increments: &mut HashMap<Address, u128>,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||||
use alloy_consensus::{
|
use alloy_consensus::{
|
||||||
transaction::Recovered, BlockHeader, Eip658Value, Receipt, Transaction as _, TxReceipt,
|
transaction::Recovered, BlockHeader, Eip658Value, Header, Receipt, Transaction as _, TxReceipt,
|
||||||
};
|
};
|
||||||
use op_alloy_consensus::OpDepositReceipt;
|
use op_alloy_consensus::OpDepositReceipt;
|
||||||
use reth_evm::{
|
use reth_evm::{
|
||||||
@ -22,9 +22,12 @@ use reth_execution_types::BlockExecutionResult;
|
|||||||
use reth_optimism_chainspec::OpChainSpec;
|
use reth_optimism_chainspec::OpChainSpec;
|
||||||
use reth_optimism_forks::OpHardforks;
|
use reth_optimism_forks::OpHardforks;
|
||||||
use reth_optimism_primitives::{transaction::signed::OpTransaction, DepositReceipt, OpPrimitives};
|
use reth_optimism_primitives::{transaction::signed::OpTransaction, DepositReceipt, OpPrimitives};
|
||||||
use reth_primitives_traits::{NodePrimitives, RecoveredBlock, SealedBlock, SignedTransaction};
|
use reth_primitives_traits::{
|
||||||
|
Block, NodePrimitives, RecoveredBlock, SealedBlock, SignedTransaction,
|
||||||
|
};
|
||||||
use revm::{context_interface::result::ResultAndState, DatabaseCommit};
|
use revm::{context_interface::result::ResultAndState, DatabaseCommit};
|
||||||
use revm_database::State;
|
use revm_database::State;
|
||||||
|
use revm_primitives::{Address, B256};
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
/// Factory for [`OpExecutionStrategy`].
|
/// Factory for [`OpExecutionStrategy`].
|
||||||
@ -89,19 +92,59 @@ where
|
|||||||
DB: Database,
|
DB: Database,
|
||||||
{
|
{
|
||||||
let evm = self.evm_config.evm_for_block(db, block.header());
|
let evm = self.evm_config.evm_for_block(db, block.header());
|
||||||
OpExecutionStrategy::new(evm, block.sealed_block(), self)
|
OpExecutionStrategy::new(
|
||||||
|
evm,
|
||||||
|
block.sealed_block(),
|
||||||
|
&self.chain_spec,
|
||||||
|
&self.evm_config,
|
||||||
|
self.receipt_builder.as_ref(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Input for block execution.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct OpBlockExecutionInput {
|
||||||
|
/// Block number.
|
||||||
|
pub number: u64,
|
||||||
|
/// Block timestamp.
|
||||||
|
pub timestamp: u64,
|
||||||
|
/// Parent block hash.
|
||||||
|
pub parent_hash: B256,
|
||||||
|
/// Block gas limit.
|
||||||
|
pub gas_limit: u64,
|
||||||
|
/// Parent beacon block root.
|
||||||
|
pub parent_beacon_block_root: Option<B256>,
|
||||||
|
/// Block beneficiary.
|
||||||
|
pub beneficiary: Address,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, B: Block> From<&'a SealedBlock<B>> for OpBlockExecutionInput {
|
||||||
|
fn from(block: &'a SealedBlock<B>) -> Self {
|
||||||
|
Self {
|
||||||
|
number: block.header().number(),
|
||||||
|
timestamp: block.header().timestamp(),
|
||||||
|
parent_hash: block.header().parent_hash(),
|
||||||
|
gas_limit: block.header().gas_limit(),
|
||||||
|
parent_beacon_block_root: block.header().parent_beacon_block_root(),
|
||||||
|
beneficiary: block.header().beneficiary(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Block execution strategy for Optimism.
|
/// Block execution strategy for Optimism.
|
||||||
#[derive(Debug, derive_more::Deref)]
|
#[derive(Debug)]
|
||||||
pub struct OpExecutionStrategy<'a, Evm, N: NodePrimitives, ChainSpec, EvmConfig: ConfigureEvm> {
|
pub struct OpExecutionStrategy<'a, Evm, N: NodePrimitives, ChainSpec, EvmConfig: ConfigureEvm> {
|
||||||
/// Reference to the parent factory.
|
/// Chainspec.
|
||||||
#[deref]
|
chain_spec: ChainSpec,
|
||||||
factory: &'a OpExecutionStrategyFactory<N, ChainSpec, EvmConfig>,
|
/// How to configure the EVM.
|
||||||
|
evm_config: EvmConfig,
|
||||||
|
/// Receipt builder.
|
||||||
|
receipt_builder:
|
||||||
|
&'a dyn OpReceiptBuilder<N::SignedTx, HaltReasonFor<EvmConfig>, Receipt = N::Receipt>,
|
||||||
|
|
||||||
/// Block being executed.
|
/// Input for block execution.
|
||||||
block: &'a SealedBlock<N::Block>,
|
input: OpBlockExecutionInput,
|
||||||
/// The EVM used by strategy.
|
/// The EVM used by strategy.
|
||||||
evm: Evm,
|
evm: Evm,
|
||||||
/// Receipts of executed transactions.
|
/// Receipts of executed transactions.
|
||||||
@ -111,7 +154,7 @@ pub struct OpExecutionStrategy<'a, Evm, N: NodePrimitives, ChainSpec, EvmConfig:
|
|||||||
/// Whether Regolith hardfork is active.
|
/// Whether Regolith hardfork is active.
|
||||||
is_regolith: bool,
|
is_regolith: bool,
|
||||||
/// Utility to call system smart contracts.
|
/// Utility to call system smart contracts.
|
||||||
system_caller: SystemCaller<&'a ChainSpec>,
|
system_caller: SystemCaller<ChainSpec>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Evm, N, ChainSpec, EvmConfig> OpExecutionStrategy<'a, Evm, N, ChainSpec, EvmConfig>
|
impl<'a, Evm, N, ChainSpec, EvmConfig> OpExecutionStrategy<'a, Evm, N, ChainSpec, EvmConfig>
|
||||||
@ -123,17 +166,26 @@ where
|
|||||||
/// Creates a new [`OpExecutionStrategy`]
|
/// Creates a new [`OpExecutionStrategy`]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
evm: Evm,
|
evm: Evm,
|
||||||
block: &'a SealedBlock<N::Block>,
|
input: impl Into<OpBlockExecutionInput>,
|
||||||
factory: &'a OpExecutionStrategyFactory<N, ChainSpec, EvmConfig>,
|
chain_spec: ChainSpec,
|
||||||
|
evm_config: EvmConfig,
|
||||||
|
receipt_builder: &'a dyn OpReceiptBuilder<
|
||||||
|
N::SignedTx,
|
||||||
|
HaltReasonFor<EvmConfig>,
|
||||||
|
Receipt = N::Receipt,
|
||||||
|
>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let input = input.into();
|
||||||
Self {
|
Self {
|
||||||
|
is_regolith: chain_spec.is_regolith_active_at_timestamp(input.timestamp),
|
||||||
evm,
|
evm,
|
||||||
factory,
|
system_caller: SystemCaller::new(chain_spec.clone()),
|
||||||
block,
|
chain_spec,
|
||||||
|
evm_config,
|
||||||
|
receipt_builder,
|
||||||
receipts: Vec::new(),
|
receipts: Vec::new(),
|
||||||
gas_used: 0,
|
gas_used: 0,
|
||||||
is_regolith: factory.chain_spec.is_regolith_active_at_timestamp(block.timestamp()),
|
input,
|
||||||
system_caller: SystemCaller::new(&factory.chain_spec),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,28 +205,26 @@ where
|
|||||||
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error> {
|
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error> {
|
||||||
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
||||||
let state_clear_flag =
|
let state_clear_flag =
|
||||||
(*self.chain_spec).is_spurious_dragon_active_at_block(self.block.number());
|
self.chain_spec.is_spurious_dragon_active_at_block(self.input.number);
|
||||||
self.evm.db_mut().set_state_clear_flag(state_clear_flag);
|
self.evm.db_mut().set_state_clear_flag(state_clear_flag);
|
||||||
|
|
||||||
self.system_caller.apply_beacon_root_contract_call(
|
self.system_caller
|
||||||
self.block.parent_beacon_block_root(),
|
.apply_beacon_root_contract_call(self.input.parent_beacon_block_root, &mut self.evm)?;
|
||||||
&mut self.evm,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Ensure that the create2deployer is force-deployed at the canyon transition. Optimism
|
// Ensure that the create2deployer is force-deployed at the canyon transition. Optimism
|
||||||
// blocks will always have at least a single transaction in them (the L1 info transaction),
|
// blocks will always have at least a single transaction in them (the L1 info transaction),
|
||||||
// so we can safely assume that this will always be triggered upon the transition and that
|
// so we can safely assume that this will always be triggered upon the transition and that
|
||||||
// the above check for empty blocks will never be hit on OP chains.
|
// the above check for empty blocks will never be hit on OP chains.
|
||||||
ensure_create2_deployer(self.chain_spec.clone(), self.block.timestamp(), self.evm.db_mut())
|
ensure_create2_deployer(self.chain_spec.clone(), self.input.timestamp, self.evm.db_mut())
|
||||||
.map_err(|_| OpBlockExecutionError::ForceCreate2DeployerFail)?;
|
.map_err(|_| OpBlockExecutionError::ForceCreate2DeployerFail)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_transaction(&mut self, tx: Recovered<&N::SignedTx>) -> Result<(), Self::Error> {
|
fn execute_transaction(&mut self, tx: Recovered<&N::SignedTx>) -> Result<u64, Self::Error> {
|
||||||
// The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior,
|
// The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior,
|
||||||
// must be no greater than the block’s gasLimit.
|
// must be no greater than the block’s gasLimit.
|
||||||
let block_available_gas = self.block.gas_limit() - self.gas_used;
|
let block_available_gas = self.input.gas_limit - self.gas_used;
|
||||||
if tx.gas_limit() > block_available_gas && (self.is_regolith || !tx.is_deposit()) {
|
if tx.gas_limit() > block_available_gas && (self.is_regolith || !tx.is_deposit()) {
|
||||||
return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
|
return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
|
||||||
transaction_gas_limit: tx.gas_limit(),
|
transaction_gas_limit: tx.gas_limit(),
|
||||||
@ -215,8 +265,10 @@ where
|
|||||||
let ResultAndState { result, state } = result_and_state;
|
let ResultAndState { result, state } = result_and_state;
|
||||||
self.evm.db_mut().commit(state);
|
self.evm.db_mut().commit(state);
|
||||||
|
|
||||||
|
let gas_used = result.gas_used();
|
||||||
|
|
||||||
// append gas used
|
// append gas used
|
||||||
self.gas_used += result.gas_used();
|
self.gas_used += gas_used;
|
||||||
|
|
||||||
self.receipts.push(
|
self.receipts.push(
|
||||||
match self.receipt_builder.build_receipt(ReceiptBuilderCtx {
|
match self.receipt_builder.build_receipt(ReceiptBuilderCtx {
|
||||||
@ -243,22 +295,25 @@ where
|
|||||||
// this is only set for post-Canyon deposit
|
// this is only set for post-Canyon deposit
|
||||||
// transactions.
|
// transactions.
|
||||||
deposit_receipt_version: (tx.is_deposit() &&
|
deposit_receipt_version: (tx.is_deposit() &&
|
||||||
self.chain_spec
|
self.chain_spec.is_canyon_active_at_timestamp(self.input.timestamp))
|
||||||
.is_canyon_active_at_timestamp(self.block.timestamp()))
|
|
||||||
.then_some(1),
|
.then_some(1),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(gas_used)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_post_execution_changes(
|
fn apply_post_execution_changes(
|
||||||
mut self,
|
mut self,
|
||||||
) -> Result<BlockExecutionResult<N::Receipt>, Self::Error> {
|
) -> Result<BlockExecutionResult<N::Receipt>, Self::Error> {
|
||||||
let balance_increments =
|
let balance_increments = post_block_balance_increments::<Header>(
|
||||||
post_block_balance_increments(&self.chain_spec.clone(), self.block);
|
&self.chain_spec.clone(),
|
||||||
|
self.evm.block(),
|
||||||
|
&[],
|
||||||
|
None,
|
||||||
|
);
|
||||||
// increment balances
|
// increment balances
|
||||||
self.evm
|
self.evm
|
||||||
.db_mut()
|
.db_mut()
|
||||||
|
|||||||
@ -7,26 +7,24 @@ use crate::{
|
|||||||
OpPayloadPrimitives,
|
OpPayloadPrimitives,
|
||||||
};
|
};
|
||||||
use alloy_consensus::{
|
use alloy_consensus::{
|
||||||
constants::EMPTY_WITHDRAWALS, Eip658Value, Header, Transaction, Typed2718,
|
constants::EMPTY_WITHDRAWALS, Header, Transaction, Typed2718, EMPTY_OMMER_ROOT_HASH,
|
||||||
EMPTY_OMMER_ROOT_HASH,
|
|
||||||
};
|
};
|
||||||
use alloy_eips::{eip4895::Withdrawals, merge::BEACON_NONCE};
|
use alloy_eips::{eip4895::Withdrawals, merge::BEACON_NONCE};
|
||||||
use alloy_primitives::{Address, Bytes, B256, U256};
|
use alloy_primitives::{Address, Bytes, B256, U256};
|
||||||
use alloy_rlp::Encodable;
|
use alloy_rlp::Encodable;
|
||||||
use alloy_rpc_types_debug::ExecutionWitness;
|
use alloy_rpc_types_debug::ExecutionWitness;
|
||||||
use alloy_rpc_types_engine::PayloadId;
|
use alloy_rpc_types_engine::PayloadId;
|
||||||
use op_alloy_consensus::OpDepositReceipt;
|
|
||||||
use op_alloy_rpc_types_engine::OpPayloadAttributes;
|
use op_alloy_rpc_types_engine::OpPayloadAttributes;
|
||||||
use reth_basic_payload_builder::*;
|
use reth_basic_payload_builder::*;
|
||||||
use reth_chain_state::{ExecutedBlock, ExecutedBlockWithTrieUpdates};
|
use reth_chain_state::{ExecutedBlock, ExecutedBlockWithTrieUpdates};
|
||||||
use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
|
use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
|
||||||
use reth_evm::{
|
use reth_evm::{
|
||||||
system_calls::SystemCaller, ConfigureEvm, ConfigureEvmFor, Database, Evm, EvmEnv, EvmError,
|
execute::{BlockExecutionError, BlockExecutionStrategy, BlockValidationError},
|
||||||
HaltReasonFor, InvalidTxError, NextBlockEnvAttributes,
|
ConfigureEvm, ConfigureEvmFor, Database, EvmEnv, HaltReasonFor, NextBlockEnvAttributes,
|
||||||
};
|
};
|
||||||
use reth_execution_types::ExecutionOutcome;
|
use reth_execution_types::ExecutionOutcome;
|
||||||
use reth_optimism_consensus::calculate_receipt_root_no_memo_optimism;
|
use reth_optimism_consensus::calculate_receipt_root_no_memo_optimism;
|
||||||
use reth_optimism_evm::{OpReceiptBuilder, ReceiptBuilderCtx};
|
use reth_optimism_evm::{OpBlockExecutionInput, OpExecutionStrategy, OpReceiptBuilder};
|
||||||
use reth_optimism_forks::OpHardforks;
|
use reth_optimism_forks::OpHardforks;
|
||||||
use reth_optimism_primitives::transaction::signed::OpTransaction;
|
use reth_optimism_primitives::transaction::signed::OpTransaction;
|
||||||
use reth_optimism_storage::predeploys;
|
use reth_optimism_storage::predeploys;
|
||||||
@ -38,8 +36,8 @@ use reth_primitives::{
|
|||||||
};
|
};
|
||||||
use reth_primitives_traits::{block::Block as _, proofs, RecoveredBlock};
|
use reth_primitives_traits::{block::Block as _, proofs, RecoveredBlock};
|
||||||
use reth_provider::{
|
use reth_provider::{
|
||||||
HashedPostStateProvider, ProviderError, StateProofProvider, StateProviderFactory,
|
BlockExecutionResult, HashedPostStateProvider, ProviderError, StateProofProvider,
|
||||||
StateRootProvider, StorageRootProvider,
|
StateProviderFactory, StateRootProvider, StorageRootProvider,
|
||||||
};
|
};
|
||||||
use reth_revm::{
|
use reth_revm::{
|
||||||
cancelled::CancelOnDrop,
|
cancelled::CancelOnDrop,
|
||||||
@ -48,14 +46,8 @@ use reth_revm::{
|
|||||||
witness::ExecutionWitnessRecord,
|
witness::ExecutionWitnessRecord,
|
||||||
};
|
};
|
||||||
use reth_transaction_pool::{BestTransactionsAttributes, PoolTransaction, TransactionPool};
|
use reth_transaction_pool::{BestTransactionsAttributes, PoolTransaction, TransactionPool};
|
||||||
use revm::{
|
use revm::context_interface::Block;
|
||||||
context_interface::{
|
use std::sync::Arc;
|
||||||
result::{ExecutionResult, ResultAndState},
|
|
||||||
Block,
|
|
||||||
},
|
|
||||||
Database as _, DatabaseCommit,
|
|
||||||
};
|
|
||||||
use std::{fmt::Display, sync::Arc};
|
|
||||||
use tracing::{debug, trace, warn};
|
use tracing::{debug, trace, warn};
|
||||||
|
|
||||||
/// Optimism's payload builder
|
/// Optimism's payload builder
|
||||||
@ -366,21 +358,34 @@ impl<Txs> OpBuilder<'_, Txs> {
|
|||||||
let Self { best } = self;
|
let Self { best } = self;
|
||||||
debug!(target: "payload_builder", id=%ctx.payload_id(), parent_header = ?ctx.parent().hash(), parent_number = ctx.parent().number, "building new payload");
|
debug!(target: "payload_builder", id=%ctx.payload_id(), parent_header = ?ctx.parent().hash(), parent_number = ctx.parent().number, "building new payload");
|
||||||
|
|
||||||
let mut evm = ctx.evm_config.evm_with_env(&mut *state, ctx.evm_env.clone());
|
let mut strategy = OpExecutionStrategy::new(
|
||||||
|
ctx.evm_config.evm_with_env(&mut *state, ctx.evm_env.clone()),
|
||||||
|
OpBlockExecutionInput {
|
||||||
|
number: ctx.evm_env.block_env.number,
|
||||||
|
timestamp: ctx.evm_env.block_env.timestamp,
|
||||||
|
parent_hash: ctx.parent().hash(),
|
||||||
|
gas_limit: ctx.evm_env.block_env.gas_limit,
|
||||||
|
parent_beacon_block_root: ctx.attributes().parent_beacon_block_root(),
|
||||||
|
beneficiary: ctx.evm_env.block_env.beneficiary,
|
||||||
|
},
|
||||||
|
&ctx.chain_spec,
|
||||||
|
&ctx.evm_config,
|
||||||
|
ctx.receipt_builder.as_ref(),
|
||||||
|
);
|
||||||
|
|
||||||
// 1. apply eip-4788 pre block contract call
|
// 1. apply pre-execution changes
|
||||||
ctx.apply_pre_beacon_root_contract_call(&mut evm)?;
|
strategy.apply_pre_execution_changes().map_err(|err| {
|
||||||
|
warn!(target: "payload_builder", %err, "failed to apply pre-execution changes");
|
||||||
|
PayloadBuilderError::Internal(err.into())
|
||||||
|
})?;
|
||||||
|
|
||||||
// 2. ensure create2deployer is force deployed
|
// 2. execute sequencer transactions
|
||||||
ctx.ensure_create2_deployer(evm.db_mut())?;
|
let mut info = ctx.execute_sequencer_transactions(&mut strategy)?;
|
||||||
|
|
||||||
// 3. execute sequencer transactions
|
// 3. if mem pool transactions are requested we execute them
|
||||||
let mut info = ctx.execute_sequencer_transactions(&mut evm)?;
|
|
||||||
|
|
||||||
// 4. if mem pool transactions are requested we execute them
|
|
||||||
if !ctx.attributes().no_tx_pool {
|
if !ctx.attributes().no_tx_pool {
|
||||||
let best_txs = best(ctx.best_transaction_attributes());
|
let best_txs = best(ctx.best_transaction_attributes());
|
||||||
if ctx.execute_best_transactions(&mut info, &mut evm, best_txs)?.is_some() {
|
if ctx.execute_best_transactions(&mut info, &mut strategy, best_txs)?.is_some() {
|
||||||
return Ok(BuildOutcomeKind::Cancelled)
|
return Ok(BuildOutcomeKind::Cancelled)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,7 +396,9 @@ impl<Txs> OpBuilder<'_, Txs> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(evm);
|
let BlockExecutionResult { receipts, .. } = strategy
|
||||||
|
.apply_post_execution_changes()
|
||||||
|
.map_err(|err| PayloadBuilderError::Internal(err.into()))?;
|
||||||
|
|
||||||
// merge all transitions into bundle state, this would apply the withdrawal balance changes
|
// merge all transitions into bundle state, this would apply the withdrawal balance changes
|
||||||
// and 4788 contract call
|
// and 4788 contract call
|
||||||
@ -407,7 +414,7 @@ impl<Txs> OpBuilder<'_, Txs> {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let payload = ExecutedPayload { info, withdrawals_root };
|
let payload = ExecutedPayload { receipts, info, withdrawals_root };
|
||||||
|
|
||||||
Ok(BuildOutcomeKind::Better { payload })
|
Ok(BuildOutcomeKind::Better { payload })
|
||||||
}
|
}
|
||||||
@ -426,19 +433,16 @@ impl<Txs> OpBuilder<'_, Txs> {
|
|||||||
DB: Database<Error = ProviderError> + AsRef<P>,
|
DB: Database<Error = ProviderError> + AsRef<P>,
|
||||||
P: StateRootProvider + HashedPostStateProvider + StorageRootProvider,
|
P: StateRootProvider + HashedPostStateProvider + StorageRootProvider,
|
||||||
{
|
{
|
||||||
let ExecutedPayload { info, withdrawals_root } = match self.execute(&mut state, &ctx)? {
|
let ExecutedPayload { receipts, info, withdrawals_root } =
|
||||||
|
match self.execute(&mut state, &ctx)? {
|
||||||
BuildOutcomeKind::Better { payload } | BuildOutcomeKind::Freeze(payload) => payload,
|
BuildOutcomeKind::Better { payload } | BuildOutcomeKind::Freeze(payload) => payload,
|
||||||
BuildOutcomeKind::Cancelled => return Ok(BuildOutcomeKind::Cancelled),
|
BuildOutcomeKind::Cancelled => return Ok(BuildOutcomeKind::Cancelled),
|
||||||
BuildOutcomeKind::Aborted { fees } => return Ok(BuildOutcomeKind::Aborted { fees }),
|
BuildOutcomeKind::Aborted { fees } => return Ok(BuildOutcomeKind::Aborted { fees }),
|
||||||
};
|
};
|
||||||
|
|
||||||
let block_number = ctx.block_number();
|
let block_number = ctx.block_number();
|
||||||
let execution_outcome = ExecutionOutcome::new(
|
let execution_outcome =
|
||||||
state.take_bundle(),
|
ExecutionOutcome::new(state.take_bundle(), vec![receipts], block_number, Vec::new());
|
||||||
vec![info.receipts],
|
|
||||||
block_number,
|
|
||||||
Vec::new(),
|
|
||||||
);
|
|
||||||
let receipts_root = execution_outcome
|
let receipts_root = execution_outcome
|
||||||
.generic_receipts_root_slow(block_number, |receipts| {
|
.generic_receipts_root_slow(block_number, |receipts| {
|
||||||
calculate_receipt_root_no_memo_optimism(
|
calculate_receipt_root_no_memo_optimism(
|
||||||
@ -588,6 +592,8 @@ pub struct ExecutedPayload<N: NodePrimitives> {
|
|||||||
pub info: ExecutionInfo<N>,
|
pub info: ExecutionInfo<N>,
|
||||||
/// Withdrawal hash.
|
/// Withdrawal hash.
|
||||||
pub withdrawals_root: Option<B256>,
|
pub withdrawals_root: Option<B256>,
|
||||||
|
/// The transaction receipts.
|
||||||
|
pub receipts: Vec<N::Receipt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This acts as the container for executed transactions and its byproducts (receipts, gas used)
|
/// This acts as the container for executed transactions and its byproducts (receipts, gas used)
|
||||||
@ -597,8 +603,6 @@ pub struct ExecutionInfo<N: NodePrimitives> {
|
|||||||
pub executed_transactions: Vec<N::SignedTx>,
|
pub executed_transactions: Vec<N::SignedTx>,
|
||||||
/// The recovered senders for the executed transactions.
|
/// The recovered senders for the executed transactions.
|
||||||
pub executed_senders: Vec<Address>,
|
pub executed_senders: Vec<Address>,
|
||||||
/// The transaction receipts
|
|
||||||
pub receipts: Vec<N::Receipt>,
|
|
||||||
/// All gas used so far
|
/// All gas used so far
|
||||||
pub cumulative_gas_used: u64,
|
pub cumulative_gas_used: u64,
|
||||||
/// Estimated DA size
|
/// Estimated DA size
|
||||||
@ -613,7 +617,6 @@ impl<N: NodePrimitives> ExecutionInfo<N> {
|
|||||||
Self {
|
Self {
|
||||||
executed_transactions: Vec::with_capacity(capacity),
|
executed_transactions: Vec::with_capacity(capacity),
|
||||||
executed_senders: Vec::with_capacity(capacity),
|
executed_senders: Vec::with_capacity(capacity),
|
||||||
receipts: Vec::with_capacity(capacity),
|
|
||||||
cumulative_gas_used: 0,
|
cumulative_gas_used: 0,
|
||||||
cumulative_da_bytes_used: 0,
|
cumulative_da_bytes_used: 0,
|
||||||
total_fees: U256::ZERO,
|
total_fees: U256::ZERO,
|
||||||
@ -787,26 +790,6 @@ where
|
|||||||
pub fn is_better_payload(&self, total_fees: U256) -> bool {
|
pub fn is_better_payload(&self, total_fees: U256) -> bool {
|
||||||
is_better_payload(self.best_payload.as_ref(), total_fees)
|
is_better_payload(self.best_payload.as_ref(), total_fees)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure that the create2deployer is force-deployed at the canyon transition. Optimism
|
|
||||||
/// blocks will always have at least a single transaction in them (the L1 info transaction),
|
|
||||||
/// so we can safely assume that this will always be triggered upon the transition and that
|
|
||||||
/// the above check for empty blocks will never be hit on OP chains.
|
|
||||||
pub fn ensure_create2_deployer<DB>(&self, db: &mut State<DB>) -> Result<(), PayloadBuilderError>
|
|
||||||
where
|
|
||||||
DB: Database,
|
|
||||||
DB::Error: Display,
|
|
||||||
{
|
|
||||||
reth_optimism_evm::ensure_create2_deployer(
|
|
||||||
self.chain_spec.clone(),
|
|
||||||
self.attributes().payload_attributes.timestamp,
|
|
||||||
db,
|
|
||||||
)
|
|
||||||
.map_err(|err| {
|
|
||||||
warn!(target: "payload_builder", %err, "missing create2 deployer, skipping block.");
|
|
||||||
PayloadBuilderError::other(OpPayloadBuilderError::ForceCreate2DeployerFail)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<EvmConfig, ChainSpec, N> OpPayloadBuilderCtx<EvmConfig, ChainSpec, N>
|
impl<EvmConfig, ChainSpec, N> OpPayloadBuilderCtx<EvmConfig, ChainSpec, N>
|
||||||
@ -815,73 +798,10 @@ where
|
|||||||
ChainSpec: EthChainSpec + OpHardforks,
|
ChainSpec: EthChainSpec + OpHardforks,
|
||||||
N: OpPayloadPrimitives,
|
N: OpPayloadPrimitives,
|
||||||
{
|
{
|
||||||
/// apply eip-4788 pre block contract call
|
|
||||||
pub fn apply_pre_beacon_root_contract_call(
|
|
||||||
&self,
|
|
||||||
evm: &mut impl Evm<DB: DatabaseCommit>,
|
|
||||||
) -> Result<(), PayloadBuilderError> {
|
|
||||||
SystemCaller::new(&self.chain_spec)
|
|
||||||
.apply_beacon_root_contract_call(
|
|
||||||
self.attributes().payload_attributes.parent_beacon_block_root,
|
|
||||||
evm,
|
|
||||||
)
|
|
||||||
.map_err(|err| {
|
|
||||||
warn!(target: "payload_builder",
|
|
||||||
parent_header=%self.parent().hash(),
|
|
||||||
%err,
|
|
||||||
"failed to apply beacon root contract call for payload"
|
|
||||||
);
|
|
||||||
PayloadBuilderError::Internal(err.into())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a receipt for the given transaction.
|
|
||||||
fn build_receipt(
|
|
||||||
&self,
|
|
||||||
info: &ExecutionInfo<N>,
|
|
||||||
result: ExecutionResult<HaltReasonFor<EvmConfig>>,
|
|
||||||
deposit_nonce: Option<u64>,
|
|
||||||
tx: &N::SignedTx,
|
|
||||||
) -> N::Receipt {
|
|
||||||
match self.receipt_builder.build_receipt(ReceiptBuilderCtx {
|
|
||||||
tx,
|
|
||||||
result,
|
|
||||||
cumulative_gas_used: info.cumulative_gas_used,
|
|
||||||
}) {
|
|
||||||
Ok(receipt) => receipt,
|
|
||||||
Err(ctx) => {
|
|
||||||
let receipt = alloy_consensus::Receipt {
|
|
||||||
// Success flag was added in `EIP-658: Embedding transaction status code
|
|
||||||
// in receipts`.
|
|
||||||
status: Eip658Value::Eip658(ctx.result.is_success()),
|
|
||||||
cumulative_gas_used: ctx.cumulative_gas_used,
|
|
||||||
logs: ctx.result.into_logs(),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.receipt_builder.build_deposit_receipt(OpDepositReceipt {
|
|
||||||
inner: receipt,
|
|
||||||
deposit_nonce,
|
|
||||||
// The deposit receipt version was introduced in Canyon to indicate an
|
|
||||||
// update to how receipt hashes should be computed
|
|
||||||
// when set. The state transition process ensures
|
|
||||||
// this is only set for post-Canyon deposit
|
|
||||||
// transactions.
|
|
||||||
deposit_receipt_version: self.is_canyon_active().then_some(1),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Executes all sequencer transactions that are included in the payload attributes.
|
/// Executes all sequencer transactions that are included in the payload attributes.
|
||||||
pub fn execute_sequencer_transactions(
|
pub fn execute_sequencer_transactions(
|
||||||
&self,
|
&self,
|
||||||
evm: &mut impl Evm<
|
strategy: &mut impl BlockExecutionStrategy<Primitives = N, Error = BlockExecutionError>,
|
||||||
DB: Database<Error = ProviderError> + DatabaseCommit,
|
|
||||||
Tx = EvmConfig::TxEnv,
|
|
||||||
HaltReason = HaltReasonFor<EvmConfig>,
|
|
||||||
>,
|
|
||||||
) -> Result<ExecutionInfo<N>, PayloadBuilderError> {
|
) -> Result<ExecutionInfo<N>, PayloadBuilderError> {
|
||||||
let mut info = ExecutionInfo::with_capacity(self.attributes().transactions.len());
|
let mut info = ExecutionInfo::with_capacity(self.attributes().transactions.len());
|
||||||
|
|
||||||
@ -901,51 +821,24 @@ where
|
|||||||
PayloadBuilderError::other(OpPayloadBuilderError::TransactionEcRecoverFailed)
|
PayloadBuilderError::other(OpPayloadBuilderError::TransactionEcRecoverFailed)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Cache the depositor account prior to the state transition for the deposit nonce.
|
let gas_used = match strategy.execute_transaction(sequencer_tx.as_recovered_ref()) {
|
||||||
//
|
Ok(gas_used) => gas_used,
|
||||||
// Note that this *only* needs to be done post-regolith hardfork, as deposit nonces
|
Err(BlockExecutionError::Validation(BlockValidationError::InvalidTx {
|
||||||
// were not introduced in Bedrock. In addition, regular transactions don't have deposit
|
error,
|
||||||
// nonces, so we don't need to touch the DB for those.
|
..
|
||||||
let depositor_nonce = (self.is_regolith_active() && sequencer_tx.is_deposit())
|
})) => {
|
||||||
.then(|| {
|
trace!(target: "payload_builder", %error, ?sequencer_tx, "Error in sequencer transaction, skipping.");
|
||||||
evm.db_mut()
|
|
||||||
.basic(sequencer_tx.signer())
|
|
||||||
.map(|acc| acc.unwrap_or_default().nonce)
|
|
||||||
})
|
|
||||||
.transpose()
|
|
||||||
.map_err(|_| {
|
|
||||||
PayloadBuilderError::other(OpPayloadBuilderError::AccountLoadFailed(
|
|
||||||
sequencer_tx.signer(),
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let tx_env = self.evm_config.tx_env(&sequencer_tx);
|
|
||||||
|
|
||||||
let ResultAndState { result, state: _ } = match evm.transact_commit(tx_env) {
|
|
||||||
Ok(res) => res,
|
|
||||||
Err(err) => {
|
|
||||||
if err.is_invalid_tx_err() {
|
|
||||||
trace!(target: "payload_builder", %err, ?sequencer_tx, "Error in sequencer transaction, skipping.");
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
Err(err) => {
|
||||||
// this is an error that we should treat as fatal for this attempt
|
// this is an error that we should treat as fatal for this attempt
|
||||||
return Err(PayloadBuilderError::EvmExecutionError(Box::new(err)))
|
return Err(PayloadBuilderError::EvmExecutionError(Box::new(err)))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let gas_used = result.gas_used();
|
|
||||||
|
|
||||||
// add gas used by the transaction to cumulative gas used, before creating the receipt
|
// add gas used by the transaction to cumulative gas used, before creating the receipt
|
||||||
info.cumulative_gas_used += gas_used;
|
info.cumulative_gas_used += gas_used;
|
||||||
|
|
||||||
// Push transaction changeset and calculate header bloom filter for receipt.
|
|
||||||
info.receipts.push(self.build_receipt(
|
|
||||||
&info,
|
|
||||||
result,
|
|
||||||
depositor_nonce,
|
|
||||||
sequencer_tx.tx(),
|
|
||||||
));
|
|
||||||
|
|
||||||
// append sender and transaction to the respective lists
|
// append sender and transaction to the respective lists
|
||||||
info.executed_senders.push(sequencer_tx.signer());
|
info.executed_senders.push(sequencer_tx.signer());
|
||||||
info.executed_transactions.push(sequencer_tx.into_tx());
|
info.executed_transactions.push(sequencer_tx.into_tx());
|
||||||
@ -960,11 +853,7 @@ where
|
|||||||
pub fn execute_best_transactions(
|
pub fn execute_best_transactions(
|
||||||
&self,
|
&self,
|
||||||
info: &mut ExecutionInfo<N>,
|
info: &mut ExecutionInfo<N>,
|
||||||
evm: &mut impl Evm<
|
strategy: &mut impl BlockExecutionStrategy<Primitives = N, Error = BlockExecutionError>,
|
||||||
DB: DatabaseCommit,
|
|
||||||
Tx = EvmConfig::TxEnv,
|
|
||||||
HaltReason = HaltReasonFor<EvmConfig>,
|
|
||||||
>,
|
|
||||||
mut best_txs: impl PayloadTransactions<
|
mut best_txs: impl PayloadTransactions<
|
||||||
Transaction: PoolTransaction<Consensus = EvmConfig::Transaction>,
|
Transaction: PoolTransaction<Consensus = EvmConfig::Transaction>,
|
||||||
>,
|
>,
|
||||||
@ -995,40 +884,34 @@ where
|
|||||||
return Ok(Some(()))
|
return Ok(Some(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the environment for the tx.
|
let gas_used = match strategy.execute_transaction(tx.as_recovered_ref()) {
|
||||||
let tx_env = self.evm_config.tx_env(&tx);
|
Ok(gas_used) => gas_used,
|
||||||
|
Err(BlockExecutionError::Validation(BlockValidationError::InvalidTx {
|
||||||
let ResultAndState { result, state: _ } = match evm.transact_commit(tx_env) {
|
error,
|
||||||
Ok(res) => res,
|
..
|
||||||
Err(err) => {
|
})) => {
|
||||||
if let Some(err) = err.as_invalid_tx_err() {
|
if error.is_nonce_too_low() {
|
||||||
if err.is_nonce_too_low() {
|
|
||||||
// if the nonce is too low, we can skip this transaction
|
// if the nonce is too low, we can skip this transaction
|
||||||
trace!(target: "payload_builder", %err, ?tx, "skipping nonce too low transaction");
|
trace!(target: "payload_builder", %error, ?tx, "skipping nonce too low transaction");
|
||||||
} else {
|
} else {
|
||||||
// if the transaction is invalid, we can skip it and all of its
|
// if the transaction is invalid, we can skip it and all of its
|
||||||
// descendants
|
// descendants
|
||||||
trace!(target: "payload_builder", %err, ?tx, "skipping invalid transaction and its descendants");
|
trace!(target: "payload_builder", %error, ?tx, "skipping invalid transaction and its descendants");
|
||||||
best_txs.mark_invalid(tx.signer(), tx.nonce());
|
best_txs.mark_invalid(tx.signer(), tx.nonce());
|
||||||
}
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
Err(err) => {
|
||||||
// this is an error that we should treat as fatal for this attempt
|
// this is an error that we should treat as fatal for this attempt
|
||||||
return Err(PayloadBuilderError::EvmExecutionError(Box::new(err)))
|
return Err(PayloadBuilderError::EvmExecutionError(Box::new(err)))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let gas_used = result.gas_used();
|
|
||||||
|
|
||||||
// add gas used by the transaction to cumulative gas used, before creating the
|
// add gas used by the transaction to cumulative gas used, before creating the
|
||||||
// receipt
|
// receipt
|
||||||
info.cumulative_gas_used += gas_used;
|
info.cumulative_gas_used += gas_used;
|
||||||
info.cumulative_da_bytes_used += tx.length() as u64;
|
info.cumulative_da_bytes_used += tx.length() as u64;
|
||||||
|
|
||||||
// Push transaction changeset and calculate header bloom filter for receipt.
|
|
||||||
info.receipts.push(self.build_receipt(info, result, None, &tx));
|
|
||||||
|
|
||||||
// update add to total fees
|
// update add to total fees
|
||||||
let miner_fee = tx
|
let miner_fee = tx
|
||||||
.effective_tip_per_gas(base_fee)
|
.effective_tip_per_gas(base_fee)
|
||||||
|
|||||||
@ -13,7 +13,6 @@ workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# reth
|
# reth
|
||||||
reth-chainspec.workspace = true
|
|
||||||
reth-primitives.workspace = true
|
reth-primitives.workspace = true
|
||||||
reth-primitives-traits.workspace = true
|
reth-primitives-traits.workspace = true
|
||||||
reth-provider.workspace = true
|
reth-provider.workspace = true
|
||||||
@ -21,12 +20,8 @@ reth-payload-builder.workspace = true
|
|||||||
reth-payload-builder-primitives.workspace = true
|
reth-payload-builder-primitives.workspace = true
|
||||||
reth-payload-primitives.workspace = true
|
reth-payload-primitives.workspace = true
|
||||||
reth-tasks.workspace = true
|
reth-tasks.workspace = true
|
||||||
reth-evm.workspace = true
|
|
||||||
reth-revm.workspace = true
|
reth-revm.workspace = true
|
||||||
|
|
||||||
# revm
|
|
||||||
revm.workspace = true
|
|
||||||
|
|
||||||
# ethereum
|
# ethereum
|
||||||
alloy-primitives.workspace = true
|
alloy-primitives.workspace = true
|
||||||
alloy-consensus.workspace = true
|
alloy-consensus.workspace = true
|
||||||
|
|||||||
@ -9,22 +9,18 @@
|
|||||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||||
|
|
||||||
use crate::metrics::PayloadBuilderMetrics;
|
use crate::metrics::PayloadBuilderMetrics;
|
||||||
use alloy_consensus::constants::EMPTY_WITHDRAWALS;
|
use alloy_eips::merge::SLOT_DURATION;
|
||||||
use alloy_eips::{eip4895::Withdrawals, merge::SLOT_DURATION};
|
|
||||||
use alloy_primitives::{B256, U256};
|
use alloy_primitives::{B256, U256};
|
||||||
use futures_core::ready;
|
use futures_core::ready;
|
||||||
use futures_util::FutureExt;
|
use futures_util::FutureExt;
|
||||||
use reth_chainspec::EthereumHardforks;
|
|
||||||
use reth_evm::state_change::post_block_withdrawals_balance_increments;
|
|
||||||
use reth_payload_builder::{KeepPayloadJobAlive, PayloadId, PayloadJob, PayloadJobGenerator};
|
use reth_payload_builder::{KeepPayloadJobAlive, PayloadId, PayloadJob, PayloadJobGenerator};
|
||||||
use reth_payload_builder_primitives::PayloadBuilderError;
|
use reth_payload_builder_primitives::PayloadBuilderError;
|
||||||
use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes, PayloadKind};
|
use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes, PayloadKind};
|
||||||
use reth_primitives::{NodePrimitives, SealedHeader};
|
use reth_primitives::{NodePrimitives, SealedHeader};
|
||||||
use reth_primitives_traits::{proofs, HeaderTy};
|
use reth_primitives_traits::HeaderTy;
|
||||||
use reth_provider::{BlockReaderIdExt, CanonStateNotification, StateProviderFactory};
|
use reth_provider::{BlockReaderIdExt, CanonStateNotification, StateProviderFactory};
|
||||||
use reth_revm::{cached::CachedReads, cancelled::CancelOnDrop, db::State};
|
use reth_revm::{cached::CachedReads, cancelled::CancelOnDrop};
|
||||||
use reth_tasks::TaskSpawner;
|
use reth_tasks::TaskSpawner;
|
||||||
use revm::Database;
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
future::Future,
|
future::Future,
|
||||||
@ -881,37 +877,6 @@ impl<Payload> Default for MissingPayloadBehaviour<Payload> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes the withdrawals and commits them to the _runtime_ Database and `BundleState`.
|
|
||||||
///
|
|
||||||
/// Returns the withdrawals root.
|
|
||||||
///
|
|
||||||
/// Returns `None` values pre shanghai
|
|
||||||
pub fn commit_withdrawals<DB, ChainSpec>(
|
|
||||||
db: &mut State<DB>,
|
|
||||||
chain_spec: &ChainSpec,
|
|
||||||
timestamp: u64,
|
|
||||||
withdrawals: &Withdrawals,
|
|
||||||
) -> Result<Option<B256>, DB::Error>
|
|
||||||
where
|
|
||||||
DB: Database,
|
|
||||||
ChainSpec: EthereumHardforks,
|
|
||||||
{
|
|
||||||
if !chain_spec.is_shanghai_active_at_timestamp(timestamp) {
|
|
||||||
return Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
if withdrawals.is_empty() {
|
|
||||||
return Ok(Some(EMPTY_WITHDRAWALS))
|
|
||||||
}
|
|
||||||
|
|
||||||
let balance_increments =
|
|
||||||
post_block_withdrawals_balance_increments(chain_spec, timestamp, withdrawals);
|
|
||||||
|
|
||||||
db.increment_balances(balance_increments)?;
|
|
||||||
|
|
||||||
Ok(Some(proofs::calculate_withdrawals_root(withdrawals)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if the new payload is better than the current best.
|
/// Checks if the new payload is better than the current best.
|
||||||
///
|
///
|
||||||
/// This compares the total fees of the blocks, higher is better.
|
/// This compares the total fees of the blocks, higher is better.
|
||||||
|
|||||||
@ -136,8 +136,8 @@ where
|
|||||||
fn execute_transaction(
|
fn execute_transaction(
|
||||||
&mut self,
|
&mut self,
|
||||||
_tx: Recovered<&TransactionSigned>,
|
_tx: Recovered<&TransactionSigned>,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<u64, Self::Error> {
|
||||||
Ok(())
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_post_execution_changes(
|
fn apply_post_execution_changes(
|
||||||
|
|||||||
Reference in New Issue
Block a user