mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
chore(e2e): refactor e2e tests (#7773)
This commit is contained in:
2
.github/workflows/integration.yml
vendored
2
.github/workflows/integration.yml
vendored
@ -48,7 +48,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cargo nextest run \
|
cargo nextest run \
|
||||||
--locked --features "asm-keccak ${{ matrix.network }}" \
|
--locked --features "asm-keccak ${{ matrix.network }}" \
|
||||||
--workspace --exclude examples --exclude ef-tests node-e2e-tests \
|
--workspace --exclude examples --exclude ef-tests node-ethereum \
|
||||||
-E "kind(test)"
|
-E "kind(test)"
|
||||||
|
|
||||||
sync:
|
sync:
|
||||||
|
|||||||
64
Cargo.lock
generated
64
Cargo.lock
generated
@ -4882,33 +4882,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "node-e2e-tests"
|
|
||||||
version = "0.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"alloy-consensus",
|
|
||||||
"alloy-network",
|
|
||||||
"alloy-rpc-types",
|
|
||||||
"alloy-signer",
|
|
||||||
"alloy-signer-wallet",
|
|
||||||
"eyre",
|
|
||||||
"futures-util",
|
|
||||||
"jsonrpsee",
|
|
||||||
"rand 0.8.5",
|
|
||||||
"reth",
|
|
||||||
"reth-db",
|
|
||||||
"reth-node-core",
|
|
||||||
"reth-node-ethereum",
|
|
||||||
"reth-payload-builder",
|
|
||||||
"reth-primitives",
|
|
||||||
"reth-rpc",
|
|
||||||
"reth-tracing",
|
|
||||||
"secp256k1 0.27.0",
|
|
||||||
"serde_json",
|
|
||||||
"tokio",
|
|
||||||
"tokio-stream",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.3"
|
version = "7.1.3"
|
||||||
@ -6446,6 +6419,33 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reth-e2e-test-utils"
|
||||||
|
version = "0.2.0-beta.5"
|
||||||
|
dependencies = [
|
||||||
|
"alloy-consensus",
|
||||||
|
"alloy-network",
|
||||||
|
"alloy-rpc-types",
|
||||||
|
"alloy-signer",
|
||||||
|
"alloy-signer-wallet",
|
||||||
|
"eyre",
|
||||||
|
"futures-util",
|
||||||
|
"jsonrpsee",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"reth",
|
||||||
|
"reth-db",
|
||||||
|
"reth-node-core",
|
||||||
|
"reth-node-ethereum",
|
||||||
|
"reth-payload-builder",
|
||||||
|
"reth-primitives",
|
||||||
|
"reth-rpc",
|
||||||
|
"reth-tracing",
|
||||||
|
"secp256k1 0.27.0",
|
||||||
|
"serde_json",
|
||||||
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reth-ecies"
|
name = "reth-ecies"
|
||||||
version = "0.2.0-beta.5"
|
version = "0.2.0-beta.5"
|
||||||
@ -6962,8 +6962,11 @@ version = "0.2.0-beta.5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"eyre",
|
"eyre",
|
||||||
"futures",
|
"futures",
|
||||||
|
"futures-util",
|
||||||
|
"reth",
|
||||||
"reth-basic-payload-builder",
|
"reth-basic-payload-builder",
|
||||||
"reth-db",
|
"reth-db",
|
||||||
|
"reth-e2e-test-utils",
|
||||||
"reth-ethereum-engine-primitives",
|
"reth-ethereum-engine-primitives",
|
||||||
"reth-ethereum-payload-builder",
|
"reth-ethereum-payload-builder",
|
||||||
"reth-evm-ethereum",
|
"reth-evm-ethereum",
|
||||||
@ -6971,10 +6974,14 @@ dependencies = [
|
|||||||
"reth-network",
|
"reth-network",
|
||||||
"reth-node-api",
|
"reth-node-api",
|
||||||
"reth-node-builder",
|
"reth-node-builder",
|
||||||
|
"reth-node-core",
|
||||||
"reth-payload-builder",
|
"reth-payload-builder",
|
||||||
|
"reth-primitives",
|
||||||
"reth-provider",
|
"reth-provider",
|
||||||
"reth-tracing",
|
"reth-tracing",
|
||||||
"reth-transaction-pool",
|
"reth-transaction-pool",
|
||||||
|
"serde_json",
|
||||||
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -7011,8 +7018,10 @@ dependencies = [
|
|||||||
"jsonrpsee",
|
"jsonrpsee",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot 0.12.1",
|
||||||
"reqwest 0.11.27",
|
"reqwest 0.11.27",
|
||||||
|
"reth",
|
||||||
"reth-basic-payload-builder",
|
"reth-basic-payload-builder",
|
||||||
"reth-db",
|
"reth-db",
|
||||||
|
"reth-e2e-test-utils",
|
||||||
"reth-evm",
|
"reth-evm",
|
||||||
"reth-interfaces",
|
"reth-interfaces",
|
||||||
"reth-network",
|
"reth-network",
|
||||||
@ -7033,6 +7042,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ members = [
|
|||||||
"crates/consensus/beacon-core/",
|
"crates/consensus/beacon-core/",
|
||||||
"crates/consensus/common/",
|
"crates/consensus/common/",
|
||||||
"crates/ethereum-forks/",
|
"crates/ethereum-forks/",
|
||||||
|
"crates/e2e-test-utils/",
|
||||||
"crates/etl/",
|
"crates/etl/",
|
||||||
"crates/evm/",
|
"crates/evm/",
|
||||||
"crates/ethereum/evm",
|
"crates/ethereum/evm",
|
||||||
@ -51,7 +52,6 @@ members = [
|
|||||||
"crates/optimism/node/",
|
"crates/optimism/node/",
|
||||||
"crates/node-core/",
|
"crates/node-core/",
|
||||||
"crates/node/api/",
|
"crates/node/api/",
|
||||||
"crates/node-e2e-tests/",
|
|
||||||
"crates/stages/",
|
"crates/stages/",
|
||||||
"crates/stages-api",
|
"crates/stages-api",
|
||||||
"crates/static-file/",
|
"crates/static-file/",
|
||||||
@ -212,6 +212,7 @@ reth-db = { path = "crates/storage/db" }
|
|||||||
reth-discv4 = { path = "crates/net/discv4" }
|
reth-discv4 = { path = "crates/net/discv4" }
|
||||||
reth-discv5 = { path = "crates/net/discv5" }
|
reth-discv5 = { path = "crates/net/discv5" }
|
||||||
reth-dns-discovery = { path = "crates/net/dns" }
|
reth-dns-discovery = { path = "crates/net/dns" }
|
||||||
|
reth-e2e-test-utils = { path = "crates/e2e-test-utils" }
|
||||||
reth-engine-primitives = { path = "crates/engine-primitives" }
|
reth-engine-primitives = { path = "crates/engine-primitives" }
|
||||||
reth-ethereum-engine-primitives = { path = "crates/ethereum/engine-primitives" }
|
reth-ethereum-engine-primitives = { path = "crates/ethereum/engine-primitives" }
|
||||||
reth-node-builder = { path = "crates/node-builder" }
|
reth-node-builder = { path = "crates/node-builder" }
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "node-e2e-tests"
|
name = "reth-e2e-test-utils"
|
||||||
version = "0.0.0"
|
version.workspace = true
|
||||||
publish = false
|
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
homepage.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@ -1,56 +1,57 @@
|
|||||||
|
use crate::traits::PayloadEnvelopeExt;
|
||||||
use jsonrpsee::http_client::HttpClient;
|
use jsonrpsee::http_client::HttpClient;
|
||||||
use reth::{
|
use reth::{
|
||||||
|
api::{EngineTypes, PayloadBuilderAttributes},
|
||||||
providers::CanonStateNotificationStream,
|
providers::CanonStateNotificationStream,
|
||||||
rpc::{
|
rpc::{api::EngineApiClient, types::engine::ForkchoiceState},
|
||||||
api::EngineApiClient,
|
|
||||||
types::engine::{ExecutionPayloadEnvelopeV3, ForkchoiceState},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use reth_node_ethereum::EthEngineTypes;
|
use reth_payload_builder::PayloadId;
|
||||||
use reth_payload_builder::{EthBuiltPayload, EthPayloadBuilderAttributes, PayloadId};
|
|
||||||
use reth_primitives::B256;
|
use reth_primitives::B256;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// Helper for engine api operations
|
/// Helper for engine api operations
|
||||||
pub struct EngineApiHelper {
|
pub struct EngineApiHelper<E> {
|
||||||
pub canonical_stream: CanonStateNotificationStream,
|
pub canonical_stream: CanonStateNotificationStream,
|
||||||
pub engine_api_client: HttpClient,
|
pub engine_api_client: HttpClient,
|
||||||
|
pub _marker: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EngineApiHelper {
|
impl<E: EngineTypes + 'static> EngineApiHelper<E> {
|
||||||
/// Retrieves a v3 payload from the engine api
|
/// Retrieves a v3 payload from the engine api
|
||||||
pub async fn get_payload_v3(
|
pub async fn get_payload_v3(
|
||||||
&self,
|
&self,
|
||||||
payload_id: PayloadId,
|
payload_id: PayloadId,
|
||||||
) -> eyre::Result<ExecutionPayloadEnvelopeV3> {
|
) -> eyre::Result<E::ExecutionPayloadV3> {
|
||||||
Ok(EngineApiClient::<EthEngineTypes>::get_payload_v3(&self.engine_api_client, payload_id)
|
Ok(EngineApiClient::<E>::get_payload_v3(&self.engine_api_client, payload_id).await?)
|
||||||
.await?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Submits a payload to the engine api
|
/// Submits a payload to the engine api
|
||||||
pub async fn submit_payload(
|
pub async fn submit_payload(
|
||||||
&self,
|
&self,
|
||||||
payload: EthBuiltPayload,
|
payload: E::BuiltPayload,
|
||||||
eth_attr: EthPayloadBuilderAttributes,
|
payload_builder_attributes: E::PayloadBuilderAttributes,
|
||||||
) -> eyre::Result<B256> {
|
) -> eyre::Result<B256>
|
||||||
|
where
|
||||||
|
E::ExecutionPayloadV3: From<E::BuiltPayload> + PayloadEnvelopeExt,
|
||||||
|
{
|
||||||
// setup payload for submission
|
// setup payload for submission
|
||||||
let envelope_v3 = ExecutionPayloadEnvelopeV3::from(payload);
|
let envelope_v3: <E as EngineTypes>::ExecutionPayloadV3 = payload.into();
|
||||||
let payload_v3 = envelope_v3.execution_payload;
|
|
||||||
|
|
||||||
// submit payload to engine api
|
// submit payload to engine api
|
||||||
let submission = EngineApiClient::<EthEngineTypes>::new_payload_v3(
|
let submission = EngineApiClient::<E>::new_payload_v3(
|
||||||
&self.engine_api_client,
|
&self.engine_api_client,
|
||||||
payload_v3,
|
envelope_v3.execution_payload(),
|
||||||
vec![],
|
vec![],
|
||||||
eth_attr.parent_beacon_block_root.unwrap(),
|
payload_builder_attributes.parent_beacon_block_root().unwrap(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
assert!(submission.is_valid());
|
assert!(submission.is_valid(), "{}", submission);
|
||||||
Ok(submission.latest_valid_hash.unwrap())
|
Ok(submission.latest_valid_hash.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends forkchoice update to the engine api
|
/// Sends forkchoice update to the engine api
|
||||||
pub async fn update_forkchoice(&self, hash: B256) -> eyre::Result<()> {
|
pub async fn update_forkchoice(&self, hash: B256) -> eyre::Result<()> {
|
||||||
EngineApiClient::<EthEngineTypes>::fork_choice_updated_v2(
|
EngineApiClient::<E>::fork_choice_updated_v2(
|
||||||
&self.engine_api_client,
|
&self.engine_api_client,
|
||||||
ForkchoiceState {
|
ForkchoiceState {
|
||||||
head_block_hash: hash,
|
head_block_hash: hash,
|
||||||
@ -12,3 +12,6 @@ mod network;
|
|||||||
|
|
||||||
/// Helper for engine api operations
|
/// Helper for engine api operations
|
||||||
mod engine_api;
|
mod engine_api;
|
||||||
|
|
||||||
|
/// Helper traits
|
||||||
|
mod traits;
|
||||||
@ -1,8 +1,11 @@
|
|||||||
use crate::{engine_api::EngineApiHelper, network::NetworkHelper, payload::PayloadHelper};
|
use crate::{
|
||||||
|
engine_api::EngineApiHelper, network::NetworkHelper, payload::PayloadHelper,
|
||||||
|
traits::PayloadEnvelopeExt,
|
||||||
|
};
|
||||||
use alloy_rpc_types::BlockNumberOrTag;
|
use alloy_rpc_types::BlockNumberOrTag;
|
||||||
use eyre::Ok;
|
use eyre::Ok;
|
||||||
use reth::{
|
use reth::{
|
||||||
api::FullNodeComponents,
|
api::{BuiltPayload, EngineTypes, FullNodeComponents, PayloadBuilderAttributes},
|
||||||
builder::FullNode,
|
builder::FullNode,
|
||||||
providers::{BlockReaderIdExt, CanonStateSubscriptions},
|
providers::{BlockReaderIdExt, CanonStateSubscriptions},
|
||||||
rpc::{
|
rpc::{
|
||||||
@ -10,28 +13,28 @@ use reth::{
|
|||||||
types::engine::PayloadAttributes,
|
types::engine::PayloadAttributes,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use reth_node_ethereum::EthEngineTypes;
|
|
||||||
use reth_payload_builder::EthPayloadBuilderAttributes;
|
use reth_payload_builder::EthPayloadBuilderAttributes;
|
||||||
use reth_primitives::{Address, Bytes, B256};
|
use reth_primitives::{Address, BlockNumber, Bytes, B256};
|
||||||
|
use std::{
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
marker::PhantomData,
|
||||||
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
|
};
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
/// An helper struct to handle node actions
|
/// An helper struct to handle node actions
|
||||||
pub struct NodeHelper<Node>
|
pub struct NodeHelper<Node>
|
||||||
where
|
where
|
||||||
Node: FullNodeComponents<Engine = EthEngineTypes>,
|
Node: FullNodeComponents,
|
||||||
{
|
{
|
||||||
pub inner: FullNode<Node>,
|
pub inner: FullNode<Node>,
|
||||||
payload: PayloadHelper<Node::Engine>,
|
payload: PayloadHelper<Node::Engine>,
|
||||||
pub network: NetworkHelper,
|
pub network: NetworkHelper,
|
||||||
pub engine_api: EngineApiHelper,
|
pub engine_api: EngineApiHelper<Node::Engine>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Node> NodeHelper<Node>
|
impl<Node> NodeHelper<Node>
|
||||||
where
|
where
|
||||||
Node: FullNodeComponents<Engine = EthEngineTypes>,
|
Node: FullNodeComponents,
|
||||||
{
|
{
|
||||||
/// Creates a new test node
|
/// Creates a new test node
|
||||||
pub async fn new(node: FullNode<Node>) -> eyre::Result<Self> {
|
pub async fn new(node: FullNode<Node>) -> eyre::Result<Self> {
|
||||||
@ -44,17 +47,26 @@ where
|
|||||||
engine_api: EngineApiHelper {
|
engine_api: EngineApiHelper {
|
||||||
engine_api_client: node.auth_server_handle().http_client(),
|
engine_api_client: node.auth_server_handle().http_client(),
|
||||||
canonical_stream: node.provider.canonical_state_stream(),
|
canonical_stream: node.provider.canonical_state_stream(),
|
||||||
|
_marker: PhantomData::<Node::Engine>,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Advances the node forward
|
/// Advances the node forward
|
||||||
pub async fn advance(&mut self, raw_tx: Bytes) -> eyre::Result<(B256, B256)> {
|
pub async fn advance(
|
||||||
|
&mut self,
|
||||||
|
raw_tx: Bytes,
|
||||||
|
attributes_generator: impl Fn(u64) -> <Node::Engine as EngineTypes>::PayloadBuilderAttributes,
|
||||||
|
) -> eyre::Result<(B256, B256)>
|
||||||
|
where
|
||||||
|
<Node::Engine as EngineTypes>::ExecutionPayloadV3:
|
||||||
|
From<<Node::Engine as EngineTypes>::BuiltPayload> + PayloadEnvelopeExt,
|
||||||
|
{
|
||||||
// push tx into pool via RPC server
|
// push tx into pool via RPC server
|
||||||
let tx_hash = self.inject_tx(raw_tx).await?;
|
let tx_hash = self.inject_tx(raw_tx).await?;
|
||||||
|
|
||||||
// trigger new payload building draining the pool
|
// trigger new payload building draining the pool
|
||||||
let eth_attr = self.payload.new_payload().await.unwrap();
|
let eth_attr = self.payload.new_payload(attributes_generator).await.unwrap();
|
||||||
|
|
||||||
// first event is the payload attributes
|
// first event is the payload attributes
|
||||||
self.payload.expect_attr_event(eth_attr.clone()).await?;
|
self.payload.expect_attr_event(eth_attr.clone()).await?;
|
||||||
@ -69,13 +81,14 @@ where
|
|||||||
let payload = self.payload.expect_built_payload().await?;
|
let payload = self.payload.expect_built_payload().await?;
|
||||||
|
|
||||||
// submit payload via engine api
|
// submit payload via engine api
|
||||||
|
let block_number = payload.block().number;
|
||||||
let block_hash = self.engine_api.submit_payload(payload, eth_attr.clone()).await?;
|
let block_hash = self.engine_api.submit_payload(payload, eth_attr.clone()).await?;
|
||||||
|
|
||||||
// trigger forkchoice update via engine api to commit the block to the blockchain
|
// trigger forkchoice update via engine api to commit the block to the blockchain
|
||||||
self.engine_api.update_forkchoice(block_hash).await?;
|
self.engine_api.update_forkchoice(block_hash).await?;
|
||||||
|
|
||||||
// assert the block has been committed to the blockchain
|
// assert the block has been committed to the blockchain
|
||||||
self.assert_new_block(tx_hash, block_hash).await?;
|
self.assert_new_block(tx_hash, block_hash, block_number).await?;
|
||||||
Ok((block_hash, tx_hash))
|
Ok((block_hash, tx_hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,6 +104,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
tip_tx_hash: B256,
|
tip_tx_hash: B256,
|
||||||
block_hash: B256,
|
block_hash: B256,
|
||||||
|
block_number: BlockNumber,
|
||||||
) -> eyre::Result<()> {
|
) -> eyre::Result<()> {
|
||||||
// get head block from notifications stream and verify the tx has been pushed to the
|
// get head block from notifications stream and verify the tx has been pushed to the
|
||||||
// pool is actually present in the canonical block
|
// pool is actually present in the canonical block
|
||||||
@ -98,14 +112,20 @@ where
|
|||||||
let tx = head.tip().transactions().next();
|
let tx = head.tip().transactions().next();
|
||||||
assert_eq!(tx.unwrap().hash().as_slice(), tip_tx_hash.as_slice());
|
assert_eq!(tx.unwrap().hash().as_slice(), tip_tx_hash.as_slice());
|
||||||
|
|
||||||
// wait for the block to commit
|
loop {
|
||||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
// wait for the block to commit
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(20)).await;
|
||||||
// make sure the block hash we submitted via FCU engine api is the new latest block
|
if let Some(latest_block) =
|
||||||
// using an RPC call
|
self.inner.provider.block_by_number_or_tag(BlockNumberOrTag::Latest)?
|
||||||
let latest_block =
|
{
|
||||||
self.inner.provider.block_by_number_or_tag(BlockNumberOrTag::Latest)?.unwrap();
|
if latest_block.number == block_number {
|
||||||
assert_eq!(latest_block.hash_slow(), block_hash);
|
// make sure the block hash we submitted via FCU engine api is the new latest
|
||||||
|
// block using an RPC call
|
||||||
|
assert_eq!(latest_block.hash_slow(), block_hash);
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,34 +1,31 @@
|
|||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
|
||||||
|
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use reth::{
|
use reth::api::{BuiltPayload, EngineTypes, PayloadBuilderAttributes};
|
||||||
api::{EngineTypes, PayloadBuilderAttributes},
|
use reth_payload_builder::{Events, PayloadBuilderHandle, PayloadId};
|
||||||
rpc::types::engine::PayloadAttributes,
|
|
||||||
};
|
|
||||||
use reth_node_ethereum::EthEngineTypes;
|
|
||||||
use reth_payload_builder::{
|
|
||||||
EthBuiltPayload, EthPayloadBuilderAttributes, Events, PayloadBuilderHandle, PayloadId,
|
|
||||||
};
|
|
||||||
use reth_primitives::{Address, B256};
|
|
||||||
use tokio_stream::wrappers::BroadcastStream;
|
use tokio_stream::wrappers::BroadcastStream;
|
||||||
|
|
||||||
/// Helper for payload operations
|
/// Helper for payload operations
|
||||||
pub struct PayloadHelper<E: EngineTypes + 'static> {
|
pub struct PayloadHelper<E: EngineTypes + 'static> {
|
||||||
pub payload_event_stream: BroadcastStream<Events<E>>,
|
pub payload_event_stream: BroadcastStream<Events<E>>,
|
||||||
payload_builder: PayloadBuilderHandle<E>,
|
payload_builder: PayloadBuilderHandle<E>,
|
||||||
|
timestamp: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PayloadHelper<EthEngineTypes> {
|
impl<E: EngineTypes + 'static> PayloadHelper<E> {
|
||||||
/// Creates a new payload helper
|
/// Creates a new payload helper
|
||||||
pub async fn new(payload_builder: PayloadBuilderHandle<EthEngineTypes>) -> eyre::Result<Self> {
|
pub async fn new(payload_builder: PayloadBuilderHandle<E>) -> eyre::Result<Self> {
|
||||||
let payload_events = payload_builder.subscribe().await?;
|
let payload_events = payload_builder.subscribe().await?;
|
||||||
let payload_event_stream = payload_events.into_stream();
|
let payload_event_stream = payload_events.into_stream();
|
||||||
Ok(Self { payload_event_stream, payload_builder })
|
// Cancun timestamp
|
||||||
|
Ok(Self { payload_event_stream, payload_builder, timestamp: 1710338135 })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new payload job from static attributes
|
/// Creates a new payload job from static attributes
|
||||||
pub async fn new_payload(&self) -> eyre::Result<EthPayloadBuilderAttributes> {
|
pub async fn new_payload(
|
||||||
let attributes = eth_payload_attributes();
|
&mut self,
|
||||||
|
attributes_generator: impl Fn(u64) -> E::PayloadBuilderAttributes,
|
||||||
|
) -> eyre::Result<E::PayloadBuilderAttributes> {
|
||||||
|
self.timestamp += 1;
|
||||||
|
let attributes: E::PayloadBuilderAttributes = attributes_generator(self.timestamp);
|
||||||
self.payload_builder.new_payload(attributes.clone()).await.unwrap();
|
self.payload_builder.new_payload(attributes.clone()).await.unwrap();
|
||||||
Ok(attributes)
|
Ok(attributes)
|
||||||
}
|
}
|
||||||
@ -36,11 +33,11 @@ impl PayloadHelper<EthEngineTypes> {
|
|||||||
/// Asserts that the next event is a payload attributes event
|
/// Asserts that the next event is a payload attributes event
|
||||||
pub async fn expect_attr_event(
|
pub async fn expect_attr_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
attrs: EthPayloadBuilderAttributes,
|
attrs: E::PayloadBuilderAttributes,
|
||||||
) -> eyre::Result<()> {
|
) -> eyre::Result<()> {
|
||||||
let first_event = self.payload_event_stream.next().await.unwrap()?;
|
let first_event = self.payload_event_stream.next().await.unwrap()?;
|
||||||
if let reth::payload::Events::Attributes(attr) = first_event {
|
if let reth::payload::Events::Attributes(attr) = first_event {
|
||||||
assert_eq!(attrs.timestamp, attr.timestamp());
|
assert_eq!(attrs.timestamp(), attr.timestamp());
|
||||||
} else {
|
} else {
|
||||||
panic!("Expect first event as payload attributes.")
|
panic!("Expect first event as payload attributes.")
|
||||||
}
|
}
|
||||||
@ -52,7 +49,7 @@ impl PayloadHelper<EthEngineTypes> {
|
|||||||
loop {
|
loop {
|
||||||
let payload = self.payload_builder.best_payload(payload_id).await.unwrap().unwrap();
|
let payload = self.payload_builder.best_payload(payload_id).await.unwrap().unwrap();
|
||||||
if payload.block().body.is_empty() {
|
if payload.block().body.is_empty() {
|
||||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(20)).await;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -60,7 +57,7 @@ impl PayloadHelper<EthEngineTypes> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Expects the next event to be a built payload event or panics
|
/// Expects the next event to be a built payload event or panics
|
||||||
pub async fn expect_built_payload(&mut self) -> eyre::Result<EthBuiltPayload> {
|
pub async fn expect_built_payload(&mut self) -> eyre::Result<E::BuiltPayload> {
|
||||||
let second_event = self.payload_event_stream.next().await.unwrap()?;
|
let second_event = self.payload_event_stream.next().await.unwrap()?;
|
||||||
if let reth::payload::Events::BuiltPayload(payload) = second_event {
|
if let reth::payload::Events::BuiltPayload(payload) = second_event {
|
||||||
Ok(payload)
|
Ok(payload)
|
||||||
@ -69,17 +66,3 @@ impl PayloadHelper<EthEngineTypes> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to create a new eth payload attributes
|
|
||||||
fn eth_payload_attributes() -> EthPayloadBuilderAttributes {
|
|
||||||
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
|
|
||||||
|
|
||||||
let attributes = PayloadAttributes {
|
|
||||||
timestamp,
|
|
||||||
prev_randao: B256::ZERO,
|
|
||||||
suggested_fee_recipient: Address::ZERO,
|
|
||||||
withdrawals: Some(vec![]),
|
|
||||||
parent_beacon_block_root: Some(B256::ZERO),
|
|
||||||
};
|
|
||||||
EthPayloadBuilderAttributes::new(B256::ZERO, attributes)
|
|
||||||
}
|
|
||||||
22
crates/e2e-test-utils/src/traits.rs
Normal file
22
crates/e2e-test-utils/src/traits.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use reth::rpc::types::{
|
||||||
|
engine::{ExecutionPayloadEnvelopeV3, OptimismExecutionPayloadEnvelopeV3},
|
||||||
|
ExecutionPayloadV3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The execution payload envelope type.
|
||||||
|
pub trait PayloadEnvelopeExt: Send + Sync + std::fmt::Debug {
|
||||||
|
/// Returns the execution payload V3 from the payload
|
||||||
|
fn execution_payload(&self) -> ExecutionPayloadV3;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PayloadEnvelopeExt for OptimismExecutionPayloadEnvelopeV3 {
|
||||||
|
fn execution_payload(&self) -> ExecutionPayloadV3 {
|
||||||
|
self.execution_payload.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PayloadEnvelopeExt for ExecutionPayloadEnvelopeV3 {
|
||||||
|
fn execution_payload(&self) -> ExecutionPayloadV3 {
|
||||||
|
self.execution_payload.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,19 +5,20 @@ use reth_primitives::{Address, Bytes, U256};
|
|||||||
/// One of the accounts of the genesis allocations.
|
/// One of the accounts of the genesis allocations.
|
||||||
pub struct Wallet {
|
pub struct Wallet {
|
||||||
inner: LocalWallet,
|
inner: LocalWallet,
|
||||||
|
nonce: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Wallet {
|
impl Wallet {
|
||||||
/// Creates a new account from one of the secret/pubkeys of the genesis allocations (test.json)
|
/// Creates a new account from one of the secret/pubkeys of the genesis allocations (test.json)
|
||||||
pub(crate) fn new(phrase: &str) -> Self {
|
pub(crate) fn new(phrase: &str) -> Self {
|
||||||
let inner = MnemonicBuilder::<English>::default().phrase(phrase).build().unwrap();
|
let inner = MnemonicBuilder::<English>::default().phrase(phrase).build().unwrap();
|
||||||
Self { inner }
|
Self { inner, nonce: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a static transfer and signs it
|
/// Creates a static transfer and signs it
|
||||||
pub async fn transfer_tx(&self) -> Bytes {
|
pub async fn transfer_tx(&mut self) -> Bytes {
|
||||||
let tx = TransactionRequest {
|
let tx = TransactionRequest {
|
||||||
nonce: Some(0),
|
nonce: Some(self.nonce),
|
||||||
value: Some(U256::from(100)),
|
value: Some(U256::from(100)),
|
||||||
to: Some(Address::random()),
|
to: Some(Address::random()),
|
||||||
gas_price: Some(20e9 as u128),
|
gas_price: Some(20e9 as u128),
|
||||||
@ -25,6 +26,7 @@ impl Wallet {
|
|||||||
chain_id: Some(1),
|
chain_id: Some(1),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
self.nonce += 1;
|
||||||
let signer = EthereumSigner::from(self.inner.clone());
|
let signer = EthereumSigner::from(self.inner.clone());
|
||||||
tx.build(&signer).await.unwrap().encoded_2718().into()
|
tx.build(&signer).await.unwrap().encoded_2718().into()
|
||||||
}
|
}
|
||||||
@ -27,8 +27,15 @@ reth-evm-ethereum.workspace = true
|
|||||||
eyre.workspace = true
|
eyre.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
reth.workspace = true
|
||||||
reth-db.workspace = true
|
reth-db.workspace = true
|
||||||
reth-exex.workspace = true
|
reth-exex.workspace = true
|
||||||
reth-node-api.workspace = true
|
reth-node-api.workspace = true
|
||||||
|
reth-node-core.workspace = true
|
||||||
|
reth-primitives.workspace = true
|
||||||
|
reth-e2e-test-utils.workspace = true
|
||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
|
tokio.workspace = true
|
||||||
|
futures-util.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
use node_e2e_tests::{node::NodeHelper, wallet::Wallet};
|
use crate::utils::eth_payload_attributes;
|
||||||
use reth::{
|
use reth::{
|
||||||
args::RpcServerArgs,
|
args::RpcServerArgs,
|
||||||
builder::{NodeBuilder, NodeConfig, NodeHandle},
|
builder::{NodeBuilder, NodeConfig, NodeHandle},
|
||||||
tasks::TaskManager,
|
tasks::TaskManager,
|
||||||
};
|
};
|
||||||
|
use reth_e2e_test_utils::{node::NodeHelper, wallet::Wallet};
|
||||||
use reth_node_ethereum::EthereumNode;
|
use reth_node_ethereum::EthereumNode;
|
||||||
use reth_primitives::{ChainSpecBuilder, Genesis, MAINNET};
|
use reth_primitives::{ChainSpecBuilder, Genesis, MAINNET};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -16,7 +17,7 @@ async fn can_run_eth_node() -> eyre::Result<()> {
|
|||||||
let exec = exec.executor();
|
let exec = exec.executor();
|
||||||
|
|
||||||
// Chain spec with test allocs
|
// Chain spec with test allocs
|
||||||
let genesis: Genesis = serde_json::from_str(include_str!("../../assets/genesis.json")).unwrap();
|
let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap();
|
||||||
let chain_spec = Arc::new(
|
let chain_spec = Arc::new(
|
||||||
ChainSpecBuilder::default()
|
ChainSpecBuilder::default()
|
||||||
.chain(MAINNET.chain)
|
.chain(MAINNET.chain)
|
||||||
@ -39,11 +40,11 @@ async fn can_run_eth_node() -> eyre::Result<()> {
|
|||||||
let mut node = NodeHelper::new(node).await?;
|
let mut node = NodeHelper::new(node).await?;
|
||||||
|
|
||||||
// Configure wallet from test mnemonic and create dummy transfer tx
|
// Configure wallet from test mnemonic and create dummy transfer tx
|
||||||
let wallet = Wallet::default();
|
let mut wallet = Wallet::default();
|
||||||
let raw_tx = wallet.transfer_tx().await;
|
let raw_tx = wallet.transfer_tx().await;
|
||||||
|
|
||||||
// make the node advance
|
// make the node advance
|
||||||
node.advance(raw_tx).await?;
|
node.advance(raw_tx, eth_payload_attributes).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -56,7 +57,7 @@ async fn can_run_eth_node_with_auth_engine_api_over_ipc() -> eyre::Result<()> {
|
|||||||
let exec = exec.executor();
|
let exec = exec.executor();
|
||||||
|
|
||||||
// Chain spec with test allocs
|
// Chain spec with test allocs
|
||||||
let genesis: Genesis = serde_json::from_str(include_str!("../../assets/genesis.json")).unwrap();
|
let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap();
|
||||||
let chain_spec = Arc::new(
|
let chain_spec = Arc::new(
|
||||||
ChainSpecBuilder::default()
|
ChainSpecBuilder::default()
|
||||||
.chain(MAINNET.chain)
|
.chain(MAINNET.chain)
|
||||||
@ -78,11 +79,11 @@ async fn can_run_eth_node_with_auth_engine_api_over_ipc() -> eyre::Result<()> {
|
|||||||
let mut node = NodeHelper::new(node).await?;
|
let mut node = NodeHelper::new(node).await?;
|
||||||
|
|
||||||
// Configure wallet from test mnemonic and create dummy transfer tx
|
// Configure wallet from test mnemonic and create dummy transfer tx
|
||||||
let wallet = Wallet::default();
|
let mut wallet = Wallet::default();
|
||||||
let raw_tx = wallet.transfer_tx().await;
|
let raw_tx = wallet.transfer_tx().await;
|
||||||
|
|
||||||
// make the node advance
|
// make the node advance
|
||||||
node.advance(raw_tx).await?;
|
node.advance(raw_tx, crate::utils::eth_payload_attributes).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -95,7 +96,7 @@ async fn test_failed_run_eth_node_with_no_auth_engine_api_over_ipc_opts() -> eyr
|
|||||||
let exec = exec.executor();
|
let exec = exec.executor();
|
||||||
|
|
||||||
// Chain spec with test allocs
|
// Chain spec with test allocs
|
||||||
let genesis: Genesis = serde_json::from_str(include_str!("../../assets/genesis.json")).unwrap();
|
let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap();
|
||||||
let chain_spec = Arc::new(
|
let chain_spec = Arc::new(
|
||||||
ChainSpecBuilder::default()
|
ChainSpecBuilder::default()
|
||||||
.chain(MAINNET.chain)
|
.chain(MAINNET.chain)
|
||||||
@ -1,5 +1,6 @@
|
|||||||
mod dev;
|
mod dev;
|
||||||
mod eth;
|
mod eth;
|
||||||
mod p2p;
|
mod p2p;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
@ -1,11 +1,12 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use node_e2e_tests::{node::NodeHelper, wallet::Wallet};
|
use crate::utils::eth_payload_attributes;
|
||||||
use reth::{
|
use reth::{
|
||||||
args::{DiscoveryArgs, NetworkArgs, RpcServerArgs},
|
args::{DiscoveryArgs, NetworkArgs, RpcServerArgs},
|
||||||
builder::{NodeBuilder, NodeConfig, NodeHandle},
|
builder::{NodeBuilder, NodeConfig, NodeHandle},
|
||||||
tasks::TaskManager,
|
tasks::TaskManager,
|
||||||
};
|
};
|
||||||
|
use reth_e2e_test_utils::{node::NodeHelper, wallet::Wallet};
|
||||||
use reth_node_ethereum::EthereumNode;
|
use reth_node_ethereum::EthereumNode;
|
||||||
use reth_primitives::{ChainSpecBuilder, Genesis, MAINNET};
|
use reth_primitives::{ChainSpecBuilder, Genesis, MAINNET};
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ async fn can_sync() -> eyre::Result<()> {
|
|||||||
let tasks = TaskManager::current();
|
let tasks = TaskManager::current();
|
||||||
let exec = tasks.executor();
|
let exec = tasks.executor();
|
||||||
|
|
||||||
let genesis: Genesis = serde_json::from_str(include_str!("../../assets/genesis.json")).unwrap();
|
let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap();
|
||||||
let chain_spec = Arc::new(
|
let chain_spec = Arc::new(
|
||||||
ChainSpecBuilder::default()
|
ChainSpecBuilder::default()
|
||||||
.chain(MAINNET.chain)
|
.chain(MAINNET.chain)
|
||||||
@ -52,7 +53,7 @@ async fn can_sync() -> eyre::Result<()> {
|
|||||||
|
|
||||||
let mut second_node = NodeHelper::new(node).await?;
|
let mut second_node = NodeHelper::new(node).await?;
|
||||||
|
|
||||||
let wallet = Wallet::default();
|
let mut wallet = Wallet::default();
|
||||||
let raw_tx = wallet.transfer_tx().await;
|
let raw_tx = wallet.transfer_tx().await;
|
||||||
|
|
||||||
// Make them peer
|
// Make them peer
|
||||||
@ -64,13 +65,13 @@ async fn can_sync() -> eyre::Result<()> {
|
|||||||
second_node.network.expect_session().await;
|
second_node.network.expect_session().await;
|
||||||
|
|
||||||
// Make the first node advance
|
// Make the first node advance
|
||||||
let (block_hash, tx_hash) = first_node.advance(raw_tx.clone()).await?;
|
let (block_hash, tx_hash) = first_node.advance(raw_tx.clone(), eth_payload_attributes).await?;
|
||||||
|
|
||||||
// only send forkchoice update to second node
|
// only send forkchoice update to second node
|
||||||
second_node.engine_api.update_forkchoice(block_hash).await?;
|
second_node.engine_api.update_forkchoice(block_hash).await?;
|
||||||
|
|
||||||
// expect second node advanced via p2p gossip
|
// expect second node advanced via p2p gossip
|
||||||
second_node.assert_new_block(tx_hash, block_hash).await?;
|
second_node.assert_new_block(tx_hash, block_hash, 1).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
15
crates/node-ethereum/tests/e2e/utils.rs
Normal file
15
crates/node-ethereum/tests/e2e/utils.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use reth::rpc::types::engine::PayloadAttributes;
|
||||||
|
use reth_payload_builder::EthPayloadBuilderAttributes;
|
||||||
|
use reth_primitives::{Address, B256};
|
||||||
|
|
||||||
|
/// Helper function to create a new eth payload attributes
|
||||||
|
pub(crate) fn eth_payload_attributes(timestamp: u64) -> EthPayloadBuilderAttributes {
|
||||||
|
let attributes = PayloadAttributes {
|
||||||
|
timestamp,
|
||||||
|
prev_randao: B256::ZERO,
|
||||||
|
suggested_fee_recipient: Address::ZERO,
|
||||||
|
withdrawals: Some(vec![]),
|
||||||
|
parent_beacon_block_root: Some(B256::ZERO),
|
||||||
|
};
|
||||||
|
EthPayloadBuilderAttributes::new(B256::ZERO, attributes)
|
||||||
|
}
|
||||||
@ -52,8 +52,11 @@ thiserror.workspace = true
|
|||||||
jsonrpsee.workspace = true
|
jsonrpsee.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
reth.workspace = true
|
||||||
reth-db.workspace = true
|
reth-db.workspace = true
|
||||||
reth-revm = { workspace = true, features = ["test-utils"]}
|
reth-revm = { workspace = true, features = ["test-utils"]}
|
||||||
|
reth-e2e-test-utils.workspace = true
|
||||||
|
tokio.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
optimism = [
|
optimism = [
|
||||||
|
|||||||
96
crates/optimism/node/tests/assets/genesis.json
Normal file
96
crates/optimism/node/tests/assets/genesis.json
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"chainId": 1,
|
||||||
|
"homesteadBlock": 0,
|
||||||
|
"daoForkSupport": true,
|
||||||
|
"eip150Block": 0,
|
||||||
|
"eip155Block": 0,
|
||||||
|
"eip158Block": 0,
|
||||||
|
"byzantiumBlock": 0,
|
||||||
|
"constantinopleBlock": 0,
|
||||||
|
"petersburgBlock": 0,
|
||||||
|
"istanbulBlock": 0,
|
||||||
|
"muirGlacierBlock": 0,
|
||||||
|
"berlinBlock": 0,
|
||||||
|
"londonBlock": 0,
|
||||||
|
"arrowGlacierBlock": 0,
|
||||||
|
"grayGlacierBlock": 0,
|
||||||
|
"shanghaiTime": 0,
|
||||||
|
"cancunTime": 0,
|
||||||
|
"terminalTotalDifficulty": "0x0",
|
||||||
|
"terminalTotalDifficultyPassed": true
|
||||||
|
},
|
||||||
|
"nonce": "0x0",
|
||||||
|
"timestamp": "0x0",
|
||||||
|
"extraData": "0x00",
|
||||||
|
"gasLimit": "0x1c9c380",
|
||||||
|
"difficulty": "0x0",
|
||||||
|
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"coinbase": "0x0000000000000000000000000000000000000000",
|
||||||
|
"alloc": {
|
||||||
|
"0x14dc79964da2c08b23698b3d3cc7ca32193d9955": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0x1cbd3b2770909d4e10f157cabc84c7264073c9ec": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0x2546bcd3c84621e976d8185a91a922ae77ecec30": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0x70997970c51812dc3a010c7d01b50e0d17dc79c8": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0x71be63f3384f5fb98995898a86b02fb2426c5788": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0x8626f6940e2eb28930efb4cef49b2d1f2c9c1199": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0x90f79bf6eb2c4f870365e785982e1f101e93b906": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0x976ea74026e726554db657fa54763abd0c3a0aa9": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0x9c41de96b2088cdc640c6182dfcf5491dc574a57": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0xa0ee7a142d267c1f36714e4a8f75612f20a79720": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0xbcd4042de499d14e55001ccbb24a551f3b954096": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0xbda5747bfd65f08deb54cb465eb87d40e51b197e": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0xcd3b766ccdd6ae721141f452c550ca635964ce71": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0xdd2fd4581271e230360230f9337d5c0430bf44c0": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0xdf3e18d64bc6a983f673ab319ccae4f1a57c7097": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
},
|
||||||
|
"0xfabb0ac9d68b0b445fb7357272ff202c5651694a": {
|
||||||
|
"balance": "0xd3c21bcecceda1000000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"number": "0x0"
|
||||||
|
}
|
||||||
7
crates/optimism/node/tests/e2e/main.rs
Normal file
7
crates/optimism/node/tests/e2e/main.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#[cfg(feature = "optimism")]
|
||||||
|
mod p2p;
|
||||||
|
|
||||||
|
#[cfg(feature = "optimism")]
|
||||||
|
mod utils;
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
78
crates/optimism/node/tests/e2e/p2p.rs
Normal file
78
crates/optimism/node/tests/e2e/p2p.rs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::utils::optimism_payload_attributes;
|
||||||
|
use reth::{
|
||||||
|
args::{DiscoveryArgs, NetworkArgs, RpcServerArgs},
|
||||||
|
builder::{NodeBuilder, NodeConfig, NodeHandle},
|
||||||
|
tasks::TaskManager,
|
||||||
|
};
|
||||||
|
use reth_e2e_test_utils::{node::NodeHelper, wallet::Wallet};
|
||||||
|
use reth_node_optimism::node::OptimismNode;
|
||||||
|
use reth_primitives::{ChainSpecBuilder, Genesis, MAINNET};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn can_sync() -> eyre::Result<()> {
|
||||||
|
reth_tracing::init_test_tracing();
|
||||||
|
|
||||||
|
let tasks = TaskManager::current();
|
||||||
|
let exec = tasks.executor();
|
||||||
|
|
||||||
|
let genesis: Genesis = serde_json::from_str(include_str!("../assets/genesis.json")).unwrap();
|
||||||
|
let chain_spec = Arc::new(
|
||||||
|
ChainSpecBuilder::default()
|
||||||
|
.chain(MAINNET.chain)
|
||||||
|
.genesis(genesis)
|
||||||
|
.cancun_activated()
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let network_config = NetworkArgs {
|
||||||
|
discovery: DiscoveryArgs { disable_discovery: true, ..DiscoveryArgs::default() },
|
||||||
|
..NetworkArgs::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let node_config = NodeConfig::test()
|
||||||
|
.with_chain(chain_spec)
|
||||||
|
.with_network(network_config)
|
||||||
|
.with_unused_ports()
|
||||||
|
.with_rpc(RpcServerArgs::default().with_unused_ports().with_http());
|
||||||
|
|
||||||
|
let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config.clone())
|
||||||
|
.testing_node(exec.clone())
|
||||||
|
.node(OptimismNode::default())
|
||||||
|
.launch()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let mut first_node = NodeHelper::new(node.clone()).await?;
|
||||||
|
|
||||||
|
let NodeHandle { node, node_exit_future: _ } = NodeBuilder::new(node_config)
|
||||||
|
.testing_node(exec)
|
||||||
|
.node(OptimismNode::default())
|
||||||
|
.launch()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let mut second_node = NodeHelper::new(node).await?;
|
||||||
|
|
||||||
|
let mut wallet = Wallet::default();
|
||||||
|
let raw_tx = wallet.transfer_tx().await;
|
||||||
|
|
||||||
|
// Make them peer
|
||||||
|
first_node.network.add_peer(second_node.network.record()).await;
|
||||||
|
second_node.network.add_peer(first_node.network.record()).await;
|
||||||
|
|
||||||
|
// Make sure they establish a new session
|
||||||
|
first_node.network.expect_session().await;
|
||||||
|
second_node.network.expect_session().await;
|
||||||
|
|
||||||
|
// Make the first node advance
|
||||||
|
let (block_hash, tx_hash) =
|
||||||
|
first_node.advance(raw_tx.clone(), optimism_payload_attributes).await?;
|
||||||
|
|
||||||
|
// only send forkchoice update to second node
|
||||||
|
second_node.engine_api.update_forkchoice(block_hash).await?;
|
||||||
|
|
||||||
|
// expect second node advanced via p2p gossip
|
||||||
|
second_node.assert_new_block(tx_hash, block_hash, 1).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
22
crates/optimism/node/tests/e2e/utils.rs
Normal file
22
crates/optimism/node/tests/e2e/utils.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use reth::rpc::types::engine::PayloadAttributes;
|
||||||
|
use reth_node_optimism::OptimismPayloadBuilderAttributes;
|
||||||
|
use reth_payload_builder::EthPayloadBuilderAttributes;
|
||||||
|
use reth_primitives::{Address, B256};
|
||||||
|
|
||||||
|
/// Helper function to create a new eth payload attributes
|
||||||
|
pub(crate) fn optimism_payload_attributes(timestamp: u64) -> OptimismPayloadBuilderAttributes {
|
||||||
|
let attributes = PayloadAttributes {
|
||||||
|
timestamp,
|
||||||
|
prev_randao: B256::ZERO,
|
||||||
|
suggested_fee_recipient: Address::ZERO,
|
||||||
|
withdrawals: Some(vec![]),
|
||||||
|
parent_beacon_block_root: Some(B256::ZERO),
|
||||||
|
};
|
||||||
|
|
||||||
|
OptimismPayloadBuilderAttributes {
|
||||||
|
payload_attributes: EthPayloadBuilderAttributes::new(B256::ZERO, attributes),
|
||||||
|
transactions: vec![],
|
||||||
|
no_tx_pool: false,
|
||||||
|
gas_limit: Some(30_000_000),
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user