Skip to content

feat: tn_ RPC Namespace Methods #530

@grantkee

Description

@grantkee

Add tn_* RPC Methods for Network Sync Status and Epoch Info

Summary

Add new RPC methods to the tn namespace to support validator operations and network monitoring. These methods will help validators determine when their node is synced and ready for activation, as well as provide epoch and committee information.

Motivation

New validator nodes need a way to determine if their node is fully synced before calling activate() on the ConsensusRegistry contract. Currently, there's no RPC method to check if a node's execution state is caught up with the current consensus epoch. Validators activating before their node is synced risk being slashed or missing consensus participation.

Additionally, operators and tooling need easy access to current epoch information and committee membership details through RPC.

NOTE: eth_syncing always returns false because peers do not exchange block execution info (requires overriding default reth RPC behavior).

Proposed Methods

1. tn_syncing

Returns sync status for the consensus chain. Follows the same pattern as eth_syncing: returns false when synced, or an object with sync progress when syncing.

Request:

{
  "jsonrpc": "2.0",
  "method": "tn_syncing",
  "params": [],
  "id": 1
}

Response (when synced):

{
  "jsonrpc": "2.0",
  "result": false,
  "id": 1
}

Response (when syncing):

{
  "jsonrpc": "2.0",
  "result": {
    "startingBlock": 0,
    "currentBlock": 5000,
    "highestBlock": 10000
  },
  "id": 1
}
  • false - Node is synced (execution has caught up to the current consensus epoch)
  • { startingBlock, currentBlock, highestBlock } - Node is syncing; values refer to consensus chain block numbers (not execution chain)

Sync Definition:

  • A node is considered "synced" when its execution state is within the current consensus epoch
  • Example: If the committee is committing subdags for epoch 10, a node executed into epoch 10 returns false (not syncing), while a node still executing epoch 9 output returns the sync status object
  • Nodes within the current epoch but outside the garbage collection window should still return false (considered synced)
  • This applies to all node types (validators, observers, etc.)

Implementation Notes:

  • The ConsensusBus provides access to NodeMode via node_mode() which tracks CvvActive, CvvInactive, and Observer states
  • However, NodeMode alone is insufficient - we need to compare the local execution epoch against the network's current consensus epoch
  • The RPC layer will need to:
    1. Get the highest known consensus block from the network (via gossip)
    2. Get the local node's current executed consensus block
    3. Track the starting block from when sync began
    4. Return false if synced, or the sync status object otherwise
  • The EngineToPrimary trait may need extension to expose this information to the RPC layer
  • startingBlock: The consensus block number when the node started syncing
  • currentBlock: The consensus block number the node has executed up to
  • highestBlock: The highest consensus block number known from the network

2. tn_epochInfo

Returns the current EpochInfo for the committee's epoch (not the local node's view if it differs during sync).

Request:

{
  "jsonrpc": "2.0",
  "method": "tn_epochInfo",
  "params": [],
  "id": 1
}

Response:

{
  "jsonrpc": "2.0",
  "result": {
    "epoch": 10,
    "committee": ["0x...", "0x...", "0x..."],
    "nextCommittee": ["0x...", "0x...", "0x..."],
    "parentHash": "0x...",
    "parentState": {
      "number": 12345,
      "hash": "0x..."
    },
    "parentConsensus": "0x..."
  },
  "id": 1
}

Implementation Notes:

  • Should return the EpochRecord for the current committee's epoch
  • The existing tn_epochRecord method requires an epoch number parameter; this method returns the current epoch without requiring the caller to know the epoch number
  • Useful for tooling that needs to discover the current epoch state

3. tn_currentCommittee

Returns validator information for the current committee members.

Request:

{
  "jsonrpc": "2.0",
  "method": "tn_currentCommittee",
  "params": [],
  "id": 1
}

Response:

{
  "jsonrpc": "2.0",
  "result": {
    "epoch": 10,
    "validators": [
      {
        "blsPublicKey": "0x...",
        "address": "0x..."
      },
      ...
    ]
  },
  "id": 1
}

Implementation Notes:

  • Returns the current committee's validator information
  • Should include both BLS public keys (from consensus layer EpochRecord.committee) and Ethereum addresses (if available)
  • The EpochRecord stores Vec<BlsPublicKey> for the committee

Implementation Approach

RPC Layer Changes

  1. Extend TelcoinNetworkRpcExtApi trait in crates/execution/tn-rpc/src/rpc_ext.rs:

    #[method(name = "syncing")]
    async fn syncing(&self) -> TelcoinNetworkRpcResult<SyncStatus>;
    
    #[method(name = "epochInfo")]
    async fn epoch_info(&self) -> TelcoinNetworkRpcResult<EpochRecord>;
    
    #[method(name = "currentCommittee")]
    async fn current_committee(&self) -> TelcoinNetworkRpcResult<CommitteeInfo>;

    Where SyncStatus is an enum that serializes to either false or the sync progress object:

    pub enum SyncStatus {
        Synced,  // serializes to `false`
        Syncing { starting_block: u64, current_block: u64, highest_block: u64 },
    }
  2. Extend EngineToPrimary trait in crates/execution/tn-rpc/src/lib.rs to expose:

    • Current consensus epoch (from network/committee perspective)
    • Local execution epoch
    • Current committee information
  3. Update EngineToPrimaryRpc implementation in crates/node/src/lib.rs to provide the required data from ConsensusBus

Data Flow

ConsensusBus (consensus layer)
    │
    ├── last_consensus_header() -> current consensus epoch
    ├── recent_blocks() -> local execution state
    └── node_mode() -> sync status hint
    │
    ▼
EngineToPrimaryRpc (implements EngineToPrimary trait)
    │
    ▼
TelcoinNetworkRpcExt (RPC implementation)
    │
    ▼
JSON-RPC Response

Use Cases

  1. Validator Activation: Before calling ConsensusRegistry.activate(), validators query tn_syncing to ensure their node is caught up
  2. Monitoring: Operators use tn_syncing to monitor node health and sync status
  3. Tooling: Block explorers and dashboards use tn_epochInfo and tn_currentCommittee to display network state

Open Questions

  1. How should we determine the "network's current epoch" for a syncing node that may not be connected to the full committee?
    • The node receives consensus headers via gossip; the latest verified header indicates the network epoch
  2. Should tn_currentCommittee include additional validator metadata (stake amount, status, etc.)?
    • Start with minimal info (BLS key, address); can extend later if needed
  3. Where should startingBlock be tracked? This value needs to persist across the sync process.
    • Reference the most-recent EpochRecord
    • ex)
      • Committe is on epoch 10
      • syncing node is half-way through epoch 8
      • startingBlock = EpochRecord for epoch 7

Related

  • Existing tn_* methods: tn_latestHeader, tn_genesis, tn_epochRecord, tn_epochRecordByHash
  • ConsensusRegistry.activate() - the contract method validators call after syncing
  • NodeMode enum: CvvActive, CvvInactive, Observer
  • any other RPC method that is considered useful for node operators, TN users, etc.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions