Ress (Reth Stateless)

repository·main·Indexed 41 days ago

https://github.com/paradigmxyz/ress

A fully validating stateless Ethereum Execution Layer node designed to minimize disk requirements (approx. 14GB) while maintaining security. Ress performs live sync by fetching state data (witness, block, and bytecodes) from a stateful Reth client via a dedicated ress RLPx subprotocol, allowing payload verification and state root calculations to be performed entirely in memory.

Tokens
13.3K
Snippets
45
Records
66
Agent score
52%

What's inside Ress

  1. Ress architecture and required components

    main

    To successfully run a Ress node, you must have two client pairs connected to a Consensus Layer client:

    1. Stateless Client Pair: A Ress node connected to a Consensus Layer client via the Engine API.
    2. Stateful Client Pair: A Reth node connected to a Consensus Layer client via the Engine API.

    The Ress node communicates with the Reth node using the ress RLPx subprotocol to fetch required state data.

  2. How the hive-adapter works

    main

    The hive-adapter acts as a proxy/MITM (Man-in-the-Middle) between hive and reth/ress. It intercepts requests and routes them based on the request type:

    1. Non-engine requests: The adapter forwards the request to reth, retrieves the response, and returns it to hive.
    2. Engine requests: The adapter forwards the request to reth and retrieves the response. It then sends the same request to ress and retrieves its response. Only after both responses are received does it return the reth response back to hive.
  3. How Ress stateless synchronization works

    main

    Ress performs live sync by receiving new payloads from a Consensus Client and fetching necessary state data (witness, block, and bytecodes) from a stateful Reth client via a dedicated ress RLPx subprotocol.

    All payload verification and new state root calculations are performed entirely in memory. This allows the node to operate with significantly lower disk requirements (approximately 14GB) compared to stateful nodes.

  4. Enable Ress subprotocol in Reth

    main

    To allow a stateful Reth node to serve as a data provider for a Ress node, start your Reth node with the --ress.enable flag. This enables support for the ress RLPx subprotocol.

    reth --ress.enable
  5. Configure the Consensus Layer client for Ress

    main

    Ress requires a Consensus Layer client. The setup instructions are identical to running a Consensus Layer client for Reth.

    Important Difference: The default JWT token location for Ress is ~/.local/share/ress/NETWORK/jwt.hex, whereas for Reth it is ~/.local/share/reth/NETWORK/jwt.hex.

  6. Run hive with reth and ress using hive-adapter

    main

    To run a simulation using hive with the reth/ress stack via the adapter, follow these steps:

    1. Prerequisites: Install docker.
    2. Setup Hive:
      git clone https://github.com/ethereum/hive && cd hive && go build .
    3. Patch Hive: Apply the provided hive.patch to the hive repository.
    4. Prepare Clients: Build reth, ress, and adapter, then copy the resulting binaries into the hive/clients/reth/ directory.
    5. Execute Simulation: From inside the hive repository, run:
      rm -rf workspace/ && ./hive --sim ethereum --sim.limit api --client reth
    rm -rf workspace/ && ./hive --sim ethereum --sim.limit api --client reth
  7. Install Ress via cargo

    main

    Install the Ress (Reth Stateless) binary using cargo install. It is recommended to use the --locked flag to ensure dependency versions match the repository's lockfile.

    cargo install --git https://github.com/paradigmxyz/ress ress --locked
  8. What is a StateWitness?

    main

    A StateWitness is a type alias for Vec<Bytes>. It represents a collection of trie node preimages. These preimages are used during stateless execution to allow the engine to retrieve state and compute the state root without having access to the full state database.

    /// Alias type representing execution state witness.
    /// Execution state witness is a collection of trie node preimages.
    pub type StateWitness = Vec<Bytes>;
  9. Identify the latest valid hash for an invalid payload

    main

    When a block validation fails, the engine must provide a PayloadStatus containing the latest_valid_hash. This hash is critical for identifying the last known good state in the chain.

    Rules for determining the latest_valid_hash:

    1. It must be the block hash of an ancestor of the invalid payload that is fully validated and deemed VALID.
    2. Any other ancestor of the invalid payload with a higher blockNumber must be INVALID.
    3. If the conditions are satisfied by a PoW block, the hash should be 0x0000000000000000000000000000000000000000000000000000000000000000.
    4. If the client cannot determine such an ancestor, the value should be null.
  10. How ConsensusEngine handles payload messages

    main

    The ConsensusEngine implements Future and processes messages from the beacon engine. It handles two primary message types:

    1. BeaconEngineMessage::NewPayload: When a new payload arrives, the engine attempts to process it using the current EngineTree. If the required witness for the block is missing, the engine 'parks' the payload (waits for a timeout) and triggers a download request for the witness. Once the data is downloaded, the engine attempts to re-process the payload.
    2. BeaconEngineMessage::ForkchoiceUpdated: Updates the internal forkchoice state and emits a BeaconConsensusEngineEvent::ForkchoiceUpdated event.

    If a payload is parked and the required data (witness/block) is not downloaded within the parked_payload_timeout (defaulting to 3 seconds), the engine returns a PayloadStatus with a status of Syncing.

  11. Use ChainState to manage in-memory blockchain state

    main

    The ChainState struct provides an in-memory representation of the blockchain tree. It tracks validated blocks (including those in forks) and maintains the canonical chain. It is thread-safe and can be cloned to share access via an internal Arc<RwLock<...>>.

    use ress::provider::ChainState;
    // ChainState can be cloned to share the underlying state
    let state = ChainState::default();
    let shared_state = state.clone();
  12. Understand BlockStatus and payload insertion results

    main

    When interacting with the engine, block inclusion results are categorized into three states via the BlockStatus enum:

    • Valid: The block is valid and extends the canonical chain.
    • Disconnected: The block may be valid, but it has an unknown missing ancestor. This variant includes the current canonical head and the missing_ancestor (both as BlockNumHash).
    • NoWitness: The block has no witness.

    If a payload is valid, the engine returns an InsertPayloadOk variant:

    • AlreadySeen: The payload was valid but has already been processed.
    • Inserted(BlockStatus): The payload was valid and successfully inserted into the tree, returning its BlockStatus.
    pub enum BlockStatus {
        Valid,
        Disconnected {
            head: BlockNumHash,
            missing_ancestor: BlockNumHash,
        },
        NoWitness,
    }
    
    pub enum InsertPayloadOk {
        AlreadySeen,
        Inserted(BlockStatus),
    }