Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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/pevm/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ pub trait PevmChain: Debug {
/// The error type for [`Self::get_tx_env`].
type TransactionParsingError: StdError + Debug + Clone + PartialEq + 'static;

/// The network type
type Network: alloy_provider::Network;

/// Get chain id.
fn id(&self) -> u64;

Expand Down
1 change: 1 addition & 0 deletions crates/pevm/src/chain/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ impl PevmChain for PevmEthereum {
type Envelope = TxEnvelope;
type BlockSpecError = std::convert::Infallible;
type TransactionParsingError = EthereumTransactionParsingError;
type Network = alloy_provider::network::Ethereum;

fn id(&self) -> u64 {
self.id
Expand Down
1 change: 1 addition & 0 deletions crates/pevm/src/chain/optimism.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ impl PevmChain for PevmOptimism {
type Envelope = OpTxEnvelope;
type BlockSpecError = OptimismBlockSpecError;
type TransactionParsingError = OptimismTransactionParsingError;
type Network = op_alloy_network::Optimism;

fn id(&self) -> ChainId {
self.id
Expand Down
135 changes: 69 additions & 66 deletions crates/pevm/tests/mainnet.rs
Original file line number Diff line number Diff line change
@@ -1,97 +1,100 @@
//! Test with mainnet blocks

use pevm::chain::PevmEthereum;

pub mod common;

#[tokio::test(flavor = "multi_thread")]
#[cfg(feature = "rpc-storage")]
async fn mainnet_blocks_from_rpc() {
async fn test_blocks_from_rpc<C>(url: reqwest::Url, chain: &C, block_numbers: &[u64])
where
C: pevm::chain::PevmChain + PartialEq + Send + Sync,
<C::Network as alloy_provider::Network>::BlockResponse:
Into<alloy_rpc_types_eth::Block<C::Transaction>>,
{
use alloy_provider::{Provider, ProviderBuilder};
use alloy_rpc_types_eth::{BlockId, BlockTransactionsKind};
use pevm::chain::PevmChain;

let rpc_url = match std::env::var("ETHEREUM_RPC_URL") {
// The empty check is for GitHub Actions where the variable is set with an empty string when unset!?
Ok(value) if !value.is_empty() => value.parse().unwrap(),
_ => reqwest::Url::parse("https://eth-mainnet.public.blastapi.io").unwrap(),
};
let provider = ProviderBuilder::new().network::<C::Network>().on_http(url);

// First block under 50 transactions of each EVM-spec-changing fork
for block_number in [
46147, // FRONTIER
1150000, // HOMESTEAD
// TODO: Enable these when CI is less flaky.
// 2463002, // TANGERINE
// 2675000, // SPURIOUS_DRAGON
// 4370003, // BYZANTIUM
// 7280003, // PETERSBURG
// 9069001, // ISTANBUL
// 12244002, // BERLIN
// 12965034, // LONDON
// 15537395, // MERGE
// 17035010, // SHANGHAI
// 19426587, // CANCUN
] {
let provider = ProviderBuilder::new().on_http(rpc_url.clone());
for &block_number in block_numbers {
let block = provider
.get_block(BlockId::number(block_number), BlockTransactionsKind::Full)
.await
.unwrap()
.unwrap();
let chain = PevmEthereum::mainnet();
.unwrap()
.into();
let spec_id = chain.get_block_spec(&block.header).unwrap();
let rpc_storage =
pevm::RpcStorage::new(provider, spec_id, BlockId::number(block_number - 1));
common::test_execute_alloy(&chain, &rpc_storage, block, true);
pevm::RpcStorage::new(provider.clone(), spec_id, BlockId::number(block_number - 1));
common::test_execute_alloy(chain, &rpc_storage, block, true);
}
}

#[test]
fn mainnet_blocks_from_disk() {
common::for_each_block_from_disk(|block, storage| {
// Run several times to try catching a race condition if there is any.
// 1000~2000 is a better choice for local testing after major changes.
for _ in 0..3 {
common::test_execute_alloy(&PevmEthereum::mainnet(), &storage, block.clone(), true)
}
});
#[tokio::test(flavor = "multi_thread")]
#[cfg(feature = "rpc-storage")]
async fn mainnet_blocks_from_rpc() {
let rpc_url = match std::env::var("ETHEREUM_RPC_URL") {
// The empty check is for GitHub Actions where the variable is set with an empty string when unset!?
Ok(value) if !value.is_empty() => value.parse().unwrap(),
_ => reqwest::Url::parse("https://eth-mainnet.public.blastapi.io").unwrap(),
};

// First block under 50 transactions of each EVM-spec-changing fork
test_blocks_from_rpc(
rpc_url,
&pevm::chain::PevmEthereum::mainnet(),
&[
46147, // FRONTIER
1150000, // HOMESTEAD
// TODO: Enable these when CI is less flaky.
// 2463002, // TANGERINE
// 2675000, // SPURIOUS_DRAGON
// 4370003, // BYZANTIUM
// 7280003, // PETERSBURG
// 9069001, // ISTANBUL
// 12244002, // BERLIN
// 12965034, // LONDON
// 15537395, // MERGE
// 17035010, // SHANGHAI
// 19426587, // CANCUN
],
)
.await;
}

#[tokio::test(flavor = "multi_thread")]
#[cfg(all(feature = "rpc-storage", feature = "optimism"))]
async fn optimism_mainnet_blocks_from_rpc() {
use alloy_provider::{Provider, ProviderBuilder};
use alloy_rpc_types_eth::{BlockId, BlockTransactionsKind};
use pevm::chain::{PevmChain, PevmOptimism};

let rpc_url = match std::env::var("OPTIMISM_RPC_URL") {
Ok(value) if !value.is_empty() => value.parse().unwrap(),
_ => reqwest::Url::parse("https://mainnet.optimism.io").unwrap(),
};

// First block under 50 transactions of each EVM-spec-changing fork
for block_number in [
114874075, // CANYON (https://specs.optimism.io/protocol/canyon/overview.html)
// TODO: doesn't pass `Err(ExecutionError("Database(InvalidNonce(0))"))`
// 117874236, // ECOTONE (https://specs.optimism.io/protocol/ecotone/overview.html)
// 122874325, // FJORD (https://specs.optimism.io/protocol/fjord/overview.html)
// 125874340, // GRANITE (https://specs.optimism.io/protocol/granite/overview.html)
] {
let provider = ProviderBuilder::new()
.network::<op_alloy_network::Optimism>()
.on_http(rpc_url.clone());
let block = provider
.get_block(BlockId::number(block_number), BlockTransactionsKind::Full)
.await
.unwrap()
.unwrap();

let chain = PevmOptimism::mainnet();
let spec_id = chain.get_block_spec(&block.header).unwrap();
test_blocks_from_rpc(
rpc_url,
&pevm::chain::PevmOptimism::mainnet(),
&[
114874075, // CANYON (https://specs.optimism.io/protocol/canyon/overview.html)
// TODO: doesn't pass `Err(ExecutionError("Database(InvalidNonce(0))"))`
// 117874236, // ECOTONE (https://specs.optimism.io/protocol/ecotone/overview.html)
// 122874325, // FJORD (https://specs.optimism.io/protocol/fjord/overview.html)
// 125874340, // GRANITE (https://specs.optimism.io/protocol/granite/overview.html)
],
)
.await;
}

let rpc_storage =
pevm::RpcStorage::new(provider, spec_id, BlockId::number(block_number - 1));
common::test_execute_alloy(&chain, &rpc_storage, block, true);
}
#[test]
fn mainnet_blocks_from_disk() {
common::for_each_block_from_disk(|block, storage| {
// Run several times to try catching a race condition if there is any.
// 1000~2000 is a better choice for local testing after major changes.
for _ in 0..3 {
common::test_execute_alloy(
&pevm::chain::PevmEthereum::mainnet(),
&storage,
block.clone(),
true,
)
}
});
}