Skip to content

Instantly share code, notes, and snippets.

@yongkangc
Last active September 5, 2025 04:11
Show Gist options
  • Select an option

  • Save yongkangc/a059d435f365fdaa2c457d1a38676e43 to your computer and use it in GitHub Desktop.

Select an option

Save yongkangc/a059d435f365fdaa2c457d1a38676e43 to your computer and use it in GitHub Desktop.
reth e2e test actions

Reth E2E Test Actions Reference

This document provides a comprehensive reference for all available actions in the Reth e2e test framework.

Core Infrastructure Actions

Action Purpose Key Parameters Example Usage
WaitForBlockHeight Wait for a node to reach specific block height height: u64, node: NodeId WaitForBlockHeight::new(5, NodeId::new(0))
AssertPeers Verify peer connection count expected_peers: usize, node: NodeId AssertPeers::new(2, NodeId::new(0))
ConnectPeers Establish connections between nodes from: NodeId, to: NodeId ConnectPeers::new(NodeId::new(0), NodeId::new(1))
DisconnectPeers Disconnect specific peer connections from: NodeId, to: NodeId DisconnectPeers::new(NodeId::new(0), NodeId::new(1))

Block Production & Management

Action Purpose Key Parameters Example Usage
ProduceBlocks Produce a specified number of blocks count: u64, interval: Duration, node: Option<NodeId> ProduceBlocks::new(3, Duration::from_secs(1), None)
MakeCanonical Set a block as the canonical head block_tag: String, node: NodeId MakeCanonical::new("my_block", NodeId::new(0))
CaptureBlock Capture and tag a block for later reference block_tag: String, node: NodeId CaptureBlock::new("genesis", NodeId::new(0))
AssertBlockHash Verify a block's hash matches expected value block_tag: String, expected_hash: B256, node: NodeId AssertBlockHash::new("block1", hash, NodeId::new(0))

Engine API Actions

Action Purpose Key Parameters Example Usage
NewPayloadV3 Submit new payload via Engine API payload: ExecutionPayloadV3, versioned_hashes: Vec<B256> NewPayloadV3::new(payload, hashes, beacon_root)
ForkchoiceUpdate Update fork choice state state: ForkchoiceState, attributes: Option<PayloadAttributes> ForkchoiceUpdate::new(state, None)
GetPayload Retrieve built payload by ID payload_id: PayloadId, node: NodeId GetPayload::new(id, NodeId::new(0))

Fork Management & Reorgs

Action Purpose Key Parameters Example Usage
CreateFork Create a new fork from existing block from_block: String, fork_name: String CreateFork::new("genesis", "fork_a")
SwitchFork Switch active chain to specified fork fork_name: String, node: NodeId SwitchFork::new("fork_a", NodeId::new(0))
ReorgToDepth Trigger reorg to specified depth depth: u64, node: NodeId ReorgToDepth::new(3, NodeId::new(0))

Node Operations

Action Purpose Key Parameters Example Usage
StartNode Start a new node instance config: NodeConfig StartNode::new(config)
StopNode Stop running node node: NodeId StopNode::new(NodeId::new(0))
RestartNode Restart existing node node: NodeId, config: Option<NodeConfig> RestartNode::new(NodeId::new(0), None)

Transaction Actions

Action Purpose Key Parameters Example Usage
SendTransaction Submit transaction to mempool tx: Transaction, node: NodeId SendTransaction::new(tx, NodeId::new(0))
SendRawTransaction Submit raw transaction bytes raw_tx: Bytes, node: NodeId SendRawTransaction::new(bytes, NodeId::new(0))

Custom Trie Corruption Test Actions

Action Purpose Key Parameters Example Usage
SendRawPayload Send payload from JSON file payload_path: String, node: NodeId, format: PayloadFormat SendRawPayload::new("3311_first.json", NodeId::new(0), PayloadFormat::Array)
AdjustAndSendPayload Adjust parent hash and send payload payload_json: String, parent_block_tag: String, format: PayloadFormat, result_tag: String AdjustAndSendPayload::new(json, "genesis", PayloadFormat::Array, "adjusted_block")
VerifyStorageRoot Verify account storage root address: Address, expected_root: B256, node: NodeId VerifyStorageRoot::new(addr, root, NodeId::new(0))
CompareStorageValues Compare storage values between nodes address: Address, key: B256, node1: NodeId, node2: NodeId CompareStorageValues::new(addr, key, n1, n2)
DumpAccountStorage Debug dump of account storage address: Address, node: NodeId DumpAccountStorage::new(addr, NodeId::new(0))

Payload Formats

PayloadFormat Enum

pub enum PayloadFormat {
    Direct,  // JSON contains ExecutionPayloadV3 directly
    Array,   // JSON contains [payload, blob_hashes, parent_beacon_root, ...]
}

Array Format Structure

[
  {
    "parentHash": "0x...",
    "feeRecipient": "0x...",
    "stateRoot": "0x...",
    // ... ExecutionPayloadV3 fields
  },
  [
    "0x...", // versioned blob hashes
    "0x..."
  ],
  "0x...", // parent beacon block root
  null     // execution requests (optional)
]

Advanced Usage Examples

Trie Corruption Test Flow

async fn trie_corruption_test_flow() -> Result<(), TestError> {
    // 1. Setup genesis with pre-allocated storage
    let genesis_action = SetupGenesis::new("genesis_with_storage.json");
    
    // 2. Capture genesis block for reference
    let capture_genesis = CaptureBlock::new("genesis", NodeId::new(0));
    
    // 3. Send first mainnet payload (adjusted to chain from genesis)
    let send_first = AdjustAndSendPayload::new(
        payload_first_json,
        "genesis",
        PayloadFormat::Array,
        "block_23003310"
    );
    
    // 4. Send second payload (chained from first)
    let send_second = AdjustAndSendPayload::new(
        payload_second_json,
        "block_23003310",
        PayloadFormat::Array,
        "block_23003311"
    );
    
    // 5. Make canonical and verify storage corruption
    let make_canonical = MakeCanonical::new("block_23003311", NodeId::new(0));
    let verify_storage = VerifyStorageRoot::new(
        Address::from_str("0x77d34361f991fa724ff1db9b1d760063a16770db")?,
        expected_root,
        NodeId::new(0)
    );
    
    Ok(())
}

Multi-Node Fork Test

async fn multi_node_fork_test() -> Result<(), TestError> {
    // Setup two nodes
    let node1 = StartNode::new(config1);
    let node2 = StartNode::new(config2);
    
    // Connect peers
    let connect = ConnectPeers::new(NodeId::new(0), NodeId::new(1));
    
    // Produce blocks on node1
    let produce = ProduceBlocks::new(5, Duration::from_secs(1), Some(NodeId::new(0)));
    
    // Create fork on node2
    let fork = CreateFork::new("block_3", "alternative_chain");
    let switch = SwitchFork::new("alternative_chain", NodeId::new(1));
    
    // Produce competing blocks
    let compete = ProduceBlocks::new(7, Duration::from_secs(1), Some(NodeId::new(1)));
    
    // Verify nodes have different heads
    let wait1 = WaitForBlockHeight::new(5, NodeId::new(0));
    let wait2 = WaitForBlockHeight::new(10, NodeId::new(1));
    
    Ok(())
}

Action Implementation Traits

All actions implement the Action trait:

#[async_trait]
pub trait Action {
    async fn execute(&self, env: &mut TestEnvironment) -> Result<(), TestError>;
}

Key components:

  • TestEnvironment: Manages nodes, block registry, and shared state
  • NodeId: Identifies specific node instances
  • Block Registry: Tracks tagged blocks across the test
  • Error Handling: Consistent error types and propagation

Best Practices

  1. Use descriptive block tags: "genesis", "fork_point", "reorg_target"
  2. Chain actions logically: Ensure dependencies are met before execution
  3. Handle async execution: All actions are async and should be awaited
  4. Verify state changes: Use assert actions to validate expected outcomes
  5. Clean up resources: Nodes are automatically cleaned up, but be mindful of resource usage

This reference covers all currently available actions in the Reth e2e test framework, including the custom actions developed for trie corruption testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment