feat: BlockExecutionStrategy::execute_transaction API (#14586)

This commit is contained in:
Arsenii Kulikov
2025-02-19 18:03:13 +04:00
committed by GitHub
parent e51e109723
commit b9c81e4d94
4 changed files with 138 additions and 137 deletions

View File

@ -92,6 +92,8 @@ pub struct EthExecutionStrategy<'a, Evm, EvmConfig> {
evm: Evm, evm: Evm,
/// Receipts of executed transactions. /// Receipts of executed transactions.
receipts: Vec<Receipt>, receipts: Vec<Receipt>,
/// Total gas used by transactions in this block.
gas_used: u64,
/// Utility to call system smart contracts. /// Utility to call system smart contracts.
system_caller: SystemCaller<&'a ChainSpec>, system_caller: SystemCaller<&'a ChainSpec>,
} }
@ -108,6 +110,7 @@ impl<'a, Evm, EvmConfig> EthExecutionStrategy<'a, Evm, EvmConfig> {
factory, factory,
block, block,
receipts: Vec::new(), receipts: Vec::new(),
gas_used: 0,
system_caller: SystemCaller::new(&factory.chain_spec), system_caller: SystemCaller::new(&factory.chain_spec),
} }
} }
@ -132,15 +135,13 @@ where
Ok(()) Ok(())
} }
fn execute_transactions<'a>( fn execute_transaction(
&mut self, &mut self,
transactions: impl IntoIterator<Item = Recovered<&'a TransactionSigned>>, tx: Recovered<&TransactionSigned>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
let mut cumulative_gas_used = 0;
for (tx_index, tx) in transactions.into_iter().enumerate() {
// 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() - cumulative_gas_used; let block_available_gas = self.block.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(),
@ -158,12 +159,12 @@ where
BlockValidationError::EVM { hash: *hash, error: Box::new(err) } BlockValidationError::EVM { hash: *hash, error: Box::new(err) }
})?; })?;
self.system_caller self.system_caller
.on_state(StateChangeSource::Transaction(tx_index), &result_and_state.state); .on_state(StateChangeSource::Transaction(self.receipts.len()), &result_and_state.state);
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);
// append gas used // append gas used
cumulative_gas_used += result.gas_used(); self.gas_used += result.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 {
@ -171,10 +172,10 @@ where
// Success flag was added in `EIP-658: Embedding transaction status code in // Success flag was added in `EIP-658: Embedding transaction status code in
// receipts`. // receipts`.
success: result.is_success(), success: result.is_success(),
cumulative_gas_used, cumulative_gas_used: self.gas_used,
logs: result.into_logs(), logs: result.into_logs(),
}); });
}
Ok(()) Ok(())
} }

View File

@ -173,12 +173,10 @@ pub trait BlockExecutionStrategy {
/// Applies any necessary changes before executing the block's transactions. /// Applies any necessary changes before executing the block's transactions.
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error>; fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error>;
/// Executes all transactions in the block. /// Executes a single transaction and applies execution result to internal state.
fn execute_transactions<'a>( fn execute_transaction(
&mut self, &mut self,
transactions: impl IntoIterator< tx: Recovered<&<Self::Primitives as NodePrimitives>::SignedTx>,
Item = Recovered<&'a <Self::Primitives as NodePrimitives>::SignedTx>,
>,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
/// Applies any necessary changes after executing the block's transactions. /// Applies any necessary changes after executing the block's transactions.
@ -278,7 +276,9 @@ where
let mut strategy = self.strategy_factory.create_strategy(&mut self.db, block); let mut strategy = self.strategy_factory.create_strategy(&mut self.db, block);
strategy.apply_pre_execution_changes()?; strategy.apply_pre_execution_changes()?;
strategy.execute_transactions(block.transactions_recovered())?; for tx in block.transactions_recovered() {
strategy.execute_transaction(tx)?;
}
let result = strategy.apply_post_execution_changes()?; let result = strategy.apply_post_execution_changes()?;
self.db.merge_transitions(BundleRetention::Reverts); self.db.merge_transitions(BundleRetention::Reverts);
@ -298,7 +298,9 @@ where
strategy.with_state_hook(Some(Box::new(state_hook))); strategy.with_state_hook(Some(Box::new(state_hook)));
strategy.apply_pre_execution_changes()?; strategy.apply_pre_execution_changes()?;
strategy.execute_transactions(block.transactions_recovered())?; for tx in block.transactions_recovered() {
strategy.execute_transaction(tx)?;
}
let result = strategy.apply_post_execution_changes()?; let result = strategy.apply_post_execution_changes()?;
self.db.merge_transitions(BundleRetention::Reverts); self.db.merge_transitions(BundleRetention::Reverts);
@ -444,9 +446,9 @@ mod tests {
Ok(()) Ok(())
} }
fn execute_transactions<'a>( fn execute_transaction(
&mut self, &mut self,
_transactions: impl IntoIterator<Item = Recovered<&'a TransactionSigned>>, _tx: Recovered<&TransactionSigned>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
Ok(()) Ok(())
} }

View File

@ -106,6 +106,10 @@ pub struct OpExecutionStrategy<'a, Evm, N: NodePrimitives, ChainSpec, EvmConfig:
evm: Evm, evm: Evm,
/// Receipts of executed transactions. /// Receipts of executed transactions.
receipts: Vec<N::Receipt>, receipts: Vec<N::Receipt>,
/// Total gas used by executed transactions.
gas_used: u64,
/// Whether Regolith hardfork is active.
is_regolith: bool,
/// Utility to call system smart contracts. /// Utility to call system smart contracts.
system_caller: SystemCaller<&'a ChainSpec>, system_caller: SystemCaller<&'a ChainSpec>,
} }
@ -127,6 +131,8 @@ where
factory, factory,
block, block,
receipts: Vec::new(), receipts: Vec::new(),
gas_used: 0,
is_regolith: factory.chain_spec.is_regolith_active_at_timestamp(block.timestamp()),
system_caller: SystemCaller::new(&factory.chain_spec), system_caller: SystemCaller::new(&factory.chain_spec),
} }
} }
@ -165,18 +171,11 @@ where
Ok(()) Ok(())
} }
fn execute_transactions<'a>( fn execute_transaction(&mut self, tx: Recovered<&N::SignedTx>) -> Result<(), Self::Error> {
&mut self,
transactions: impl IntoIterator<Item = Recovered<&'a N::SignedTx>>,
) -> Result<(), Self::Error> {
let is_regolith = self.chain_spec.is_regolith_active_at_timestamp(self.block.timestamp());
let mut cumulative_gas_used = 0;
for (tx_index, tx) in transactions.into_iter().enumerate() {
// The sum of the transactions gas limit, Tg, and the gas utilized in this block prior, // The sum of the transactions gas limit, Tg, and the gas utilized in this block prior,
// must be no greater than the blocks gasLimit. // must be no greater than the blocks gasLimit.
let block_available_gas = self.block.gas_limit() - cumulative_gas_used; let block_available_gas = self.block.gas_limit() - self.gas_used;
if tx.gas_limit() > block_available_gas && (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(),
block_available_gas, block_available_gas,
@ -189,7 +188,7 @@ where
// Note that this *only* needs to be done post-regolith hardfork, as deposit nonces // Note that this *only* needs to be done post-regolith hardfork, as deposit nonces
// were not introduced in Bedrock. In addition, regular transactions don't have deposit // were not introduced in Bedrock. In addition, regular transactions don't have deposit
// nonces, so we don't need to touch the DB for those. // nonces, so we don't need to touch the DB for those.
let depositor = (is_regolith && tx.is_deposit()) let depositor = (self.is_regolith && tx.is_deposit())
.then(|| { .then(|| {
self.evm self.evm
.db_mut() .db_mut()
@ -214,18 +213,18 @@ where
"Executed transaction" "Executed transaction"
); );
self.system_caller self.system_caller
.on_state(StateChangeSource::Transaction(tx_index), &result_and_state.state); .on_state(StateChangeSource::Transaction(self.receipts.len()), &result_and_state.state);
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);
// append gas used // append gas used
cumulative_gas_used += result.gas_used(); self.gas_used += result.gas_used();
self.receipts.push( self.receipts.push(
match self.receipt_builder.build_receipt(ReceiptBuilderCtx { match self.receipt_builder.build_receipt(ReceiptBuilderCtx {
tx: tx.tx(), tx: tx.tx(),
result, result,
cumulative_gas_used, cumulative_gas_used: self.gas_used,
}) { }) {
Ok(receipt) => receipt, Ok(receipt) => receipt,
Err(ctx) => { Err(ctx) => {
@ -233,7 +232,7 @@ where
// Success flag was added in `EIP-658: Embedding transaction status code // Success flag was added in `EIP-658: Embedding transaction status code
// in receipts`. // in receipts`.
status: Eip658Value::Eip658(ctx.result.is_success()), status: Eip658Value::Eip658(ctx.result.is_success()),
cumulative_gas_used, cumulative_gas_used: self.gas_used,
logs: ctx.result.into_logs(), logs: ctx.result.into_logs(),
}; };
@ -253,7 +252,6 @@ where
} }
}, },
); );
}
Ok(()) Ok(())
} }

View File

@ -133,9 +133,9 @@ where
Ok(()) Ok(())
} }
fn execute_transactions<'a>( fn execute_transaction(
&mut self, &mut self,
_transactions: impl IntoIterator<Item = Recovered<&'a TransactionSigned>>, _tx: Recovered<&TransactionSigned>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
Ok(()) Ok(())
} }