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, EthChainSpec};
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, 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 bytecodes: Vec<Bytecode>,
56 #[serde_as(as = "Option<Vec<alloy_consensus::serde_bincode_compat::ReceiptEnvelope>>")]
58 pub receipts: Option<Vec<ReceiptEnvelope>>,
59}
60
61impl WitnessInput for EvmSketchInput {
62 #[inline(always)]
63 fn state(&self) -> &EthereumState {
64 &self.state
65 }
66
67 #[inline(always)]
68 fn state_anchor(&self) -> B256 {
69 self.anchor.header().state_root
70 }
71
72 #[inline(always)]
73 fn state_requests(&self) -> impl Iterator<Item = (&Address, &Vec<U256>)> {
74 if true {
76 unimplemented!()
77 } else {
78 std::iter::empty()
79 }
80 }
81
82 #[inline(always)]
83 fn bytecodes(&self) -> impl Iterator<Item = &Bytecode> {
84 self.bytecodes.iter()
85 }
86
87 #[inline(always)]
88 fn sealed_headers(&self) -> impl Iterator<Item = SealedHeader> {
89 once(SealedHeader::seal_slow(self.anchor.header().clone()))
90 .chain(self.ancestor_headers.iter().map(|h| SealedHeader::seal_slow(h.clone())))
91 }
92}
93
94pub trait Primitives: NodePrimitives {
95 type ChainSpec: EthChainSpec + Debug;
96 type HaltReason: Debug;
97
98 fn build_spec(genesis: &Genesis) -> Result<Arc<Self::ChainSpec>, ClientError>;
99
100 fn validate_header(
101 header: &SealedHeader,
102 chain_spec: Arc<Self::ChainSpec>,
103 ) -> Result<(), ConsensusError>;
104
105 fn transact<DB>(
106 input: &ContractInput,
107 db: DB,
108 header: &Header,
109 difficulty: U256,
110 chain_spec: Arc<Self::ChainSpec>,
111 ) -> Result<ResultAndState<Self::HaltReason>, String>
112 where
113 DB: Database;
114
115 fn active_fork_name(chain_spec: &Self::ChainSpec, header: &Header) -> String;
116}
117
118impl Primitives for EthPrimitives {
119 type ChainSpec = ChainSpec;
120 type HaltReason = HaltReason;
121
122 fn build_spec(genesis: &Genesis) -> Result<Arc<Self::ChainSpec>, ClientError> {
123 Ok(Arc::new(ChainSpec::try_from(genesis).unwrap()))
124 }
125
126 fn validate_header(
127 header: &SealedHeader,
128 chain_spec: Arc<Self::ChainSpec>,
129 ) -> Result<(), ConsensusError> {
130 let validator = EthBeaconConsensus::new(chain_spec);
131 validator.validate_header(header)
132 }
133
134 fn transact<DB: Database>(
135 input: &ContractInput,
136 db: DB,
137 header: &Header,
138 difficulty: U256,
139 chain_spec: Arc<Self::ChainSpec>,
140 ) -> Result<ResultAndState<Self::HaltReason>, String> {
141 let EvmEnv { mut cfg_env, mut block_env, .. } =
142 EthEvmConfig::new(chain_spec).evm_env(header);
143
144 block_env.basefee = 0;
146 block_env.difficulty = difficulty;
147 cfg_env.disable_nonce_check = true;
148 cfg_env.disable_balance_check = true;
149
150 let evm = Context::mainnet()
151 .with_db(db)
152 .with_cfg(cfg_env)
153 .with_block(block_env)
154 .modify_tx_chained(|tx_env| {
155 tx_env.gas_limit = header.gas_limit;
156 })
157 .build_mainnet_with_inspector(NoOpInspector {});
158
159 let mut evm = EthEvm::new(evm, false);
160
161 evm.transact(input).map_err(|err| err.to_string())
162 }
163
164 fn active_fork_name(chain_spec: &Self::ChainSpec, header: &Header) -> String {
165 let spec = reth_evm_ethereum::revm_spec(chain_spec, header);
166
167 spec.to_string()
168 }
169}
170
171#[cfg(feature = "optimism")]
172impl Primitives for reth_optimism_primitives::OpPrimitives {
173 type ChainSpec = reth_optimism_chainspec::OpChainSpec;
174 type HaltReason = op_revm::OpHaltReason;
175
176 fn build_spec(genesis: &Genesis) -> Result<Arc<Self::ChainSpec>, ClientError> {
177 Ok(Arc::new(reth_optimism_chainspec::OpChainSpec::try_from(genesis).unwrap()))
178 }
179
180 fn validate_header(
181 header: &SealedHeader,
182 chain_spec: Arc<Self::ChainSpec>,
183 ) -> Result<(), ConsensusError> {
184 let validator = reth_optimism_consensus::OpBeaconConsensus::new(chain_spec);
185 validator.validate_header(header)
186 }
187
188 fn transact<DB: Database>(
189 input: &ContractInput,
190 db: DB,
191 header: &Header,
192 difficulty: U256,
193 chain_spec: Arc<Self::ChainSpec>,
194 ) -> Result<ResultAndState<Self::HaltReason>, String> {
195 use op_revm::{DefaultOp, OpBuilder};
196
197 let EvmEnv { mut cfg_env, mut block_env, .. } =
198 reth_optimism_evm::OpEvmConfig::optimism(chain_spec).evm_env(header);
199
200 block_env.basefee = 0;
202 block_env.difficulty = difficulty;
203 cfg_env.disable_nonce_check = true;
204 cfg_env.disable_balance_check = true;
205
206 let evm = op_revm::OpContext::op()
207 .with_db(db)
208 .with_cfg(cfg_env)
209 .with_block(block_env)
210 .modify_tx_chained(|tx_env| {
211 tx_env.base.gas_limit = header.gas_limit;
212 })
213 .build_op_with_inspector(NoOpInspector {});
214
215 let mut evm = alloy_op_evm::OpEvm::new(evm, false);
216
217 evm.transact(input).map_err(|err| err.to_string())
218 }
219
220 fn active_fork_name(chain_spec: &Self::ChainSpec, header: &Header) -> String {
221 let spec = reth_optimism_evm::revm_spec(chain_spec, header);
222 let spec: &'static str = spec.into();
223
224 spec.to_string()
225 }
226}