sp1_cc_client_executor/
io.rs1use std::{fmt::Debug, iter::once, sync::Arc};
12
13use alloy_consensus::ReceiptEnvelope;
14use alloy_evm::{Database, Evm};
15use reth_chainspec::ChainSpec;
16use reth_consensus::{ConsensusError, HeaderValidator};
17use reth_ethereum_consensus::EthBeaconConsensus;
18use reth_evm::{ConfigureEvm, EthEvm, EvmEnv};
19use reth_evm_ethereum::EthEvmConfig;
20use reth_primitives::{EthPrimitives, Header, NodePrimitives, SealedHeader};
21use revm::{
22 context::result::{HaltReason, ResultAndState},
23 inspector::NoOpInspector,
24 state::Bytecode,
25 Context, MainBuilder, MainContext,
26};
27use revm_primitives::{Address, HashMap, B256, U256};
28use rsp_client_executor::{error::ClientError, io::WitnessInput};
29use rsp_mpt::EthereumState;
30use rsp_primitives::genesis::Genesis;
31use serde::{Deserialize, Serialize};
32use serde_with::serde_as;
33
34use crate::{Anchor, ContractInput};
35
36#[serde_as]
42#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
43pub struct EvmSketchInput {
44 pub anchor: Anchor,
46 pub genesis: Genesis,
48 #[serde_as(as = "Vec<alloy_consensus::serde_bincode_compat::Header>")]
51 pub ancestor_headers: Vec<Header>,
52 pub state: EthereumState,
54 pub state_requests: HashMap<Address, Vec<U256>>,
56 pub bytecodes: Vec<Bytecode>,
58 #[serde_as(as = "Option<Vec<alloy_consensus::serde_bincode_compat::ReceiptEnvelope>>")]
60 pub receipts: Option<Vec<ReceiptEnvelope>>,
61}
62
63impl WitnessInput for EvmSketchInput {
64 #[inline(always)]
65 fn state(&self) -> &EthereumState {
66 &self.state
67 }
68
69 #[inline(always)]
70 fn state_anchor(&self) -> B256 {
71 self.anchor.header().state_root
72 }
73
74 #[inline(always)]
75 fn state_requests(&self) -> impl Iterator<Item = (&Address, &Vec<U256>)> {
76 self.state_requests.iter()
77 }
78
79 #[inline(always)]
80 fn bytecodes(&self) -> impl Iterator<Item = &Bytecode> {
81 self.bytecodes.iter()
82 }
83
84 #[inline(always)]
85 fn sealed_headers(&self) -> impl Iterator<Item = SealedHeader> {
86 once(SealedHeader::seal_slow(self.anchor.header().clone()))
87 .chain(self.ancestor_headers.iter().map(|h| SealedHeader::seal_slow(h.clone())))
88 }
89}
90
91pub trait Primitives: NodePrimitives {
92 type ChainSpec: Debug;
93 type HaltReason: Debug;
94
95 fn build_spec(genesis: &Genesis) -> Result<Arc<Self::ChainSpec>, ClientError>;
96
97 fn validate_header(
98 header: &SealedHeader,
99 chain_spec: Arc<Self::ChainSpec>,
100 ) -> Result<(), ConsensusError>;
101
102 fn transact<DB>(
103 input: &ContractInput,
104 db: DB,
105 header: &Header,
106 difficulty: U256,
107 chain_spec: Arc<Self::ChainSpec>,
108 ) -> Result<ResultAndState<Self::HaltReason>, String>
109 where
110 DB: Database;
111}
112
113impl Primitives for EthPrimitives {
114 type ChainSpec = ChainSpec;
115 type HaltReason = HaltReason;
116
117 fn build_spec(genesis: &Genesis) -> Result<Arc<Self::ChainSpec>, ClientError> {
118 Ok(Arc::new(ChainSpec::try_from(genesis).unwrap()))
119 }
120
121 fn validate_header(
122 header: &SealedHeader,
123 chain_spec: Arc<Self::ChainSpec>,
124 ) -> Result<(), ConsensusError> {
125 let validator = EthBeaconConsensus::new(chain_spec);
126 validator.validate_header(header)
127 }
128
129 fn transact<DB: Database>(
130 input: &ContractInput,
131 db: DB,
132 header: &Header,
133 difficulty: U256,
134 chain_spec: Arc<Self::ChainSpec>,
135 ) -> Result<ResultAndState<Self::HaltReason>, String> {
136 let EvmEnv { mut cfg_env, mut block_env, .. } =
137 EthEvmConfig::new(chain_spec).evm_env(header);
138
139 block_env.basefee = 0;
141 block_env.difficulty = difficulty;
142 cfg_env.disable_nonce_check = true;
143 cfg_env.disable_balance_check = true;
144
145 let evm = Context::mainnet()
146 .with_db(db)
147 .with_cfg(cfg_env)
148 .with_block(block_env)
149 .modify_tx_chained(|tx_env| {
150 tx_env.gas_limit = header.gas_limit;
151 })
152 .build_mainnet_with_inspector(NoOpInspector {});
153
154 let mut evm = EthEvm::new(evm, false);
155
156 evm.transact(input).map_err(|err| err.to_string())
157 }
158}
159
160#[cfg(feature = "optimism")]
161impl Primitives for reth_optimism_primitives::OpPrimitives {
162 type ChainSpec = reth_optimism_chainspec::OpChainSpec;
163 type HaltReason = op_revm::OpHaltReason;
164
165 fn build_spec(genesis: &Genesis) -> Result<Arc<Self::ChainSpec>, ClientError> {
166 Ok(Arc::new(reth_optimism_chainspec::OpChainSpec::try_from(genesis).unwrap()))
167 }
168
169 fn validate_header(
170 header: &SealedHeader,
171 chain_spec: Arc<Self::ChainSpec>,
172 ) -> Result<(), ConsensusError> {
173 let validator = reth_optimism_consensus::OpBeaconConsensus::new(chain_spec);
174 validator.validate_header(header)
175 }
176
177 fn transact<DB: Database>(
178 input: &ContractInput,
179 db: DB,
180 header: &Header,
181 difficulty: U256,
182 chain_spec: Arc<Self::ChainSpec>,
183 ) -> Result<ResultAndState<Self::HaltReason>, String> {
184 use op_revm::{DefaultOp, OpBuilder};
185
186 let EvmEnv { mut cfg_env, mut block_env, .. } =
187 reth_optimism_evm::OpEvmConfig::optimism(chain_spec).evm_env(header);
188
189 block_env.basefee = 0;
191 block_env.difficulty = difficulty;
192 cfg_env.disable_nonce_check = true;
193 cfg_env.disable_balance_check = true;
194
195 let evm = op_revm::OpContext::op()
196 .with_db(db)
197 .with_cfg(cfg_env)
198 .with_block(block_env)
199 .modify_tx_chained(|tx_env| {
200 tx_env.base.gas_limit = header.gas_limit;
201 })
202 .build_op_with_inspector(NoOpInspector {});
203
204 let mut evm = alloy_op_evm::OpEvm::new(evm, false);
205
206 evm.transact(input).map_err(|err| err.to_string())
207 }
208}