Skip to content

Commit 1afa5a2

Browse files
authored
feat(anvil): op support revm 21 (#10407)
* enable OpHardforks in NodeConfig * feat: add is_optimism flag to foundry_evm::Env * feat(`anvil`): set is_optimism in Backend * feat(`anvil`): introducing EvmContext enum holding Eth and Op variants. * adds OpEnv to foundry_evm_core * feat: EitherEvm * impl Evm for EitherEvm * integrate EitherEvm into RPC and executor *Map OpHaltReason and OpTransactionError * rm old evm helpers * feat(`foundry_evm`): add deposit tx parts field to Env * fix(`anvil`): set deposit tx parts in tx executor and backend.inspect_tx * nit
1 parent 4730007 commit 1afa5a2

File tree

20 files changed

+579
-174
lines changed

20 files changed

+579
-174
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ alloy-sol-types = "0.8.22"
245245

246246
alloy-chains = "0.1"
247247
alloy-evm = "0.3.2"
248+
alloy-op-evm = "0.3.2"
248249
alloy-rlp = "0.3"
249250
alloy-trie = "0.7.0"
250251

crates/anvil/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ foundry-evm-core.workspace = true
3131

3232
# alloy
3333
alloy-evm.workspace = true
34+
alloy-op-evm.workspace = true
3435
alloy-primitives = { workspace = true, features = ["serde"] }
3536
alloy-consensus = { workspace = true, features = ["k256", "kzg"] }
3637
alloy-contract = { workspace = true, features = ["pubsub"] }

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

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use alloy_serde::{OtherFields, WithOtherFields};
2323
use bytes::BufMut;
2424
use foundry_evm::traces::CallTraceNode;
2525
use op_alloy_consensus::{TxDeposit, DEPOSIT_TX_TYPE_ID};
26+
use op_revm::{transaction::deposit::DepositTransactionParts, OpTransaction};
2627
use revm::{context::TxEnv, interpreter::InstructionResult};
2728
use serde::{Deserialize, Serialize};
2829
use std::ops::{Deref, Mul};
@@ -381,7 +382,9 @@ impl PendingTransaction {
381382

382383
/// Converts the [PendingTransaction] into the [TxEnv] context that [`revm`](foundry_evm)
383384
/// expects.
384-
pub fn to_revm_tx_env(&self) -> TxEnv {
385+
///
386+
/// Base [`TxEnv`] is encapsulated in the [`OpTransaction`]
387+
pub fn to_revm_tx_env(&self) -> OpTransaction<TxEnv> {
385388
fn transact_to(kind: &TxKind) -> TxKind {
386389
match kind {
387390
TxKind::Call(c) => TxKind::Call(*c),
@@ -394,7 +397,7 @@ impl PendingTransaction {
394397
TypedTransaction::Legacy(tx) => {
395398
let chain_id = tx.tx().chain_id;
396399
let TxLegacy { nonce, gas_price, gas_limit, value, to, input, .. } = tx.tx();
397-
TxEnv {
400+
OpTransaction::new(TxEnv {
398401
caller,
399402
kind: transact_to(to),
400403
data: input.clone(),
@@ -405,8 +408,9 @@ impl PendingTransaction {
405408
gas_priority_fee: None,
406409
gas_limit: *gas_limit,
407410
access_list: vec![].into(),
411+
tx_type: 0,
408412
..Default::default()
409-
}
413+
})
410414
}
411415
TypedTransaction::EIP2930(tx) => {
412416
let TxEip2930 {
@@ -420,7 +424,7 @@ impl PendingTransaction {
420424
access_list,
421425
..
422426
} = tx.tx();
423-
TxEnv {
427+
OpTransaction::new(TxEnv {
424428
caller,
425429
kind: transact_to(to),
426430
data: input.clone(),
@@ -431,8 +435,9 @@ impl PendingTransaction {
431435
gas_priority_fee: None,
432436
gas_limit: *gas_limit,
433437
access_list: access_list.clone().into(),
438+
tx_type: 1,
434439
..Default::default()
435-
}
440+
})
436441
}
437442
TypedTransaction::EIP1559(tx) => {
438443
let TxEip1559 {
@@ -447,7 +452,7 @@ impl PendingTransaction {
447452
access_list,
448453
..
449454
} = tx.tx();
450-
TxEnv {
455+
OpTransaction::new(TxEnv {
451456
caller,
452457
kind: transact_to(to),
453458
data: input.clone(),
@@ -458,8 +463,9 @@ impl PendingTransaction {
458463
gas_priority_fee: Some(*max_priority_fee_per_gas),
459464
gas_limit: *gas_limit,
460465
access_list: access_list.clone().into(),
466+
tx_type: 2,
461467
..Default::default()
462-
}
468+
})
463469
}
464470
TypedTransaction::EIP4844(tx) => {
465471
let TxEip4844 {
@@ -476,7 +482,7 @@ impl PendingTransaction {
476482
blob_versioned_hashes,
477483
..
478484
} = tx.tx().tx();
479-
TxEnv {
485+
OpTransaction::new(TxEnv {
480486
caller,
481487
kind: TxKind::Call(*to),
482488
data: input.clone(),
@@ -489,8 +495,9 @@ impl PendingTransaction {
489495
blob_hashes: blob_versioned_hashes.clone(),
490496
gas_limit: *gas_limit,
491497
access_list: access_list.clone().into(),
498+
tx_type: 3,
492499
..Default::default()
493-
}
500+
})
494501
}
495502
TypedTransaction::EIP7702(tx) => {
496503
let TxEip7702 {
@@ -505,7 +512,7 @@ impl PendingTransaction {
505512
authorization_list,
506513
input,
507514
} = tx.tx();
508-
TxEnv {
515+
OpTransaction::new(TxEnv {
509516
caller,
510517
kind: TxKind::Call(*to),
511518
data: input.clone(),
@@ -517,8 +524,9 @@ impl PendingTransaction {
517524
gas_limit: *gas_limit,
518525
access_list: access_list.clone().into(),
519526
authorization_list: authorization_list.clone(),
527+
tx_type: 4,
520528
..Default::default()
521-
}
529+
})
522530
}
523531
TypedTransaction::Deposit(tx) => {
524532
let chain_id = tx.chain_id();
@@ -533,7 +541,7 @@ impl PendingTransaction {
533541
is_system_tx,
534542
..
535543
} = tx;
536-
TxEnv {
544+
let base = TxEnv {
537545
caller,
538546
kind: transact_to(kind),
539547
data: input.clone(),
@@ -544,15 +552,19 @@ impl PendingTransaction {
544552
gas_priority_fee: None,
545553
gas_limit: { *gas_limit },
546554
access_list: vec![].into(),
547-
// TODO: add Optimism support
548-
// optimism: OptimismFields {
549-
// source_hash: Some(*source_hash),
550-
// mint: Some(mint.to::<u128>()),
551-
// is_system_transaction: Some(*is_system_tx),
552-
// enveloped_tx: None,
553-
// },
555+
tx_type: DEPOSIT_TX_TYPE_ID,
554556
..Default::default()
555-
}
557+
};
558+
559+
let deposit = DepositTransactionParts {
560+
source_hash: *source_hash,
561+
mint: Some(mint.to::<u128>()),
562+
is_system_transaction: *is_system_tx,
563+
};
564+
565+
let mut encoded = Vec::new();
566+
tx.encode_2718(&mut encoded);
567+
OpTransaction { base, deposit, enveloped_tx: Some(encoded.into()) }
556568
}
557569
}
558570
}

crates/anvil/src/cmd.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
config::{ForkChoice, DEFAULT_MNEMONIC},
33
eth::{backend::db::SerializableState, pool::transactions::TransactionOrder, EthApi},
4-
AccountGenerator, EthereumHardfork, NodeConfig, CHAIN_ID,
4+
AccountGenerator, EthereumHardfork, NodeConfig, OptimismHardfork, CHAIN_ID,
55
};
66
use alloy_genesis::Genesis;
77
use alloy_primitives::{utils::Unit, B256, U256};
@@ -217,11 +217,11 @@ impl NodeArgs {
217217

218218
let hardfork = match &self.hardfork {
219219
Some(hf) => {
220-
// if self.evm.optimism {
221-
// Some(OptimismHardfork::from_str(hf)?.into())
222-
// } else {
223-
Some(EthereumHardfork::from_str(hf)?.into())
224-
// }
220+
if self.evm.optimism {
221+
Some(OptimismHardfork::from_str(hf)?.into())
222+
} else {
223+
Some(EthereumHardfork::from_str(hf)?.into())
224+
}
225225
}
226226
None => None,
227227
};
@@ -791,9 +791,8 @@ fn duration_from_secs_f64(s: &str) -> Result<Duration, String> {
791791

792792
#[cfg(test)]
793793
mod tests {
794-
use crate::EthereumHardfork;
795-
796794
use super::*;
795+
use crate::{EthereumHardfork, OptimismHardfork};
797796
use std::{env, net::Ipv4Addr};
798797

799798
#[test]
@@ -833,13 +832,13 @@ mod tests {
833832
assert_eq!(config.hardfork, Some(EthereumHardfork::Berlin.into()));
834833
}
835834

836-
// #[test]
837-
// fn can_parse_optimism_hardfork() {
838-
// let args: NodeArgs =
839-
// NodeArgs::parse_from(["anvil", "--optimism", "--hardfork", "Regolith"]);
840-
// let config = args.into_node_config().unwrap();
841-
// assert_eq!(config.hardfork, Some(OptimismHardfork::Regolith.into()));
842-
// }
835+
#[test]
836+
fn can_parse_optimism_hardfork() {
837+
let args: NodeArgs =
838+
NodeArgs::parse_from(["anvil", "--optimism", "--hardfork", "Regolith"]);
839+
let config = args.into_node_config().unwrap();
840+
assert_eq!(config.hardfork, Some(OptimismHardfork::Regolith.into()));
841+
}
843842

844843
#[test]
845844
fn cant_parse_invalid_hardfork() {

crates/anvil/src/config.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
},
1313
hardfork::ChainHardfork,
1414
mem::{self, in_memory_db::MemDb},
15-
EthereumHardfork, FeeManager, PrecompileFactory,
15+
EthereumHardfork, FeeManager, OptimismHardfork, PrecompileFactory,
1616
};
1717
use alloy_consensus::BlockHeader;
1818
use alloy_genesis::Genesis;
@@ -527,9 +527,9 @@ impl NodeConfig {
527527
if let Some(hardfork) = self.hardfork {
528528
return hardfork;
529529
}
530-
// if self.enable_optimism {
531-
// return OptimismHardfork::default().into();
532-
// }
530+
if self.enable_optimism {
531+
return OptimismHardfork::default().into();
532+
}
533533
EthereumHardfork::default().into()
534534
}
535535

@@ -1048,6 +1048,8 @@ impl NodeConfig {
10481048
TxEnv { chain_id: Some(self.get_chain_id()), ..Default::default() },
10491049
);
10501050

1051+
env.is_optimism = self.enable_optimism;
1052+
10511053
let fees = FeeManager::new(
10521054
spec_id,
10531055
self.get_base_fee(),

0 commit comments

Comments
 (0)