Skip to content

Commit 6cefbd8

Browse files
committed
expose eth_createAccessList, block param in eth_estimateGas
1 parent 0b5f4bb commit 6cefbd8

File tree

9 files changed

+142
-23
lines changed

9 files changed

+142
-23
lines changed

core/src/client/mod.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::sync::Arc;
33
use std::time::Duration;
44

55
use alloy::primitives::{Address, Bytes, B256, U256};
6-
use alloy::rpc::types::{Filter, FilterChanges, Log, SyncStatus};
6+
use alloy::rpc::types::{AccessListResult, Filter, FilterChanges, Log, SyncStatus};
77
use eyre::Result;
88
use tracing::{info, warn};
99

@@ -73,8 +73,22 @@ impl<N: NetworkSpec, C: Consensus<N::BlockResponse>> Client<N, C> {
7373
self.node.call(tx, block).await.map_err(|err| err.into())
7474
}
7575

76-
pub async fn estimate_gas(&self, tx: &N::TransactionRequest) -> Result<u64> {
77-
self.node.estimate_gas(tx).await.map_err(|err| err.into())
76+
pub async fn estimate_gas(&self, tx: &N::TransactionRequest, block: BlockTag) -> Result<u64> {
77+
self.node
78+
.estimate_gas(tx, block)
79+
.await
80+
.map_err(|err| err.into())
81+
}
82+
83+
pub async fn create_access_list(
84+
&self,
85+
tx: &N::TransactionRequest,
86+
block: BlockTag,
87+
) -> Result<AccessListResult> {
88+
self.node
89+
.create_access_list(tx, block)
90+
.await
91+
.map_err(|err| err.into())
7892
}
7993

8094
pub async fn get_balance(&self, address: Address, block: BlockTag) -> Result<U256> {

core/src/client/node.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::sync::Arc;
33
use alloy::consensus::BlockHeader;
44
use alloy::network::BlockResponse;
55
use alloy::primitives::{Address, Bytes, B256, U256};
6-
use alloy::rpc::types::{Filter, FilterChanges, Log, SyncInfo, SyncStatus};
6+
use alloy::rpc::types::{AccessListResult, Filter, FilterChanges, Log, SyncInfo, SyncStatus};
77
use eyre::{eyre, Result};
88

99
use helios_common::{
@@ -75,19 +75,45 @@ impl<N: NetworkSpec, C: Consensus<N::BlockResponse>> Node<N, C> {
7575
evm.call(tx).await.map_err(ClientError::EvmError)
7676
}
7777

78-
pub async fn estimate_gas(&self, tx: &N::TransactionRequest) -> Result<u64, ClientError> {
79-
self.check_head_age().await?;
78+
pub async fn estimate_gas(
79+
&self,
80+
tx: &N::TransactionRequest,
81+
block: BlockTag,
82+
) -> Result<u64, ClientError> {
83+
self.check_blocktag_age(&block).await?;
8084

8185
let mut evm = Evm::new(
8286
self.execution.clone(),
8387
self.chain_id(),
8488
self.fork_schedule,
85-
BlockTag::Latest,
89+
block,
8690
);
8791

8892
evm.estimate_gas(tx).await.map_err(ClientError::EvmError)
8993
}
9094

95+
pub async fn create_access_list(
96+
&self,
97+
tx: &N::TransactionRequest,
98+
block: BlockTag,
99+
) -> Result<AccessListResult, ClientError> {
100+
self.check_blocktag_age(&block).await?;
101+
102+
let mut evm = Evm::new(
103+
self.execution.clone(),
104+
self.chain_id(),
105+
self.fork_schedule,
106+
block,
107+
);
108+
109+
let res = evm
110+
.create_access_list(tx)
111+
.await
112+
.map_err(ClientError::EvmError)?;
113+
114+
Ok(res.access_list_result)
115+
}
116+
91117
pub async fn get_balance(&self, address: Address, tag: BlockTag) -> Result<U256> {
92118
self.check_blocktag_age(&tag).await?;
93119

core/src/client/rpc.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{fmt::Display, net::SocketAddr, sync::Arc};
33
use alloy::network::{BlockResponse, ReceiptResponse, TransactionResponse};
44
use alloy::primitives::{Address, Bytes, B256, U256, U64};
55
use alloy::rpc::json_rpc::RpcObject;
6-
use alloy::rpc::types::{Filter, FilterChanges, Log, SyncStatus};
6+
use alloy::rpc::types::{AccessListResult, Filter, FilterChanges, Log, SyncStatus};
77
use eyre::Result;
88
use jsonrpsee::{
99
core::{async_trait, server::Methods},
@@ -83,7 +83,13 @@ trait EthRpc<
8383
#[method(name = "call")]
8484
async fn call(&self, tx: TXR, block: BlockTag) -> Result<Bytes, ErrorObjectOwned>;
8585
#[method(name = "estimateGas")]
86-
async fn estimate_gas(&self, tx: TXR) -> Result<U64, ErrorObjectOwned>;
86+
async fn estimate_gas(&self, tx: TXR, block: BlockTag) -> Result<U64, ErrorObjectOwned>;
87+
#[method(name = "createAccessList")]
88+
async fn create_access_list(
89+
&self,
90+
tx: TXR,
91+
block: BlockTag,
92+
) -> Result<AccessListResult, ErrorObjectOwned>;
8793
#[method(name = "chainId")]
8894
async fn chain_id(&self) -> Result<U64, ErrorObjectOwned>;
8995
#[method(name = "gasPrice")]
@@ -241,12 +247,24 @@ impl<N: NetworkSpec, C: Consensus<N::BlockResponse>>
241247
convert_err(self.node.call(&tx, block).await)
242248
}
243249

244-
async fn estimate_gas(&self, tx: N::TransactionRequest) -> Result<U64, ErrorObjectOwned> {
245-
let res = self.node.estimate_gas(&tx).await.map(U64::from);
250+
async fn estimate_gas(
251+
&self,
252+
tx: N::TransactionRequest,
253+
block: BlockTag,
254+
) -> Result<U64, ErrorObjectOwned> {
255+
let res = self.node.estimate_gas(&tx, block).await.map(U64::from);
246256

247257
convert_err(res)
248258
}
249259

260+
async fn create_access_list(
261+
&self,
262+
tx: N::TransactionRequest,
263+
block: BlockTag,
264+
) -> Result<AccessListResult, ErrorObjectOwned> {
265+
convert_err(self.node.create_access_list(&tx, block).await)
266+
}
267+
250268
async fn chain_id(&self) -> Result<U64, ErrorObjectOwned> {
251269
Ok(U64::from(self.node.chain_id()))
252270
}

core/src/execution/evm.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
use std::{borrow::BorrowMut, collections::HashMap, sync::Arc};
22

3-
use alloy::network::{primitives::HeaderResponse, BlockResponse};
3+
use alloy::{
4+
network::{primitives::HeaderResponse, BlockResponse},
5+
rpc::types::{AccessListResult, EIP1186StorageProof},
6+
};
47
use eyre::{Report, Result};
58
use revm::{
69
primitives::{
7-
address, AccountInfo, Address, Bytecode, Bytes, CfgEnv, Env, ExecutionResult, B256, U256,
10+
address, AccessListItem, AccountInfo, Address, Bytecode, Bytes, CfgEnv, Env,
11+
ExecutionResult, B256, U256,
812
},
913
Database, Evm as Revm,
1014
};
@@ -68,11 +72,32 @@ impl<N: NetworkSpec> Evm<N> {
6872
pub async fn create_access_list(
6973
&mut self,
7074
tx: &N::TransactionRequest,
71-
) -> Result<HashMap<Address, Account>, EvmError> {
75+
) -> Result<AccessListResultWithAccounts, EvmError> {
7276
let (result, accounts) = self.call_inner(tx).await?;
7377

7478
match result {
75-
ExecutionResult::Success { .. } => Ok(accounts),
79+
ExecutionResult::Success { .. } => Ok(AccessListResultWithAccounts {
80+
access_list_result: AccessListResult {
81+
access_list: accounts
82+
.iter()
83+
.map(|(address, account)| {
84+
let storage_keys = account
85+
.storage_proof
86+
.iter()
87+
.map(|EIP1186StorageProof { key, .. }| key.as_b256())
88+
.collect();
89+
AccessListItem {
90+
address: *address,
91+
storage_keys,
92+
}
93+
})
94+
.collect::<Vec<_>>()
95+
.into(),
96+
gas_used: U256::from(result.gas_used()),
97+
error: None,
98+
},
99+
accounts,
100+
}),
76101
ExecutionResult::Revert { output, .. } => {
77102
Err(EvmError::Revert(Some(output.to_vec().into())))
78103
}
@@ -295,6 +320,10 @@ impl<N: NetworkSpec> Database for ProofDB<N> {
295320
fn is_precompile(address: &Address) -> bool {
296321
address.le(&address!("0000000000000000000000000000000000000009")) && address.gt(&Address::ZERO)
297322
}
323+
pub struct AccessListResultWithAccounts {
324+
pub access_list_result: AccessListResult,
325+
pub accounts: HashMap<Address, Account>,
326+
}
298327

299328
// #[cfg(test)]
300329
// mod tests {

helios-ts/lib.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ export class HeliosProvider {
9393
return this.#client.call(req.params[0], req.params[1]);
9494
}
9595
case "eth_estimateGas": {
96-
return this.#client.estimate_gas(req.params[0]);
96+
return this.#client.estimate_gas(req.params[0], req.params[1]);
97+
}
98+
case "eth_createAccessList": {
99+
return this.#client.create_access_list(req.params[0], req.params[1]);
97100
}
98101
case "eth_gasPrice": {
99102
return this.#client.gas_price();

helios-ts/src/ethereum.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,22 @@ impl EthereumClient {
252252
}
253253

254254
#[wasm_bindgen]
255-
pub async fn estimate_gas(&self, opts: JsValue) -> Result<u32, JsError> {
255+
pub async fn estimate_gas(&self, opts: JsValue, block: JsValue) -> Result<u32, JsError> {
256256
let opts: TransactionRequest = serde_wasm_bindgen::from_value(opts)?;
257-
Ok(map_err(self.inner.estimate_gas(&opts).await)? as u32)
257+
let block: BlockTag = serde_wasm_bindgen::from_value(block)?;
258+
Ok(map_err(self.inner.estimate_gas(&opts, block).await)? as u32)
259+
}
260+
261+
#[wasm_bindgen]
262+
pub async fn create_access_list(
263+
&self,
264+
opts: JsValue,
265+
block: JsValue,
266+
) -> Result<JsValue, JsError> {
267+
let opts: TransactionRequest = serde_wasm_bindgen::from_value(opts)?;
268+
let block: BlockTag = serde_wasm_bindgen::from_value(block)?;
269+
let access_list_result = map_err(self.inner.create_access_list(&opts, block).await)?;
270+
Ok(serde_wasm_bindgen::to_value(&access_list_result)?)
258271
}
259272

260273
#[wasm_bindgen]

helios-ts/src/opstack.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,22 @@ impl OpStackClient {
203203
}
204204

205205
#[wasm_bindgen]
206-
pub async fn estimate_gas(&self, opts: JsValue) -> Result<u32, JsError> {
206+
pub async fn estimate_gas(&self, opts: JsValue, block: JsValue) -> Result<u32, JsError> {
207207
let opts: OpTransactionRequest = serde_wasm_bindgen::from_value(opts)?;
208-
Ok(map_err(self.inner.estimate_gas(&opts).await)? as u32)
208+
let block: BlockTag = serde_wasm_bindgen::from_value(block)?;
209+
Ok(map_err(self.inner.estimate_gas(&opts, block).await)? as u32)
210+
}
211+
212+
#[wasm_bindgen]
213+
pub async fn create_access_list(
214+
&self,
215+
opts: JsValue,
216+
block: JsValue,
217+
) -> Result<JsValue, JsError> {
218+
let opts: OpTransactionRequest = serde_wasm_bindgen::from_value(opts)?;
219+
let block: BlockTag = serde_wasm_bindgen::from_value(block)?;
220+
let access_list_result = map_err(self.inner.create_access_list(&opts, block).await)?;
221+
Ok(serde_wasm_bindgen::to_value(&access_list_result)?)
209222
}
210223

211224
#[wasm_bindgen]

rpc.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ Helios provides a variety of RPC methods for interacting with the Ethereum netwo
1010
| `eth_getTransactionCount` | `get_nonce` | Returns the number of transactions sent from the given address. | `client.get_nonce(&self, address: &str, block: BlockTag)` |
1111
| `eth_getCode` | `get_code` | Returns the code at a given address. | `client.get_code(&self, address: &str, block: BlockTag)` |
1212
| `eth_call` | `call` | Executes a new message call immediately without creating a transaction on the blockchain. | `client.call(&self, opts: CallOpts, block: BlockTag)` |
13-
| `eth_estimateGas` | `estimate_gas` | Generates and returns an estimate of how much gas is necessary to allow the transaction to be completed. | `client.estimate_gas(&self, opts: CallOpts)` |
13+
| `eth_estimateGas` | `estimate_gas` | Generates and returns an estimate of how much gas is necessary to allow the transaction to be completed. | `client.estimate_gas(&self, opts: CallOpts, block: BlockTag)` |
14+
| `eth_createAccessList` | `create_access_list` | Creates an EIP2930 type `accessList` based on a given Transaction object. Returns list of addresses and storage keys that are read and written by the transaction (except precompiles), plus the estimated gas consumed when the access list is added. | `client.create_access_list(&self, opts: CallOpts, block: BlockTag)` |
1415
| `eth_getChainId` | `chain_id` | Returns the chain ID of the current network. | `client.chain_id(&self)` |
1516
| `eth_gasPrice` | `gas_price` | Returns the current price per gas in wei. | `client.gas_price(&self)` |
1617
| `eth_maxPriorityFeePerGas` | `max_priority_fee_per_gas` | Returns the current max priority fee per gas in wei. | `client.max_priority_fee_per_gas(&self)` |

verifiable-api/server/src/service.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,11 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>> VerifiableApi<N> for ApiService<N, R> {
186186
},
187187
tag,
188188
);
189-
let accounts = evm.create_access_list(&tx).await?;
189+
let res = evm.create_access_list(&tx).await?;
190190

191-
Ok(AccessListResponse { accounts })
191+
Ok(AccessListResponse {
192+
accounts: res.accounts,
193+
})
192194
}
193195

194196
async fn chain_id(&self) -> Result<ChainIdResponse> {

0 commit comments

Comments
 (0)