Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(evm): EIP-7002 withdrawal requests #8212

Merged
merged 23 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6a0f553
feat(evm): EIP-7002 withdrawal requests
shekhirin May 12, 2024
602bd89
Merge remote-tracking branch 'origin/main' into alexey/eip-7002-withd…
shekhirin May 12, 2024
8e1c172
make it compile
shekhirin May 13, 2024
a58710c
reorder requests field
shekhirin May 13, 2024
e546045
rename the execute method
shekhirin May 13, 2024
d5dc0b1
fix lints
shekhirin May 13, 2024
c876c5b
return from impl gated under test-utils
shekhirin May 13, 2024
71c3338
add comments to the fill_tx_env_with_system_contract_call
shekhirin May 13, 2024
dbfdbc8
remove unused deps and imports
shekhirin May 13, 2024
45d54ce
Merge remote-tracking branch 'origin/devnet-0' into alexey/eip-7002-w…
shekhirin May 13, 2024
d4e48b5
Cargo.lock
shekhirin May 13, 2024
1083d06
Merge remote-tracking branch 'origin/devnet-0' into alexey/eip-7002-w…
shekhirin May 13, 2024
0d17302
change return args order
shekhirin May 13, 2024
b5016e0
Cargo.lock
shekhirin May 13, 2024
3b6dc03
Merge remote-tracking branch 'origin/devnet-0' into alexey/eip-7002-w…
shekhirin May 13, 2024
daedecb
introduce Requests struct
shekhirin May 13, 2024
f50b10c
add a helper type
shekhirin May 13, 2024
b08f642
Merge remote-tracking branch 'origin/devnet-0' into alexey/eip-7002-w…
shekhirin May 13, 2024
8334ee3
Merge remote-tracking branch 'origin/devnet-0' into alexey/eip-7002-w…
shekhirin May 13, 2024
8a223df
Merge remote-tracking branch 'origin/devnet-0' into alexey/eip-7002-w…
shekhirin May 13, 2024
49f2c03
fix optimism execute.rs
shekhirin May 13, 2024
8c3e3a1
Merge remote-tracking branch 'origin/devnet-0' into alexey/eip-7002-w…
shekhirin May 13, 2024
4d518fd
no mutable EVM borrow
shekhirin May 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion bin/reth/src/commands/debug_cmd/merkle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ impl Command {
PruneModes::none(),
);
executor.execute_one((&sealed_block.clone().unseal(), td).into())?;
let BatchBlockExecutionOutput { bundle, receipts, first_block } = executor.finalize();
let BatchBlockExecutionOutput { bundle, receipts, requests: _, first_block } =
executor.finalize();
BundleStateWithReceipts::new(bundle, receipts, first_block).write_to_storage(
provider_rw.tx_ref(),
None,
Expand Down
2 changes: 1 addition & 1 deletion crates/config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl Config {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("reth config file extension must be '{EXTENSION}'"),
));
))
}
confy::store_path(path, self).map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
}
Expand Down
4 changes: 2 additions & 2 deletions crates/e2e-test-utils/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ impl<E: EngineTypes + 'static> PayloadTestContext<E> {
let payload = self.payload_builder.best_payload(payload_id).await.unwrap().unwrap();
if payload.block().body.is_empty() {
tokio::time::sleep(std::time::Duration::from_millis(20)).await;
continue;
continue
}
break;
break
}
}

Expand Down
3 changes: 3 additions & 0 deletions crates/ethereum/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ revm-interpreter.workspace = true

revm-precompile = { version = "7.0.0", features = ["std"], default-features = false }

# Alloy
alloy-consensus.workspace = true

# misc
tracing.workspace = true

Expand Down
65 changes: 44 additions & 21 deletions crates/ethereum/evm/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{
verify::verify_receipts,
EthEvmConfig,
};
use alloy_consensus::Request;
use reth_evm::{
execute::{
BatchBlockExecutionOutput, BatchExecutor, BlockExecutionInput, BlockExecutionOutput,
Expand All @@ -25,6 +26,7 @@ use reth_revm::{
db::states::bundle_state::BundleRetention,
state_change::{
apply_beacon_root_contract_call, apply_blockhashes_update, post_block_balance_increments,
post_block_withdrawal_requests,
},
Evm, State,
};
Expand Down Expand Up @@ -105,6 +107,14 @@ where
}
}

/// Helper type for the output of executing a block.
#[derive(Debug, Clone)]
struct EthExecuteOutput {
Comment on lines +110 to +112
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will combine this with the other output types separately

receipts: Vec<Receipt>,
requests: Vec<Request>,
gas_used: u64,
}

/// Helper container type for EVM with chain spec.
#[derive(Debug, Clone)]
struct EthEvmExecutor<EvmConfig> {
Expand All @@ -118,18 +128,21 @@ impl<EvmConfig> EthEvmExecutor<EvmConfig>
where
EvmConfig: ConfigureEvm,
{
/// Executes the transactions in the block and returns the receipts.
/// Executes the transactions in the block and returns the receipts of the transactions in the
/// block, the total gas used and the list of EIP-7685 [requests](Request).
///
/// This applies the pre-execution changes, and executes the transactions.
/// This applies the pre-execution and post-execution changes that require an [EVM](Evm), and
/// executes the transactions.
///
/// # Note
///
/// It does __not__ apply post-execution changes.
fn execute_pre_and_transactions<Ext, DB>(
/// It does __not__ apply post-execution changes that do not require an [EVM](Evm), for that see
/// [EthBlockExecutor::post_execution].
fn execute_state_transitions<Ext, DB>(
&self,
block: &BlockWithSenders,
mut evm: Evm<'_, Ext, &mut State<DB>>,
) -> Result<(Vec<Receipt>, u64), BlockExecutionError>
) -> Result<EthExecuteOutput, BlockExecutionError>
where
DB: Database<Error = ProviderError>,
{
Expand All @@ -155,7 +168,7 @@ where
transaction_gas_limit: transaction.gas_limit(),
block_available_gas,
}
.into());
.into())
}

EvmConfig::fill_tx_env(evm.tx_mut(), transaction, *sender);
Expand Down Expand Up @@ -188,7 +201,6 @@ where
},
);
}
drop(evm);

// Check if gas used matches the value set in header.
if block.gas_used != cumulative_gas_used {
Expand All @@ -197,10 +209,15 @@ where
gas: GotExpected { got: cumulative_gas_used, expected: block.gas_used },
gas_spent_by_tx: receipts.gas_spent_by_tx()?,
}
.into());
.into())
}

Ok((receipts, cumulative_gas_used))
// Collect all EIP-7685 requests
let withdrawal_requests =
post_block_withdrawal_requests(&self.chain_spec, block.timestamp, &mut evm)?;
let requests = withdrawal_requests;

Ok(EthExecuteOutput { receipts, requests, gas_used: cumulative_gas_used })
}
}

Expand Down Expand Up @@ -261,23 +278,23 @@ where

/// Execute a single block and apply the state changes to the internal state.
///
/// Returns the receipts of the transactions in the block and the total gas used.
/// Returns the receipts of the transactions in the block, the total gas used and the list of
/// EIP-7685 [requests](Request).
///
/// Returns an error if execution fails or receipt verification fails.
fn execute_and_verify(
&mut self,
block: &BlockWithSenders,
total_difficulty: U256,
) -> Result<(Vec<Receipt>, u64), BlockExecutionError> {
) -> Result<EthExecuteOutput, BlockExecutionError> {
// 1. prepare state on new block
self.on_new_block(&block.header);

// 2. configure the evm and execute
let env = self.evm_env_for_block(&block.header, total_difficulty);

let (receipts, gas_used) = {
let EthExecuteOutput { receipts, requests, gas_used } = {
let evm = self.executor.evm_config.evm_with_env(&mut self.state, env);
self.executor.execute_pre_and_transactions(block, evm)
self.executor.execute_state_transitions(block, evm)
}?;

// 3. apply post execution changes
Expand All @@ -294,11 +311,11 @@ where
receipts.iter(),
) {
debug!(target: "evm", %error, ?receipts, "receipts verification failed");
return Err(error);
return Err(error)
};
}

Ok((receipts, gas_used))
Ok(EthExecuteOutput { receipts, requests, gas_used })
}

/// Apply settings before a new block is executed.
Expand All @@ -308,8 +325,8 @@ where
self.state.set_state_clear_flag(state_clear_flag);
}

/// Apply post execution state changes, including block rewards, withdrawals, and irregular DAO
/// hardfork state change.
/// Apply post execution state changes that do not require an [EVM](Evm), such as: block
/// rewards, withdrawals, and irregular DAO hardfork state change
pub fn post_execution(
&mut self,
block: &BlockWithSenders,
Expand Down Expand Up @@ -366,12 +383,13 @@ where
/// State changes are committed to the database.
fn execute(mut self, input: Self::Input<'_>) -> Result<Self::Output, Self::Error> {
let BlockExecutionInput { block, total_difficulty } = input;
let (receipts, gas_used) = self.execute_and_verify(block, total_difficulty)?;
let EthExecuteOutput { receipts, requests, gas_used } =
self.execute_and_verify(block, total_difficulty)?;

// NOTE: we need to merge keep the reverts for the bundle retention
self.state.merge_transitions(BundleRetention::Reverts);

Ok(BlockExecutionOutput { state: self.state.take_bundle(), receipts, gas_used })
Ok(BlockExecutionOutput { state: self.state.take_bundle(), receipts, requests, gas_used })
}
}

Expand Down Expand Up @@ -408,7 +426,8 @@ where

fn execute_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> {
let BlockExecutionInput { block, total_difficulty } = input;
let (receipts, _gas_used) = self.executor.execute_and_verify(block, total_difficulty)?;
let EthExecuteOutput { receipts, requests, gas_used: _ } =
self.executor.execute_and_verify(block, total_difficulty)?;

// prepare the state according to the prune mode
let retention = self.batch_record.bundle_retention(block.number);
Expand All @@ -417,6 +436,9 @@ where
// store receipts in the set
self.batch_record.save_receipts(receipts)?;

// store requests in the set
self.batch_record.save_requests(requests);

if self.batch_record.first_block().is_none() {
self.batch_record.set_first_block(block.number);
}
Expand All @@ -430,6 +452,7 @@ where
BatchBlockExecutionOutput::new(
self.executor.state.take_bundle(),
self.batch_record.take_receipts(),
self.batch_record.take_requests(),
self.batch_record.first_block().unwrap_or_default(),
)
}
Expand Down
10 changes: 5 additions & 5 deletions crates/ethereum/evm/src/instructions/eip3074.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,13 @@ fn auth_instruction<EXT, DB: Database>(
ctx.remove(AUTHORIZED_VAR_NAME);
push!(interp, B256::ZERO.into());
interp.instruction_result = InstructionResult::Continue;
return;
return
}
acc
}
Err(_) => {
interp.instruction_result = InstructionResult::Revert;
return;
return
}
};
let nonce = authority_account.0.info.nonce;
Expand All @@ -132,7 +132,7 @@ fn auth_instruction<EXT, DB: Database>(
Ok(signer) => signer,
Err(_) => {
interp.instruction_result = InstructionResult::Revert;
return;
return
}
};

Expand Down Expand Up @@ -164,7 +164,7 @@ fn authcall_instruction<EXT, DB: Database>(
Some(address) => Address::from_slice(&address),
None => {
interp.instruction_result = InstructionResult::Revert;
return;
return
}
};

Expand All @@ -181,7 +181,7 @@ fn authcall_instruction<EXT, DB: Database>(
pop!(interp, value);
if interp.is_static && value != U256::ZERO {
interp.instruction_result = InstructionResult::CallNotAllowedInsideStatic;
return;
return
}

let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interp) else {
Expand Down
5 changes: 4 additions & 1 deletion crates/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ revm-primitives.workspace = true
revm.workspace = true
reth-interfaces.workspace = true

# alloy
alloy-consensus.workspace = true

futures-util.workspace = true
parking_lot = { workspace = true, optional = true }

[dev-dependencies]
parking_lot.workspace = true

[features]
test-utils = ["dep:parking_lot"]
test-utils = ["dep:parking_lot"]
23 changes: 20 additions & 3 deletions crates/evm/src/execute.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//! Traits for execution.

use alloy_consensus::Request;
use reth_interfaces::{executor::BlockExecutionError, provider::ProviderError};
use reth_primitives::{BlockNumber, BlockWithSenders, PruneModes, Receipt, Receipts, U256};
use reth_primitives::{
BlockNumber, BlockWithSenders, PruneModes, Receipt, Receipts, Requests, U256,
};
use revm::db::BundleState;
use revm_primitives::db::Database;

Expand Down Expand Up @@ -80,6 +83,8 @@ pub struct BlockExecutionOutput<T> {
pub state: BundleState,
/// All the receipts of the transactions in the block.
pub receipts: Vec<T>,
/// All the EIP-7685 requests of the transactions in the block.
pub requests: Vec<Request>,
Comment on lines +86 to +87
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is fine for now

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how would you improve it?

/// The total gas used by the block.
pub gas_used: u64,
}
Expand All @@ -95,14 +100,26 @@ pub struct BatchBlockExecutionOutput {
///
/// If receipt is None it means it is pruned.
pub receipts: Receipts,
/// The collection of EIP-7685 requests.
/// Outer vector stores requests for each block sequentially.
/// The inner vector stores requests ordered by transaction number.
///
/// A transaction may have zero or more requests, so the length of the inner vector is not
/// guaranteed to be the same as the number of transactions.
pub requests: Requests,
/// First block of bundle state.
pub first_block: BlockNumber,
}

impl BatchBlockExecutionOutput {
/// Create Bundle State.
pub fn new(bundle: BundleState, receipts: Receipts, first_block: BlockNumber) -> Self {
Self { bundle, receipts, first_block }
pub fn new(
bundle: BundleState,
receipts: Receipts,
requests: Requests,
first_block: BlockNumber,
) -> Self {
Self { bundle, receipts, requests, first_block }
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/evm/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ impl<DB> Executor<DB> for MockExecutorProvider {
state: bundle,
receipts: receipts.into_iter().flatten().flatten().collect(),
gas_used: 0,
requests: vec![],
})
}
}
Expand Down
Loading
Loading