Skip to content

Commit 76404e6

Browse files
feat: implement state overrides for EVM calls
1 parent 5276792 commit 76404e6

File tree

16 files changed

+369
-50
lines changed

16 files changed

+369
-50
lines changed

common/src/network_spec.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
use std::{collections::HashMap, fmt::Debug, sync::Arc};
22

3-
use alloy::{eips::BlockId, network::Network, primitives::Address, rpc::types::Log};
3+
use alloy::{
4+
eips::BlockId,
5+
network::Network,
6+
primitives::Address,
7+
rpc::types::{state::StateOverride, Log},
8+
};
49
use async_trait::async_trait;
510
use revm::context::result::ExecutionResult;
611

@@ -27,5 +32,6 @@ pub trait NetworkSpec: Network {
2732
chain_id: u64,
2833
fork_schedule: ForkSchedule,
2934
block_id: BlockId,
35+
state_overrides: Option<StateOverride>,
3036
) -> Result<(ExecutionResult<Self::HaltReason>, HashMap<Address, Account>), EvmError>;
3137
}

core/src/client/api.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use alloy::{
22
eips::BlockId,
33
primitives::{Address, Bytes, B256, U256},
4-
rpc::types::{AccessListResult, EIP1186AccountProofResponse, Filter, Log, SyncStatus},
4+
rpc::types::{
5+
state::StateOverride, AccessListResult, EIP1186AccountProofResponse, Filter, Log,
6+
SyncStatus,
7+
},
58
};
69
use async_trait::async_trait;
710
use eyre::Result;
@@ -53,12 +56,23 @@ pub trait HeliosApi<N: NetworkSpec>: Send + Sync + 'static {
5356
block_id: BlockId,
5457
) -> Result<Option<Vec<N::ReceiptResponse>>>;
5558
// evm
56-
async fn call(&self, tx: &N::TransactionRequest, block_id: BlockId) -> Result<Bytes>;
57-
async fn estimate_gas(&self, tx: &N::TransactionRequest, block_id: BlockId) -> Result<u64>;
59+
async fn call(
60+
&self,
61+
tx: &N::TransactionRequest,
62+
block_id: BlockId,
63+
state_overrides: Option<StateOverride>,
64+
) -> Result<Bytes>;
65+
async fn estimate_gas(
66+
&self,
67+
tx: &N::TransactionRequest,
68+
block_id: BlockId,
69+
state_overrides: Option<StateOverride>,
70+
) -> Result<u64>;
5871
async fn create_access_list(
5972
&self,
6073
tx: &N::TransactionRequest,
6174
block_id: BlockId,
75+
state_overrides: Option<StateOverride>,
6276
) -> Result<AccessListResult>;
6377
// logs
6478
async fn get_logs(&self, filter: &Filter) -> Result<Vec<Log>>;

core/src/client/node.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use alloy::eips::{BlockId, BlockNumberOrTag};
66
use alloy::network::BlockResponse;
77
use alloy::primitives::{Address, Bytes, B256, U256};
88
use alloy::rpc::types::{
9-
AccessListItem, AccessListResult, EIP1186AccountProofResponse, EIP1186StorageProof, Filter,
10-
Log, SyncInfo, SyncStatus,
9+
state::StateOverride, AccessListItem, AccessListResult, EIP1186AccountProofResponse,
10+
EIP1186StorageProof, Filter, Log, SyncInfo, SyncStatus,
1111
};
1212
use async_trait::async_trait;
1313
use eyre::{eyre, Result};
@@ -172,7 +172,12 @@ impl<N: NetworkSpec, C: Consensus<N::BlockResponse>, E: ExecutionProvider<N>> He
172172
self.consensus.wait_synced().await
173173
}
174174

175-
async fn call(&self, tx: &N::TransactionRequest, block_id: BlockId) -> Result<Bytes> {
175+
async fn call(
176+
&self,
177+
tx: &N::TransactionRequest,
178+
block_id: BlockId,
179+
state_overrides: Option<StateOverride>,
180+
) -> Result<Bytes> {
176181
self.check_blocktag_age(&block_id).await?;
177182
let (result, ..) = N::transact(
178183
tx,
@@ -181,6 +186,7 @@ impl<N: NetworkSpec, C: Consensus<N::BlockResponse>, E: ExecutionProvider<N>> He
181186
self.get_chain_id().await,
182187
self.fork_schedule,
183188
block_id,
189+
state_overrides,
184190
)
185191
.await?;
186192

@@ -195,7 +201,12 @@ impl<N: NetworkSpec, C: Consensus<N::BlockResponse>, E: ExecutionProvider<N>> He
195201
Ok(res)
196202
}
197203

198-
async fn estimate_gas(&self, tx: &N::TransactionRequest, block_id: BlockId) -> Result<u64> {
204+
async fn estimate_gas(
205+
&self,
206+
tx: &N::TransactionRequest,
207+
block_id: BlockId,
208+
state_overrides: Option<StateOverride>,
209+
) -> Result<u64> {
199210
self.check_blocktag_age(&block_id).await?;
200211

201212
let (result, ..) = N::transact(
@@ -205,6 +216,7 @@ impl<N: NetworkSpec, C: Consensus<N::BlockResponse>, E: ExecutionProvider<N>> He
205216
self.get_chain_id().await,
206217
self.fork_schedule,
207218
block_id,
219+
state_overrides,
208220
)
209221
.await?;
210222

@@ -215,6 +227,7 @@ impl<N: NetworkSpec, C: Consensus<N::BlockResponse>, E: ExecutionProvider<N>> He
215227
&self,
216228
tx: &N::TransactionRequest,
217229
block: BlockId,
230+
state_overrides: Option<StateOverride>,
218231
) -> Result<AccessListResult> {
219232
self.check_blocktag_age(&block).await?;
220233

@@ -225,6 +238,7 @@ impl<N: NetworkSpec, C: Consensus<N::BlockResponse>, E: ExecutionProvider<N>> He
225238
self.get_chain_id().await,
226239
self.fork_schedule,
227240
block,
241+
state_overrides,
228242
)
229243
.await?;
230244

core/src/jsonrpc/mod.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use alloy::network::{BlockResponse, ReceiptResponse, TransactionResponse};
77
use alloy::primitives::{Address, Bytes, B256, U256, U64};
88
use alloy::rpc::json_rpc::RpcObject;
99
use alloy::rpc::types::{
10-
AccessListResult, EIP1186AccountProofResponse, Filter, FilterChanges, Log, SyncStatus,
10+
state::StateOverride, AccessListResult, EIP1186AccountProofResponse, Filter, FilterChanges,
11+
Log, SyncStatus,
1112
};
1213
use eyre::{eyre, Result};
1314
use jsonrpsee::{
@@ -84,14 +85,25 @@ trait EthRpc<
8485
#[method(name = "getCode")]
8586
async fn get_code(&self, address: Address, block: BlockId) -> Result<Bytes, ErrorObjectOwned>;
8687
#[method(name = "call")]
87-
async fn call(&self, tx: TXR, block: BlockId) -> Result<Bytes, ErrorObjectOwned>;
88+
async fn call(
89+
&self,
90+
tx: TXR,
91+
block: BlockId,
92+
state_overrides: Option<StateOverride>,
93+
) -> Result<Bytes, ErrorObjectOwned>;
8894
#[method(name = "estimateGas")]
89-
async fn estimate_gas(&self, tx: TXR, block: BlockId) -> Result<U64, ErrorObjectOwned>;
95+
async fn estimate_gas(
96+
&self,
97+
tx: TXR,
98+
block: BlockId,
99+
state_overrides: Option<StateOverride>,
100+
) -> Result<U64, ErrorObjectOwned>;
90101
#[method(name = "createAccessList")]
91102
async fn create_access_list(
92103
&self,
93104
tx: TXR,
94105
block: BlockId,
106+
state_overrides: Option<StateOverride>,
95107
) -> Result<AccessListResult, ErrorObjectOwned>;
96108
#[method(name = "chainId")]
97109
async fn chain_id(&self) -> Result<U64, ErrorObjectOwned>;
@@ -238,16 +250,22 @@ impl<N: NetworkSpec>
238250
&self,
239251
tx: N::TransactionRequest,
240252
block: BlockId,
253+
state_overrides: Option<StateOverride>,
241254
) -> Result<Bytes, ErrorObjectOwned> {
242-
convert_err(self.client.call(&tx, block).await)
255+
convert_err(self.client.call(&tx, block, state_overrides).await)
243256
}
244257

245258
async fn estimate_gas(
246259
&self,
247260
tx: N::TransactionRequest,
248261
block: BlockId,
262+
state_overrides: Option<StateOverride>,
249263
) -> Result<U64, ErrorObjectOwned> {
250-
let res = self.client.estimate_gas(&tx, block).await.map(U64::from);
264+
let res = self
265+
.client
266+
.estimate_gas(&tx, block, state_overrides)
267+
.await
268+
.map(U64::from);
251269

252270
convert_err(res)
253271
}
@@ -256,8 +274,9 @@ impl<N: NetworkSpec>
256274
&self,
257275
tx: N::TransactionRequest,
258276
block: BlockId,
277+
state_overrides: Option<StateOverride>,
259278
) -> Result<AccessListResult, ErrorObjectOwned> {
260-
convert_err(self.client.create_access_list(&tx, block).await)
279+
convert_err(self.client.create_access_list(&tx, block, state_overrides).await)
261280
}
262281

263282
async fn chain_id(&self) -> Result<U64, ErrorObjectOwned> {

ethereum/src/evm.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use alloy::{
44
consensus::{BlockHeader, TxType},
55
eips::BlockId,
66
network::TransactionBuilder,
7-
rpc::types::{Block, Header, Transaction, TransactionRequest},
7+
rpc::types::{state::StateOverride, Block, Header, Transaction, TransactionRequest},
88
};
99
use eyre::Result;
1010
use revm::{
@@ -53,8 +53,9 @@ impl<E: ExecutionProvider<Ethereum>> EthereumEvm<E> {
5353
&mut self,
5454
tx: &TransactionRequest,
5555
validate_tx: bool,
56+
state_overrides: Option<StateOverride>,
5657
) -> Result<(ExecutionResult, HashMap<Address, Account>), EvmError> {
57-
let mut db = ProofDB::new(self.block_id, self.execution.clone());
58+
let mut db = ProofDB::new(self.block_id, self.execution.clone(), state_overrides);
5859
_ = db.state.prefetch_state(tx, validate_tx).await;
5960

6061
// Track iterations for debugging

ethereum/src/spec.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use alloy::{
88
eips::{BlockId, Encodable2718},
99
network::{BuildResult, Network, NetworkWallet, TransactionBuilder, TransactionBuilderError},
1010
primitives::{Address, Bytes, ChainId, TxKind, U256},
11-
rpc::types::{AccessList, Log, TransactionRequest},
11+
rpc::types::{state::StateOverride, AccessList, Log, TransactionRequest},
1212
};
1313
use async_trait::async_trait;
1414
use revm::context::result::{ExecutionResult, HaltReason};
@@ -104,10 +104,11 @@ impl NetworkSpec for Ethereum {
104104
chain_id: u64,
105105
fork_schedule: ForkSchedule,
106106
block_id: BlockId,
107+
state_overrides: Option<StateOverride>,
107108
) -> Result<(ExecutionResult, HashMap<Address, Account>), EvmError> {
108109
let mut evm = EthereumEvm::new(execution, chain_id, fork_schedule, block_id);
109110

110-
evm.transact_inner(tx, validate_tx).await
111+
evm.transact_inner(tx, validate_tx, state_overrides).await
111112
}
112113
}
113114

helios-ts/lib.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,13 @@ export class HeliosProvider {
211211
return this.#client.get_proof(req.params[0], req.params[1], req.params[2]);
212212
}
213213
case "eth_call": {
214-
return this.#client.call(req.params[0], req.params[1]);
214+
return this.#client.call(req.params[0], req.params[1], req.params[2]);
215215
}
216216
case "eth_estimateGas": {
217-
return this.#client.estimate_gas(req.params[0], req.params[1]);
217+
return this.#client.estimate_gas(req.params[0], req.params[1], req.params[2]);
218218
}
219219
case "eth_createAccessList": {
220-
return this.#client.create_access_list(req.params[0], req.params[1]);
220+
return this.#client.create_access_list(req.params[0], req.params[1], req.params[2]);
221221
}
222222
case "eth_gasPrice": {
223223
return this.#client.gas_price();

helios-ts/src/ethereum.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::str::FromStr;
77
use alloy::eips::{BlockId, BlockNumberOrTag};
88
use alloy::hex::{self, FromHex};
99
use alloy::primitives::{Address, B256, U256};
10-
use alloy::rpc::types::{Filter, TransactionRequest};
10+
use alloy::rpc::types::{state::StateOverride, Filter, TransactionRequest};
1111
use eyre::Result;
1212
use url::Url;
1313
use wasm_bindgen::prelude::*;
@@ -321,29 +321,50 @@ impl EthereumClient {
321321
}
322322

323323
#[wasm_bindgen]
324-
pub async fn call(&self, opts: JsValue, block: JsValue) -> Result<String, JsError> {
324+
pub async fn call(
325+
&self,
326+
opts: JsValue,
327+
block: JsValue,
328+
state_overrides: JsValue,
329+
) -> Result<String, JsError> {
325330
let opts: TransactionRequest = serde_wasm_bindgen::from_value(opts)?;
326331
let block: BlockId = serde_wasm_bindgen::from_value(block)?;
327-
let res = map_err(self.inner.call(&opts, block).await)?;
332+
let state_overrides: Option<StateOverride> =
333+
serde_wasm_bindgen::from_value(state_overrides)?;
334+
let res = map_err(self.inner.call(&opts, block, state_overrides).await)?;
328335
Ok(format!("0x{}", hex::encode(res)))
329336
}
330337

331338
#[wasm_bindgen]
332-
pub async fn estimate_gas(&self, opts: JsValue, block: JsValue) -> Result<u32, JsError> {
339+
pub async fn estimate_gas(
340+
&self,
341+
opts: JsValue,
342+
block: JsValue,
343+
state_overrides: JsValue,
344+
) -> Result<u32, JsError> {
333345
let opts: TransactionRequest = serde_wasm_bindgen::from_value(opts)?;
334346
let block: BlockId = serde_wasm_bindgen::from_value(block)?;
335-
Ok(map_err(self.inner.estimate_gas(&opts, block).await)? as u32)
347+
let state_overrides: Option<StateOverride> =
348+
serde_wasm_bindgen::from_value(state_overrides)?;
349+
Ok(map_err(self.inner.estimate_gas(&opts, block, state_overrides).await)? as u32)
336350
}
337351

338352
#[wasm_bindgen]
339353
pub async fn create_access_list(
340354
&self,
341355
opts: JsValue,
342356
block: JsValue,
357+
state_overrides: JsValue,
343358
) -> Result<JsValue, JsError> {
344359
let opts: TransactionRequest = serde_wasm_bindgen::from_value(opts)?;
345360
let block: BlockId = serde_wasm_bindgen::from_value(block)?;
346-
let access_list_result = map_err(self.inner.create_access_list(&opts, block).await)?;
361+
let state_overrides: Option<StateOverride> =
362+
serde_wasm_bindgen::from_value(state_overrides)?;
363+
let access_list_result = map_err(
364+
self.inner
365+
.create_access_list(&opts, block, state_overrides)
366+
.await,
367+
)?;
347368
Ok(serde_wasm_bindgen::to_value(&access_list_result)?)
348369
}
349370

helios-ts/src/linea.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::str::FromStr;
77
use alloy::eips::{BlockId, BlockNumberOrTag};
88
use alloy::hex;
99
use alloy::primitives::{Address, B256, U256};
10-
use alloy::rpc::types::{Filter, TransactionRequest};
10+
use alloy::rpc::types::{state::StateOverride, Filter, TransactionRequest};
1111
use url::Url;
1212
use wasm_bindgen::prelude::*;
1313
use web_sys::js_sys::Function;
@@ -245,29 +245,50 @@ impl LineaClient {
245245
}
246246

247247
#[wasm_bindgen]
248-
pub async fn call(&self, opts: JsValue, block: JsValue) -> Result<String, JsError> {
248+
pub async fn call(
249+
&self,
250+
opts: JsValue,
251+
block: JsValue,
252+
state_overrides: JsValue,
253+
) -> Result<String, JsError> {
249254
let opts: TransactionRequest = serde_wasm_bindgen::from_value(opts)?;
250255
let block: BlockId = serde_wasm_bindgen::from_value(block)?;
251-
let res = map_err(self.inner.call(&opts, block).await)?;
256+
let state_overrides: Option<StateOverride> =
257+
serde_wasm_bindgen::from_value(state_overrides)?;
258+
let res = map_err(self.inner.call(&opts, block, state_overrides).await)?;
252259
Ok(format!("0x{}", hex::encode(res)))
253260
}
254261

255262
#[wasm_bindgen]
256-
pub async fn estimate_gas(&self, opts: JsValue, block: JsValue) -> Result<u32, JsError> {
263+
pub async fn estimate_gas(
264+
&self,
265+
opts: JsValue,
266+
block: JsValue,
267+
state_overrides: JsValue,
268+
) -> Result<u32, JsError> {
257269
let opts: TransactionRequest = serde_wasm_bindgen::from_value(opts)?;
258270
let block: BlockId = serde_wasm_bindgen::from_value(block)?;
259-
Ok(map_err(self.inner.estimate_gas(&opts, block).await)? as u32)
271+
let state_overrides: Option<StateOverride> =
272+
serde_wasm_bindgen::from_value(state_overrides)?;
273+
Ok(map_err(self.inner.estimate_gas(&opts, block, state_overrides).await)? as u32)
260274
}
261275

262276
#[wasm_bindgen]
263277
pub async fn create_access_list(
264278
&self,
265279
opts: JsValue,
266280
block: JsValue,
281+
state_overrides: JsValue,
267282
) -> Result<JsValue, JsError> {
268283
let opts: TransactionRequest = serde_wasm_bindgen::from_value(opts)?;
269284
let block: BlockId = serde_wasm_bindgen::from_value(block)?;
270-
let access_list_result = map_err(self.inner.create_access_list(&opts, block).await)?;
285+
let state_overrides: Option<StateOverride> =
286+
serde_wasm_bindgen::from_value(state_overrides)?;
287+
let access_list_result = map_err(
288+
self.inner
289+
.create_access_list(&opts, block, state_overrides)
290+
.await,
291+
)?;
271292
Ok(serde_wasm_bindgen::to_value(&access_list_result)?)
272293
}
273294

0 commit comments

Comments
 (0)