Skip to content

Commit a0ee5b8

Browse files
cichaczem0xForerunner
authored andcommitted
Make test_eth_api_receipt work
1 parent f9ad672 commit a0ee5b8

File tree

5 files changed

+192
-92
lines changed

5 files changed

+192
-92
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/world/node/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ alloy-eips.workspace = true
7373
alloy-rpc-types-engine.workspace = true
7474
alloy-consensus.workspace = true
7575

76+
op-alloy-rpc-types.workspace = true
7677
op-alloy-rpc-types-engine.workspace = true
7778

7879
tokio-tungstenite.workspace = true

crates/world/node/tests/e2e-testsuite/actions.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ use eyre::eyre::{eyre, Result};
66
use flashblocks_primitives::p2p::Authorization;
77
use flashblocks_rpc::{engine::FlashblocksEngineApiExtClient, op::OpApiExtClient};
88
use futures::future::BoxFuture;
9+
use op_alloy_rpc_types::OpTransactionReceipt;
910
use op_alloy_rpc_types_engine::OpExecutionPayloadEnvelopeV3;
1011
use reth::rpc::api::{EngineApiClient, EthApiClient};
1112
use reth_e2e_test_utils::testsuite::{actions::Action, Environment};
1213
use reth_optimism_node::{OpEngineTypes, OpPayloadAttributes};
13-
use reth_optimism_primitives::OpReceipt;
1414
use revm_primitives::{Address, Bytes, B256, U256};
1515
use std::{fmt::Debug, marker::PhantomData, time::Duration};
1616
use tokio::time::sleep;
@@ -643,7 +643,7 @@ pub struct EthGetTransactionReceipt {
643643
/// Duration in milliseconds of backoff before fetching the receipt
644644
pub backoff: u64,
645645
/// Tx sender for receipt results
646-
pub tx: tokio::sync::mpsc::Sender<Vec<Option<OpReceipt>>>,
646+
pub tx: tokio::sync::mpsc::Sender<Vec<Option<OpTransactionReceipt>>>,
647647
}
648648

649649
impl EthGetTransactionReceipt {
@@ -652,7 +652,7 @@ impl EthGetTransactionReceipt {
652652
hash: B256,
653653
node_idxs: Vec<usize>,
654654
backoff: u64,
655-
tx: tokio::sync::mpsc::Sender<Vec<Option<OpReceipt>>>,
655+
tx: tokio::sync::mpsc::Sender<Vec<Option<OpTransactionReceipt>>>,
656656
) -> Self {
657657
Self {
658658
hash,
@@ -674,12 +674,12 @@ impl Action<OpEngineTypes> for EthGetTransactionReceipt {
674674
let mut receipts = vec![];
675675
for node_idx in &self.node_idxs {
676676
let rpc_client = env.node_clients[*node_idx].rpc.clone();
677-
let receipt: Option<OpReceipt> =
677+
let receipt: Option<OpTransactionReceipt> =
678678
EthApiClient::<
679679
TransactionRequest,
680680
Transaction,
681681
alloy_rpc_types_eth::Block,
682-
OpReceipt,
682+
OpTransactionReceipt,
683683
Header,
684684
>::transaction_receipt(&rpc_client, self.hash)
685685
.await?;

crates/world/node/tests/e2e-testsuite/setup.rs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
use alloy_eips::eip2718::Encodable2718;
12
use alloy_genesis::{Genesis, GenesisAccount};
3+
use alloy_primitives::{address, Address, Sealed};
24
use eyre::eyre::eyre;
5+
use op_alloy_consensus::{OpTxEnvelope, TxDeposit};
36
use reth::api::TreeConfig;
47
use reth::args::PayloadBuilderArgs;
58
use reth::builder::{EngineNodeLauncher, Node, NodeBuilder, NodeConfig, NodeHandle};
69
use reth::network::PeersHandleProvider;
10+
use reth::payload::{EthPayloadBuilderAttributes, PayloadId};
711
use reth::tasks::TaskManager;
812
use reth_e2e_test_utils::testsuite::{Environment, NodeClient};
913
use reth_e2e_test_utils::{Adapter, NodeHelperType, TmpDB};
@@ -17,7 +21,8 @@ use reth_optimism_chainspec::{OpChainSpec, OpChainSpecBuilder};
1721
use reth_optimism_node::OpEngineTypes;
1822
use reth_optimism_primitives::OpPrimitives;
1923
use reth_provider::providers::{BlockchainProvider, ChainStorage};
20-
use revm_primitives::U256;
24+
use revm_primitives::TxKind;
25+
use revm_primitives::{Bytes, U256};
2126
use std::{
2227
collections::BTreeMap,
2328
ops::Range,
@@ -40,6 +45,68 @@ use world_chain_rpc::{EthApiExtServer, SequencerClient, WorldChainEthApiExt};
4045

4146
const GENESIS: &str = include_str!("../res/genesis.json");
4247

48+
// Optimism protocol constants - these addresses are defined by the Optimism specification
49+
const L1_BLOCK_PREDEPLOY: Address = address!("4200000000000000000000000000000000000015");
50+
const SYSTEM_DEPOSITOR: Address = address!("DeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001");
51+
52+
fn create_l1_attributes_deposit_tx() -> Bytes {
53+
const SELECTOR: [u8; 4] = [0x44, 0x0a, 0x5e, 0x20];
54+
let mut calldata = SELECTOR.to_vec();
55+
calldata.extend_from_slice(&[0u8; 32]);
56+
calldata.extend_from_slice(&[0u8; 32]);
57+
calldata.extend_from_slice(&[0u8; 32]);
58+
calldata.extend_from_slice(&[0u8; 32]);
59+
calldata.extend_from_slice(&[0u8; 32]);
60+
61+
let deposit = TxDeposit {
62+
source_hash: revm_primitives::B256::ZERO,
63+
from: SYSTEM_DEPOSITOR,
64+
to: TxKind::Call(L1_BLOCK_PREDEPLOY),
65+
mint: 0u128,
66+
value: U256::ZERO,
67+
gas_limit: 1_000_000,
68+
is_system_transaction: true,
69+
input: calldata.into(),
70+
};
71+
72+
let sealed_deposit = Sealed::new_unchecked(deposit, revm_primitives::B256::ZERO);
73+
let envelope = OpTxEnvelope::Deposit(sealed_deposit);
74+
let mut buf = Vec::new();
75+
envelope.encode_2718(&mut buf);
76+
buf.into()
77+
}
78+
79+
/// L1 attributes deposit transaction - required as the first transaction in Optimism blocks
80+
pub static TX_SET_L1_BLOCK: LazyLock<Bytes> = LazyLock::new(create_l1_attributes_deposit_tx);
81+
82+
/// Generate basic Optimism payload attributes for testing
83+
pub fn optimism_payload_attributes(
84+
timestamp: u64,
85+
) -> reth_optimism_payload_builder::OpPayloadBuilderAttributes<op_alloy_consensus::OpTxEnvelope> {
86+
use alloy_eips::eip4895::Withdrawals;
87+
use alloy_primitives::b64;
88+
use revm_primitives::{Address, B256};
89+
90+
let eth_attrs = EthPayloadBuilderAttributes {
91+
id: PayloadId::new([0u8; 8]),
92+
parent: B256::ZERO,
93+
timestamp,
94+
suggested_fee_recipient: Address::random(),
95+
prev_randao: B256::random(),
96+
withdrawals: Withdrawals::default(),
97+
parent_beacon_block_root: Some(B256::ZERO),
98+
};
99+
100+
reth_optimism_payload_builder::OpPayloadBuilderAttributes {
101+
payload_attributes: eth_attrs,
102+
transactions: vec![],
103+
no_tx_pool: false,
104+
eip_1559_params: Some(b64!("0000000800000008")),
105+
gas_limit: Some(30_000_000),
106+
min_base_fee: None,
107+
}
108+
}
109+
43110
pub struct WorldChainTestingNodeContext<T: WorldChainTestContextBounds>
44111
where
45112
WorldChainNode<T>: WorldChainNodeTestBounds<T>,

crates/world/node/tests/e2e-testsuite/testsuite.rs

Lines changed: 117 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use reth::primitives::RecoveredBlock;
1010
use reth_e2e_test_utils::testsuite::actions::Action;
1111
use reth_e2e_test_utils::transaction::TransactionTestContext;
1212
use reth_node_api::{Block, PayloadAttributes};
13-
use reth_optimism_node::utils::optimism_payload_attributes;
1413
use reth_optimism_node::OpPayloadAttributes;
1514
use reth_optimism_payload_builder::payload_id_optimism;
1615
use reth_optimism_primitives::OpTransactionSigned;
@@ -27,7 +26,7 @@ use world_chain_node::context::FlashblocksContext;
2726
use world_chain_test::node::{raw_pbh_bundle_bytes, tx};
2827
use world_chain_test::utils::signer;
2928

30-
use crate::setup::{setup, CHAIN_SPEC};
29+
use crate::setup::{optimism_payload_attributes, setup, CHAIN_SPEC};
3130

3231
#[tokio::test]
3332
async fn test_can_build_pbh_payload() -> eyre::Result<()> {
@@ -354,90 +353,122 @@ async fn test_flashblocks() -> eyre::Result<()> {
354353
Ok(())
355354
}
356355

357-
// #[tokio::test(flavor = "multi_thread")]
358-
// async fn test_eth_api_receipt() -> eyre::Result<()> {
359-
// reth_tracing::init_test_tracing();
360-
// let (_, nodes, _tasks, mut env) =
361-
// setup::<FlashblocksContext>(3, optimism_payload_attributes).await?;
362-
363-
// let ext_context = nodes[0].ext_context.clone();
364-
365-
// let block_hash = nodes[0].node.block_hash(0);
366-
367-
// let authorization_generator = move |attrs: OpPayloadAttributes| {
368-
// let authorizer_sk = SigningKey::from_bytes(&[0; 32]);
369-
370-
// let payload_id = payload_id_optimism(&block_hash, &attrs, 3);
371-
372-
// Authorization::new(
373-
// payload_id,
374-
// attrs.timestamp(),
375-
// &authorizer_sk,
376-
// ext_context
377-
// .flashblocks_handle
378-
// .builder_sk()
379-
// .unwrap()
380-
// .verifying_key(),
381-
// )
382-
// };
383-
384-
// let timestamp = std::time::SystemTime::now()
385-
// .duration_since(std::time::UNIX_EPOCH)
386-
// .unwrap()
387-
// .as_secs();
388-
389-
// let (sender, _) = tokio::sync::mpsc::channel(1);
390-
391-
// // Compose a Mine Block action with an eth_getTransactionReceipt action
392-
// let attributes = OpPayloadAttributes {
393-
// payload_attributes: alloy_rpc_types_engine::PayloadAttributes {
394-
// timestamp,
395-
// prev_randao: B256::random(),
396-
// suggested_fee_recipient: Address::random(),
397-
// withdrawals: Some(vec![]),
398-
// parent_beacon_block_root: Some(B256::ZERO),
399-
// },
400-
// transactions: Some(vec![crate::setup::TX_SET_L1_BLOCK.into()]),
401-
// no_tx_pool: Some(false),
402-
// eip_1559_params: Some(b64!("0000000800000008")),
403-
// gas_limit: Some(30_000_000),
404-
// };
405-
406-
// let mock_tx =
407-
// TransactionTestContext::transfer_tx(nodes[0].node.inner.chain_spec().chain_id(), signer(0))
408-
// .await;
409-
410-
// let raw_tx: Bytes = mock_tx.encoded_2718().into();
411-
412-
// nodes[0].node.rpc.inject_tx(raw_tx.clone()).await?;
413-
414-
// let mine_block = crate::actions::AssertMineBlock::new(
415-
// 0,
416-
// vec![raw_tx],
417-
// Some(B256::ZERO),
418-
// attributes,
419-
// authorization_generator,
420-
// std::time::Duration::from_millis(2000),
421-
// true,
422-
// false,
423-
// sender,
424-
// )
425-
// .await;
426-
427-
// let (tx, mut rx) = tokio::sync::mpsc::channel(1);
428-
429-
// // 200ms backoff should be enough time to fetch the pending receipt
430-
// let transaction_receipt =
431-
// crate::actions::EthGetTransactionReceipt::new(*mock_tx.hash(), vec![0, 1, 2], 230, tx);
432-
433-
// let mut action = crate::actions::EthApiAction::new(mine_block, transaction_receipt);
434-
// action.execute(&mut env).await?;
435-
436-
// let _receipts = rx.recv().await.expect("should receive receipts");
437-
// info!("Receipts: {:?}", _receipts);
438-
// // TODO: Assertions once EthApi is fixed
439-
// Ok(())
440-
// }
356+
#[tokio::test(flavor = "multi_thread")]
357+
async fn test_eth_api_receipt() -> eyre::Result<()> {
358+
reth_tracing::init_test_tracing();
359+
let (_, nodes, _tasks, mut env) =
360+
setup::<FlashblocksContext>(3, optimism_payload_attributes).await?;
361+
362+
let ext_context = nodes[0].ext_context.clone();
363+
364+
let block_hash = nodes[0].node.block_hash(0);
365+
366+
let authorization_generator = move |attrs: OpPayloadAttributes| {
367+
let authorizer_sk = SigningKey::from_bytes(&[0; 32]);
368+
369+
let payload_id = payload_id_optimism(&block_hash, &attrs, 3);
370+
371+
Authorization::new(
372+
payload_id,
373+
attrs.timestamp(),
374+
&authorizer_sk,
375+
ext_context
376+
.flashblocks_handle
377+
.builder_sk()
378+
.unwrap()
379+
.verifying_key(),
380+
)
381+
};
382+
383+
let timestamp = std::time::SystemTime::now()
384+
.duration_since(std::time::UNIX_EPOCH)
385+
.unwrap()
386+
.as_secs();
387+
388+
let (sender, _) = tokio::sync::mpsc::channel(1);
389+
390+
// Compose a Mine Block action with an eth_getTransactionReceipt action
391+
let attributes = OpPayloadAttributes {
392+
payload_attributes: alloy_rpc_types_engine::PayloadAttributes {
393+
timestamp,
394+
prev_randao: B256::random(),
395+
suggested_fee_recipient: Address::random(),
396+
withdrawals: Some(vec![]),
397+
parent_beacon_block_root: Some(B256::ZERO),
398+
},
399+
transactions: Some(vec![crate::setup::TX_SET_L1_BLOCK.clone()]),
400+
no_tx_pool: Some(false),
401+
eip_1559_params: Some(b64!("0000000800000008")),
402+
gas_limit: Some(30_000_000),
403+
min_base_fee: None,
404+
};
405+
406+
let mock_tx =
407+
TransactionTestContext::transfer_tx(nodes[0].node.inner.chain_spec().chain_id(), signer(0))
408+
.await;
409+
410+
let raw_tx: Bytes = mock_tx.encoded_2718().into();
411+
412+
nodes[0].node.rpc.inject_tx(raw_tx.clone()).await?;
413+
414+
let mine_block = crate::actions::AssertMineBlock::new(
415+
0,
416+
vec![],
417+
None,
418+
attributes,
419+
authorization_generator,
420+
std::time::Duration::from_millis(2000),
421+
true,
422+
false,
423+
sender,
424+
)
425+
.await;
426+
427+
let (tx, mut rx) = tokio::sync::mpsc::channel(1);
428+
429+
let transaction_receipt =
430+
crate::actions::EthGetTransactionReceipt::new(*mock_tx.hash(), vec![0, 1, 2], 230, tx);
431+
432+
let mut action = crate::actions::EthApiAction::new(mine_block, transaction_receipt);
433+
action.execute(&mut env).await?;
434+
435+
let receipts = rx.recv().await.expect("should receive receipts");
436+
info!("Receipts: {:?}", receipts);
437+
438+
assert_eq!(
439+
receipts.len(),
440+
3,
441+
"Should receive receipts from all 3 nodes"
442+
);
443+
444+
for (idx, receipt_opt) in receipts.iter().enumerate() {
445+
assert!(
446+
receipt_opt.is_some(),
447+
"Node {} should return a receipt",
448+
idx
449+
);
450+
}
451+
452+
let receipts: Vec<_> = receipts.into_iter().map(|r| r.unwrap()).collect();
453+
454+
for (idx, receipt) in receipts.iter().enumerate() {
455+
assert!(
456+
receipt.inner.inner.status(),
457+
"Transaction should succeed on node {}",
458+
idx
459+
);
460+
}
461+
462+
for (idx, receipt) in receipts.iter().enumerate().skip(1) {
463+
assert_eq!(
464+
receipt, &receipts[0],
465+
"Node {} receipt doesn't match node 0",
466+
idx
467+
);
468+
}
469+
470+
Ok(())
471+
}
441472

442473
#[tokio::test(flavor = "multi_thread")]
443474
async fn test_eth_api_call() -> eyre::Result<()> {

0 commit comments

Comments
 (0)