Skip to main content
Archive node vs. historical proofsThis guide covers running a full archive node, which serves every historical-state RPC call (such as eth_getBalance or eth_call) at any block and requires terabytes of storage. Celo also supports a narrower historical proofs feature for serving deep eth_getProof within a bounded window without keeping full archive state; see Serving historical proofs.
Execution client: op-rethThese instructions use op-reth, Celo’s primary execution client. op-geth is supported until your network’s switch date — see the Still running op-geth? notes at the end of this guide and End of Support for op-geth.

Overview

To run an L2 archive node, you need to start the L2 execution client in archive mode. This allows the node to accept RPC requests that require archive data for blocks created after the L2 transition. For historical data from before the L2 transition, you can configure your node to forward those requests to a legacy Celo L1 archive node that contains the historical blockchain state.

Instructions

PrerequisitesAn L2 archive node starts from an empty datadir, like a full node — no migrated L1 data is required. To serve pre-L2 historical state, you additionally need one of:
  1. A non-migrated Celo L1 archive node datadir (the compose setup runs a legacy archive node from it). Do not attempt to migrate an archive datadir.
  2. The RPC endpoint of a running legacy Celo L1 archive node.
Ensure any datadir you supply is not in use by a running node before proceeding.
  1. Pull the latest version of celo-l2-node-docker-compose and cd into the root of the project.
    git clone https://github.com/celo-org/celo-l2-node-docker-compose.git
    cd celo-l2-node-docker-compose
    
  2. Configure your .env file.

    Copy default configurations

    The celo-l2-node-docker-compose repo contains a <network>.env file for each Celo network (celo-sepolia, mainnet). Start by copying the default configuration for the appropriate network.
    export NETWORK=<celo-sepolia or mainnet>
    cp $NETWORK.env .env
    

    Configure node type

    To enable archive mode, configure .env as follows:
    NODE_TYPE=archive
    

    Bootstrap your datadir

    An archive node starts from an empty datadir and keeps the full historical state. Bootstrap it from a published snapshot:
    OP_RETH__SNAPSHOT=true
    
    On first start this downloads the snapshot matching your NODE_TYPE (here, the archive snapshot) and continues from there. On mainnet a snapshot is required — it provides the pre-L2 (Celo L1) history. On Celo Sepolia, which has no pre-L2 history, you can instead leave OP_RETH__SNAPSHOT=false and execute every block from genesis. Either way, NODE_TYPE=archive is what keeps the full historical state available, and DATADIR_PATH must be empty on first start — a datadir written by op-geth cannot be reused.

    Configure Historical RPC Service

    To handle RPC requests for pre-hardfork state and execution, an L2 archive node proxies to a legacy archive node or “Historical RPC Service”. There are two ways to configure a Historical RPC Service for your archive node:
    1. Supply a pre-hardfork archive datadir and let celo-l2-node-docker-compose start a legacy archive node. To do this configure .env as follows:
      HISTORICAL_RPC_DATADIR_PATH=<path to your pre-hardfork archive datadir>
      
      When you start your L2 node, a legacy archive node will also start using the pre-hardfork archive datadir. Your L2 node will be configured to use the legacy archive node as its Historical RPC Service.
    2. Start the legacy archive node yourself and configure .env as follows:
      OP_RETH__HISTORICAL_RPC=<RPC endpoint of a running legacy archive node>
      
      This will cause any value you set for HISTORICAL_RPC_DATADIR_PATH to be ignored. The tool will not start a legacy archive node when it starts your L2 archive node. If you choose to run your own legacy archive node, you should do so with different flags than before the hardfork, as the node will no longer be syncing blocks or communicating with other nodes. To see how we recommend re-starting a legacy archive node as a Historical RPC Service, see this script.

    Configure P2P for external network access

    Network ConfigurationIf the following options are not configured correctly, your node will not be discoverable or reachable to other nodes on the network. This is likely to impair your node’s ability to stay reliably connected to and synced with the network.
    • OP_NODE__P2P_ADVERTISE_IP - Specifies the public IP to be shared via discovery so that other nodes can connect to your node. If unset, other nodes on the network will not be able to discover and connect to your op-node.
    • PORT__OP_NODE_P2P - Specifies the port to be shared via discovery so that other nodes can connect to your node. Defaults to 9222.
    • OP_RETH__NAT - Controls how op-reth determines its public IP that is shared via the discovery mechanism. If the public IP is not correctly configured then other nodes on the network will not be able to discover and connect to your node. The default value of any will try to automatically determine the public IP, but the most reliable approach is to explicitly set the public IP using extip:<your-public-ip>. Other acceptable values are (any|none|upnp|publicip|extip:<IP>|stun:<IP:PORT>).
    • PORT__OP_RETH_P2P - Specifies the port to be shared via discovery so that other nodes can connect to your node. Defaults to 30303.
  3. Start the node(s).
    docker compose up -d --build
    
  4. Check the progress of your L2 archive node as it syncs.
    docker compose logs -n 50 -f op-reth
    
    This will display and follow the last 50 lines of logs. As the node syncs you will see op-reth executing blocks and its head advancing toward the network’s latest block.
  5. Check that node is fully synced. You can validate that your node is following the network by fetching the current block number via the RPC API and seeing that it climbs as the node syncs and then tracks the network’s latest block.
    cast block-number --rpc-url http://localhost:9993
    
  6. Try querying historical state to test archive functionality.
    cast balance --block <pre-migration-block-number> <address> --rpc-url http://localhost:9993
    
Until your network’s switch date, you can keep running an op-geth archive node from an existing checkout of celo-l2-node-docker-compose. The flow above is the same, with these differences:
  • Sync mode instead of a snapshot. op-geth archive nodes should run full sync against a migrated pre-hardfork datadir — snap sync only stores archive data from the point it completes, leaving a gap after the hardfork:
    OP_GETH__SYNCMODE=full
    DATADIR_PATH=<path to a migrated L1 full node datadir>
    
  • Historical RPC variable. Use OP_GETH__HISTORICAL_RPC in place of OP_RETH__HISTORICAL_RPC.
  • P2P variables. Use OP_GETH__NAT (values any|none|upnp|pmp|pmp:<IP>|extip:<IP>|stun:<IP:PORT>) and PORT__OP_GETH_P2P (default 30303).
  • Logs. Follow docker compose logs -n 50 -f op-geth; a syncing node shows Syncing beacon headers downloaded=... and later "Syncing: chain download in progress","synced":"21.07%".