Skip to content

GeniusVentures/rlp_enodes

Repository files navigation

rlp_enodes — EVM Bootstrap Node Filter

Automated system that downloads the latest all.json crawl from the Ethereum discv4-dns-lists repository, filters nodes by EVM-compatible chain, selects only those advertising the dominant (current-head) fork ID, ranks them by score and recency, and writes clean JSON files of the top bootstrap peers for use with your discv4 peer-discovery library.

Output structure

The generator writes three kinds of JSON artifacts:

output/
  fork_ids.json
  chain_enodes.json
  ethereum-mainnet.json
  ethereum-sepolia.json
  ethereum-holesky.json
  ethereum-hoodi.json
  bnb-smart-chain.json
  bnb-smart-chain-testnet.json
  polygon-mainnet.json
  polygon-amoy.json
  base-mainnet.json
  base-sepolia.json
  gnosis-chain.json

output/fork_ids.json

fork_ids.json is the fork metadata source of truth. Each top-level key is a configured chain name. Fork IDs are EIP-2124 tuples: forkId is the CRC32 fork hash and forkNext is the next fork block/timestamp encoded as lowercase hex, or "0" when no future fork is configured.

{
  "ethereum-mainnet": {
    "chainId": 1,
    "genesisHex": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3",
    "current": {
      "forkId": "07c9462e",
      "forkNext": "0"
    },
    "upcoming": {
      "at": "695db057",
      "forkId": "12345678",
      "forkNext": "0"
    },
    "source": "https://raw.githubusercontent.com/ethereum/go-ethereum/master/params/config.go",
    "generatedAt": "2026-05-15T00:00:00Z",
    "forks": [
      { "forkId": "fc64ec04", "forkNext": "118c30" },
      { "forkId": "07c9462e", "forkNext": "0" }
    ]
  }
}

Fields:

Field Description
chainId EVM chain ID.
genesisHex 32-byte genesis hash used as the fork ID CRC32 seed.
current Current fork tuple used for node filtering and output metadata.
upcoming Optional scheduled next fork metadata. Present when current.forkNext != "0".
upcoming.at The scheduled fork block/timestamp from current.forkNext.
upcoming.forkId / upcoming.forkNext Optional post-fork tuple when it can be derived from the known schedule.
source GitHub/config source used to derive the fork schedule.
generatedAt UTC generation timestamp.
forks Known fork tuple progression from the source, ordered by activation.

Per-chain {chain}.json

Each chain also produces a file containing chain metadata plus nodes sorted by score (descending) then lastResponse (most recent first), capped at topN (default 100):

{
  "networkId": 1,
  "genesisHex": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3",
  "forkId": "07c9462e",
  "forkNext": "0",
  "upcomingFork": {
    "at": "695db057",
    "forkId": "12345678",
    "forkNext": "0",
    "nodes": []
  },
  "nodes": [
    {
      "enr": "enr:-...",
      "enode": "enode://<128-hex-pubkey>@162.55.86.114:30311",
      "pubkey": "<128-hex-secp256k1-pubkey>",
      "score": 3371,
      "lastResponse": "2026-03-14T20:54:48Z",
      "forkId": "07c9462e",
      "forkNext": "0",
      "ip": "162.55.86.114",
      "port": 30311
    }
  ]
}

pubkey, enode, ip, and port are derived from the decoded ENR itself. pubkey is the 64-byte uncompressed secp256k1 public key (hex, without 0x04). port prefers the ENR TCP port and falls back to UDP only when TCP is absent.

forkId and forkNext at the chain level mirror fork_ids.json.current. upcomingFork is omitted when no future fork is configured. When present, upcomingFork.nodes contains peers already advertising the post-fork tuple. If the schedule only identifies the activation point, upcomingFork.at is set and nodes may be empty.

output/chain_enodes.json

chain_enodes.json is the combined output consumed by clients. It maps each configured chain name to the same schema as the per-chain {chain}.json files. When signing is enabled, it also includes top-level signature and signerAddress fields:

{
  "ethereum-mainnet": {
    "networkId": 1,
    "genesisHex": "...",
    "forkId": "07c9462e",
    "forkNext": "0",
    "nodes": []
  },
  "gnosis-chain": {
    "networkId": 100,
    "genesisHex": "...",
    "forkId": "06000064",
    "forkNext": "0",
    "nodes": []
  },
  "signature": "0x<65-byte-secp256k1-signature>",
  "signerAddress": "0x<ethereum-address>"
}

Automation

A GitHub Actions workflow runs every 6 hours but only regenerates output when all.json has actually changed (SHA-256 comparison against output/.state). It also triggers on pushes to main that change source files, and can be run on-demand.

Local usage

# Build
go build -o filter_nodes .

# Run (downloads all.json from the internet)
./filter_nodes

# Use a local copy of all.json (faster for development / testing)
./filter_nodes -input /path/to/all.json

# Discovery mode: print ranked fork-hash summary to identify unknown chains
./filter_nodes -discover -v

# Combine: discovery on a local file
./filter_nodes -input /path/to/all.json -discover -v

Supported filter strategies

Strategy Description
geth_network Filters Ethereum-family ENRs against the current tuple from fork_ids.json. Supported networks: mainnet, sepolia, holesky, hoodi.
enr_field Accepts nodes that carry a specific ENR key (e.g. bsc for BNB Smart Chain).
fork_hash_list Accepts nodes whose eth fork hash is in the configured forkHashes list.
bootnodes_yaml Loads a chain from an external YAML list of ENR bootnodes via sourceUrl.
bootnodes_go Loads a chain from a named []string bootnode slice in an external Go source file via sourceUrl + sourceKey.

Fork ID sources

Fork IDs are generated before node filtering and written to output/fork_ids.json. The normal run then reloads that file and uses it for filtering and output metadata. Current source providers:

Provider Chains Source
ethereum_geth Ethereum mainnet/testnets ethereum/go-ethereum params/config.go from the configured forkSourceRef (currently master).
bsc BNB Smart Chain mainnet/testnet bnb-chain/bsc params/config.go from a pinned release tag.
polygon_bor Polygon PoS / Amoy 0xPolygon/bor params/config.go, including Bor-specific fork blocks.
op_stack_superchain Base mainnet/sepolia ethereum-optimism/superchain-registry superchain hardfork config.

Providers compute the EIP-2124 tuple from genesis hash plus already-passed fork blocks/timestamps. For block forks, the generator reads eth_blockNumber from the configured rpcUrl; for timestamp forks it uses the current UTC time.

Compound AND filter

Set both enrField and forkHashes together with either "enr_field" or "fork_hash_list" as filterType to require both conditions simultaneously. This is used to distinguish BNB Smart Chain testnet (Chapel) from mainnet — both advertise the bsc ENR key but at different fork hashes.

Configured chains

Chain Chain ID Filter
Ethereum Mainnet 1 geth_network: mainnet
Ethereum Sepolia 11155111 geth_network: sepolia
Ethereum Holesky 17000 geth_network: holesky
Ethereum Hoodi 560048 geth_network: hoodi
BNB Smart Chain 56 enr_field: bsc
BNB Smart Chain Testnet 97 enr_field: bsc + fork_hash_list (compound)
Polygon PoS Mainnet 137 bootnodes_enrtree + explicit bootnodes_go
Polygon Amoy Testnet 80002 bootnodes_enrtree + explicit bootnodes_go
Base Mainnet 8453 bootnodes_go
Base Sepolia Testnet 84532 bootnodes_go
Gnosis Chain (xDai) 100 bootnodes_go

Adding or updating chains

  1. Edit chains_config.json.
  2. Run ./filter_nodes -discover (or -input + -discover) to print a ranked table of all fork hashes observed in the crawl. Chain-specific ENR keys (e.g. bsc(2709)) help identify which hash belongs to which chain.
  3. For fork_hash_list, cross-reference the top hashes with the chain's release notes.
  4. Add the hash(es) to the chain's forkHashes array, or for bootnodes_yaml / bootnodes_go set the external source fields.
  5. Re-run to verify results.

Known Ethereum fork hash progression (March 2026)

Chain Fork Hash Timestamp / Block
Mainnet Cancun 9f3d2254 1710338135
Mainnet Prague c376cf8b 1746612311
Mainnet Osaka 5167e2a6 1764798551
Mainnet BPO1 cba2a1c0 1765290071
Mainnet BPO2 07c9462e 1767747671 (current)
Sepolia Cancun 88cf81d9 1706655072
Sepolia BPO2 268956b6 current
Holesky Cancun 9b192ad0 1707305664
Holesky BPO2 9bc6cb31 current
Hoodi Prague 0929e24e 1742999832 (current)

Dependencies

Signing & Authenticity

The chain_enodes.json file can be cryptographically signed to prove you generated it. Use ECDSA (secp256k1, Ethereum-compatible) signing with a private key.

Quick Start:

  1. Generate a signing key:

    ./generate_signing_key.sh
  2. Export the key and run:

    export SIGNING_KEY='<base64-encoded-key>'
    ./filter_nodes
  3. The output/chain_enodes.json will now include:

    • signature: ECDSA signature over the entire JSON document
    • signerAddress: Ethereum address of the signer

For full setup and verification instructions, see SIGNING.md.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors