Skip to content

Commit 3819ce0

Browse files
refcellbyteflyfunny
authored andcommitted
feat(executor): EIP-7251 Syscall Support [ISTHMUS] (op-rs#968)
1 parent fea3c75 commit 3819ce0

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed
+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
//! Contains the logic for the EIP-7251 syscall.
2+
3+
use crate::{
4+
db::TrieDB,
5+
errors::{ExecutorError, ExecutorResult},
6+
TrieDBProvider,
7+
};
8+
use alloc::{boxed::Box, vec::Vec};
9+
use alloy_primitives::{Address, Bytes, U256};
10+
use kona_mpt::TrieHinter;
11+
use maili_genesis::RollupConfig;
12+
use op_alloy_rpc_types_engine::OpPayloadAttributes;
13+
use revm::{
14+
db::State,
15+
primitives::{
16+
BlockEnv, CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg, OptimismFields, TransactTo, TxEnv,
17+
},
18+
DatabaseCommit, Evm,
19+
};
20+
21+
/// Execute the EIP-7251 pre-block beacon root contract call.
22+
pub(crate) fn pre_block_consolidation_requests_contract_call<F, H>(
23+
db: &mut State<&mut TrieDB<F, H>>,
24+
config: &RollupConfig,
25+
initialized_cfg: &CfgEnvWithHandlerCfg,
26+
initialized_block_env: &BlockEnv,
27+
payload: &OpPayloadAttributes,
28+
) -> ExecutorResult<()>
29+
where
30+
F: TrieDBProvider,
31+
H: TrieHinter,
32+
{
33+
let mut evm_pre_block = Evm::builder()
34+
.with_db(db)
35+
.with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env(
36+
initialized_cfg.clone(),
37+
initialized_block_env.clone(),
38+
Default::default(),
39+
))
40+
.build();
41+
42+
// initialize a block from the env, because the pre block call needs the block itself
43+
apply_consolidation_requests_contract_call(
44+
config,
45+
payload.payload_attributes.timestamp,
46+
&mut evm_pre_block,
47+
)
48+
}
49+
50+
/// Apply the EIP-7251 pre-block consolidation requests contract call to a given EVM instance.
51+
fn apply_consolidation_requests_contract_call<F, H>(
52+
config: &RollupConfig,
53+
timestamp: u64,
54+
evm: &mut Evm<'_, (), &mut State<&mut TrieDB<F, H>>>,
55+
) -> ExecutorResult<()>
56+
where
57+
F: TrieDBProvider,
58+
H: TrieHinter,
59+
{
60+
if !config.is_isthmus_active(timestamp) {
61+
return Ok(());
62+
}
63+
64+
// Get the previous environment
65+
let previous_env = Box::new(evm.context.evm.env().clone());
66+
67+
// modify env for pre block call
68+
fill_tx_env_with_consolidation_requests_contract_call(&mut evm.context.evm.env);
69+
70+
let mut state = match evm.transact() {
71+
Ok(res) => res.state,
72+
Err(e) => {
73+
evm.context.evm.env = previous_env;
74+
return Err(ExecutorError::ExecutionError(e));
75+
}
76+
};
77+
78+
state.remove(&alloy_eips::eip7002::SYSTEM_ADDRESS);
79+
state.remove(&evm.block().coinbase);
80+
81+
evm.context.evm.db.commit(state);
82+
83+
// re-set the previous env
84+
evm.context.evm.env = previous_env;
85+
86+
Ok(())
87+
}
88+
89+
/// Fill transaction environment with the EIP-7251 system contract message data.
90+
///
91+
/// This requirements for the beacon root contract call are defined by
92+
/// [EIP-7251](https://eips.ethereum.org/EIPS/eip-7251).
93+
fn fill_tx_env_with_consolidation_requests_contract_call(env: &mut Env) {
94+
fill_tx_env_with_system_contract_call(
95+
env,
96+
alloy_eips::eip7002::SYSTEM_ADDRESS,
97+
alloy_eips::eip7251::CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS,
98+
Bytes::new(),
99+
);
100+
}
101+
102+
/// Fill transaction environment with the system caller and the system contract address and message
103+
/// data.
104+
///
105+
/// This is a system operation and therefore:
106+
/// * the call must execute to completion
107+
/// * the call does not count against the block’s gas limit
108+
/// * the call does not follow the EIP-1559 burn semantics - no value should be transferred as part
109+
/// of the call
110+
/// * if no code exists at the provided address, the call will fail silently
111+
fn fill_tx_env_with_system_contract_call(
112+
env: &mut Env,
113+
caller: Address,
114+
contract: Address,
115+
data: Bytes,
116+
) {
117+
env.tx = TxEnv {
118+
caller,
119+
transact_to: TransactTo::Call(contract),
120+
// Explicitly set nonce to None so revm does not do any nonce checks
121+
nonce: None,
122+
gas_limit: 30_000_000,
123+
value: U256::ZERO,
124+
data,
125+
// Setting the gas price to zero enforces that no value is transferred as part of the call,
126+
// and that the call will not count against the block's gas limit
127+
gas_price: U256::ZERO,
128+
// The chain ID check is not relevant here and is disabled if set to None
129+
chain_id: None,
130+
// Setting the gas priority fee to None ensures the effective gas price is derived from the
131+
// `gas_price` field, which we need to be zero
132+
gas_priority_fee: None,
133+
access_list: Vec::new(),
134+
authorization_list: None,
135+
// blob fields can be None for this tx
136+
blob_hashes: Vec::new(),
137+
max_fee_per_blob_gas: None,
138+
optimism: OptimismFields {
139+
source_hash: None,
140+
mint: None,
141+
is_system_transaction: Some(false),
142+
// The L1 fee is not charged for the EIP-7251 transaction, submit zero bytes for the
143+
// enveloped tx size.
144+
enveloped_tx: Some(Bytes::default()),
145+
},
146+
};
147+
148+
// ensure the block gas limit is >= the tx
149+
env.block.gas_limit = U256::from(env.tx.gas_limit);
150+
151+
// disable the base fee check for this call by setting the base fee to zero
152+
env.block.basefee = U256::ZERO;
153+
}

crates/executor/src/syscalls/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ pub(crate) use eip2935::pre_block_block_hash_contract_call;
66
mod eip7002;
77
pub(crate) use eip7002::pre_block_withdrawals_request_contract_call;
88

9+
mod eip7251;
10+
pub(crate) use eip7251::pre_block_consolidation_requests_contract_call;
11+
912
mod eip4788;
1013
pub(crate) use eip4788::pre_block_beacon_root_contract_call;
1114

0 commit comments

Comments
 (0)