Skip to content

Commit 92e020e

Browse files
mattssedbeal-ethjoshieDo
authored
feat(anvil): add eth_simulateV1 rpc call (#10227)
* compiles * fix serialization now the response returns. joy! * looking good with the example * changes to get `status` and `error` properly populated and also some structural fixes * wip * wip2 * feat: implement block simulate * rustfmt * add test --------- Co-authored-by: Daniel Beal <git@dbeal.dev> Co-authored-by: joshieDo <93316087+joshieDo@users.noreply.github.com>
1 parent 8da7373 commit 92e020e

File tree

9 files changed

+341
-8
lines changed

9 files changed

+341
-8
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/anvil/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ revm = { workspace = true, features = [
3535
"memory_limit",
3636
"c-kzg",
3737
] }
38+
revm-inspectors.workspace = true
3839
alloy-primitives = { workspace = true, features = ["serde"] }
3940
alloy-consensus = { workspace = true, features = ["k256", "kzg"] }
4041
alloy-contract = { workspace = true, features = ["pubsub"] }

crates/anvil/core/src/eth/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use alloy_rpc_types::{
44
anvil::{Forking, MineOptions},
55
pubsub::{Params as SubscriptionParams, SubscriptionKind},
66
request::TransactionRequest,
7+
simulate::SimulatePayload,
78
state::StateOverride,
89
trace::{
910
filter::TraceFilter,
@@ -152,6 +153,9 @@ pub enum EthRequest {
152153
#[serde(default)] Option<StateOverride>,
153154
),
154155

156+
#[serde(rename = "eth_simulateV1")]
157+
EthSimulateV1(SimulatePayload, #[serde(default)] Option<BlockId>),
158+
155159
#[serde(rename = "eth_createAccessList")]
156160
EthCreateAccessList(WithOtherFields<TransactionRequest>, #[serde(default)] Option<BlockId>),
157161

crates/anvil/src/eth/api.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ use alloy_rpc_types::{
5353
ForkedNetwork, Forking, Metadata, MineOptions, NodeEnvironment, NodeForkConfig, NodeInfo,
5454
},
5555
request::TransactionRequest,
56+
simulate::{SimulatePayload, SimulatedBlock},
5657
state::StateOverride,
5758
trace::{
5859
filter::TraceFilter,
@@ -249,6 +250,9 @@ impl EthApi {
249250
EthRequest::EthCall(call, block, overrides) => {
250251
self.call(call, block, overrides).await.to_rpc_result()
251252
}
253+
EthRequest::EthSimulateV1(simulation, block) => {
254+
self.simulate_v1(simulation, block).await.to_rpc_result()
255+
}
252256
EthRequest::EthCreateAccessList(call, block) => {
253257
self.create_access_list(call, block).await.to_rpc_result()
254258
}
@@ -1103,6 +1107,33 @@ impl EthApi {
11031107
.await
11041108
}
11051109

1110+
pub async fn simulate_v1(
1111+
&self,
1112+
request: SimulatePayload,
1113+
block_number: Option<BlockId>,
1114+
) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>> {
1115+
node_info!("eth_simulateV1");
1116+
let block_request = self.block_request(block_number).await?;
1117+
// check if the number predates the fork, if in fork mode
1118+
if let BlockRequest::Number(number) = block_request {
1119+
if let Some(fork) = self.get_fork() {
1120+
if fork.predates_fork(number) {
1121+
return Ok(fork.simulate_v1(&request, Some(number.into())).await?)
1122+
}
1123+
}
1124+
}
1125+
1126+
// this can be blocking for a bit, especially in forking mode
1127+
// <https://github.com/foundry-rs/foundry/issues/6036>
1128+
self.on_blocking_task(|this| async move {
1129+
let simulated_blocks = this.backend.simulate(request, Some(block_request)).await?;
1130+
trace!(target : "node", "Simulate status {:?}", simulated_blocks);
1131+
1132+
Ok(simulated_blocks)
1133+
})
1134+
.await
1135+
}
1136+
11061137
/// This method creates an EIP2930 type accessList based on a given Transaction. The accessList
11071138
/// contains all storage slots and addresses read and written by the transaction, except for the
11081139
/// sender account and the precompiles.

crates/anvil/src/eth/backend/fork.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use alloy_provider::{
1414
};
1515
use alloy_rpc_types::{
1616
request::TransactionRequest,
17+
simulate::{SimulatePayload, SimulatedBlock},
1718
trace::{
1819
geth::{GethDebugTracingOptions, GethTrace},
1920
parity::LocalizedTransactionTrace as Trace,
@@ -197,7 +198,23 @@ impl ClientFork {
197198
Ok(res)
198199
}
199200

200-
/// Sends `eth_call`
201+
/// Sends `eth_simulateV1`
202+
pub async fn simulate_v1(
203+
&self,
204+
request: &SimulatePayload,
205+
block: Option<BlockNumber>,
206+
) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>, TransportError> {
207+
let mut simulate_call = self.provider().simulate(request);
208+
if let Some(n) = block {
209+
simulate_call = simulate_call.number(n.as_number().unwrap());
210+
}
211+
212+
let res = simulate_call.await?;
213+
214+
Ok(res)
215+
}
216+
217+
/// Sends `eth_estimateGas`
201218
pub async fn estimate_gas(
202219
&self,
203220
request: &WithOtherFields<TransactionRequest>,

0 commit comments

Comments
 (0)