Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/anvil/core/src/eth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,9 @@ pub enum EthRequest {
#[serde(rename = "eth_syncing", with = "empty_params")]
EthSyncing(()),

#[serde(rename = "eth_config", with = "empty_params")]
EthConfig(()),

/// geth's `debug_getRawTransaction` endpoint
#[serde(rename = "debug_getRawTransaction", with = "sequence")]
DebugGetRawTransaction(TxHash),
Expand Down
32 changes: 31 additions & 1 deletion crates/anvil/src/eth/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ use alloy_consensus::{
transaction::{Recovered, eip4844::TxEip4844Variant},
};
use alloy_dyn_abi::TypedData;
use alloy_eips::eip2718::Encodable2718;
use alloy_eips::{
eip2718::Encodable2718,
eip7910::{EthConfig, EthForkConfig},
};
use alloy_evm::overrides::{OverrideBlockHashes, apply_state_overrides};
use alloy_network::{
AnyRpcBlock, AnyRpcTransaction, BlockResponse, Ethereum, NetworkWallet, TransactionBuilder,
Expand Down Expand Up @@ -313,6 +316,7 @@ impl EthApi {
EthRequest::EthGetLogs(filter) => self.logs(filter).await.to_rpc_result(),
EthRequest::EthGetWork(_) => self.work().to_rpc_result(),
EthRequest::EthSyncing(_) => self.syncing().to_rpc_result(),
EthRequest::EthConfig(_) => self.config().to_rpc_result(),
EthRequest::EthSubmitWork(nonce, pow, digest) => {
self.submit_work(nonce, pow, digest).to_rpc_result()
}
Expand Down Expand Up @@ -1472,6 +1476,32 @@ impl EthApi {
Ok(false)
}

/// Returns the current configuration of the chain.
/// This is useful for finding out what precompiles and system contracts are available.
///
/// Note: the activation timestamp is always 0 as the configuration is set at genesis.
/// Note: the `fork_id` is always `0x00000000` as this node does not participate in any forking
/// on the network.
/// Note: the `next` and `last` fields are always `null` as this node does not participate in
/// any forking on the network.
///
/// Handler for ETH RPC call: `eth_config`
pub fn config(&self) -> Result<EthConfig> {
node_info!("eth_config");
Ok(EthConfig {
current: EthForkConfig {
activation_time: 0,
blob_schedule: self.backend.blob_params(),
chain_id: self.backend.env().read().evm_env.cfg_env.chain_id,
fork_id: Bytes::from_static(&[0; 4]),
precompiles: self.backend.precompiles(),
system_contracts: self.backend.system_contracts(),
},
next: None,
last: None,
})
}

/// Used for submitting a proof-of-work solution.
///
/// Handler for ETH RPC call: `eth_submitWork`
Expand Down
63 changes: 60 additions & 3 deletions crates/anvil/src/eth/backend/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::{
pool::transactions::PoolTransaction,
sign::build_typed_transaction,
},
evm::celo_precompile,
evm::celo_precompile::{self, CELO_TRANSFER_ADDRESS},
inject_precompiles,
mem::{
inspector::AnvilInspector,
Expand All @@ -41,7 +41,10 @@ use alloy_consensus::{
proofs::{calculate_receipt_root, calculate_transaction_root},
transaction::Recovered,
};
use alloy_eips::{eip1559::BaseFeeParams, eip4844::kzg_to_versioned_hash, eip7840::BlobParams};
use alloy_eips::{
eip1559::BaseFeeParams, eip4844::kzg_to_versioned_hash, eip7840::BlobParams,
eip7910::SystemContract,
};
use alloy_evm::{
Database, Evm,
eth::EthEvmContext,
Expand Down Expand Up @@ -115,7 +118,11 @@ use revm::{
},
database::{CacheDB, WrapDatabaseRef},
interpreter::InstructionResult,
precompile::secp256r1::{P256VERIFY, P256VERIFY_BASE_GAS_FEE},
precompile::{
PrecompileId, PrecompileSpecId, Precompiles,
secp256r1::{P256VERIFY, P256VERIFY_ADDRESS, P256VERIFY_BASE_GAS_FEE},
u64_to_address,
},
primitives::{KECCAK_EMPTY, hardfork::SpecId},
state::AccountInfo,
};
Expand Down Expand Up @@ -843,6 +850,56 @@ impl Backend {
self.env.read().is_celo
}

/// Returns the precompiles for the current spec.
pub fn precompiles(&self) -> BTreeMap<String, Address> {
let spec_id = self.env.read().evm_env.cfg_env.spec;
let precompiles = Precompiles::new(PrecompileSpecId::from_spec_id(spec_id));

let mut precompiles_map = BTreeMap::<String, Address>::default();
for (address, precompile) in precompiles.inner() {
precompiles_map.insert(precompile.id().name().to_string(), *address);
}

if self.odyssey {
precompiles_map.insert(
PrecompileId::P256Verify.name().to_string(),
u64_to_address(P256VERIFY_ADDRESS),
);
}

if self.is_celo() {
precompiles_map.insert(
celo_precompile::PRECOMPILE_ID_CELO_TRANSFER.clone().name().to_string(),
CELO_TRANSFER_ADDRESS,
);
}

if let Some(factory) = &self.precompile_factory {
for (precompile, _) in &factory.precompiles() {
precompiles_map.insert(precompile.id().name().to_string(), *precompile.address());
}
}
Comment on lines +863 to +881
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to do something about this, we have this in a few locations and maintaining this is a bit horrible

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, will have a look in a follow-up if we can have a shared helper for this to make this more maintainable as it currently is strictly tied to the EVM creation that we don't have access to in Anvil's backend


precompiles_map
}

/// Returns the system contracts for the current spec.
pub fn system_contracts(&self) -> BTreeMap<SystemContract, Address> {
let mut system_contracts = BTreeMap::<SystemContract, Address>::default();

let spec_id = self.env.read().evm_env.cfg_env.spec;

if spec_id >= SpecId::CANCUN {
system_contracts.extend(SystemContract::cancun());
}

if spec_id >= SpecId::PRAGUE {
system_contracts.extend(SystemContract::prague(None));
}

system_contracts
}

/// Returns [`BlobParams`] corresponding to the current spec.
pub fn blob_params(&self) -> BlobParams {
let spec_id = self.env.read().evm_env.cfg_env.spec;
Expand Down
13 changes: 10 additions & 3 deletions crates/anvil/src/evm/celo_precompile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,25 @@
//! - to address (32 bytes, left-padded)
//! - value (32 bytes, big-endian U256)

use std::borrow::Cow;

use alloy_evm::precompiles::{DynPrecompile, PrecompileInput};
use alloy_primitives::{Address, U256, address};
use revm::precompile::{PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult};

/// Address of the Celo transfer precompile.
pub const CELO_TRANSFER_ADDRESS: Address = address!("0x00000000000000000000000000000000000000fd");

/// Gas cost for Celo transfer precompile
/// ID for the [Celo transfer precompile](CELO_TRANSFER_ADDRESS).
pub static PRECOMPILE_ID_CELO_TRANSFER: PrecompileId =
PrecompileId::Custom(Cow::Borrowed("celo transfer"));

/// Gas cost for Celo transfer precompile.
const CELO_TRANSFER_GAS_COST: u64 = 9000;

/// Returns the celo native transfer
/// Returns the Celo native transfer.
pub fn precompile() -> DynPrecompile {
DynPrecompile::new_stateful(PrecompileId::custom("celo transfer"), celo_transfer_precompile)
DynPrecompile::new_stateful(PRECOMPILE_ID_CELO_TRANSFER.clone(), celo_transfer_precompile)
}

/// Celo transfer precompile implementation.
Expand Down
Loading
Loading