discv5/discv5_bootnodes.cpp¶
Namespaces¶
| Name |
|---|
| discv5 |
Source code¶
// Copyright 2025 GeniusVentures
// SPDX-License-Identifier: Apache-2.0
//
// Bootnode source implementations for the discv5 crawler.
//
// Data provenance:
// Ethereum mainnet/Sepolia/Holesky — go-ethereum params/bootnodes.go
// https://github.com/ethereum/go-ethereum/blob/master/params/bootnodes.go
// Polygon mainnet/Amoy — docs.polygon.technology/pos/reference/seed-and-bootnodes
// BSC mainnet/testnet — github.com/bnb-chain/bsc/blob/master/params/config.go
// Base mainnet/Sepolia — github.com/base-org/op-geth, github.com/base-org/op-node
//
// !!! Always verify against the latest official sources before production use !!!
#include "discv5/discv5_bootnodes.hpp"
#include <unordered_map>
#include <utility>
namespace discv5
{
// ===========================================================================
// StaticEnrBootnodeSource
// ===========================================================================
StaticEnrBootnodeSource::StaticEnrBootnodeSource(
std::vector<std::string> enr_uris,
std::string name) noexcept
: enr_uris_(std::move(enr_uris))
, name_(std::move(name))
{
}
std::vector<std::string> StaticEnrBootnodeSource::fetch() const noexcept
{
return enr_uris_;
}
std::string StaticEnrBootnodeSource::name() const noexcept
{
return name_;
}
// ===========================================================================
// StaticEnodeBootnodeSource
// ===========================================================================
StaticEnodeBootnodeSource::StaticEnodeBootnodeSource(
std::vector<std::string> enode_uris,
std::string name) noexcept
: enode_uris_(std::move(enode_uris))
, name_(std::move(name))
{
}
std::vector<std::string> StaticEnodeBootnodeSource::fetch() const noexcept
{
return enode_uris_;
}
std::string StaticEnodeBootnodeSource::name() const noexcept
{
return name_;
}
// ===========================================================================
// ChainBootnodeRegistry — per-chain factory functions
// ===========================================================================
// ---------------------------------------------------------------------------
// Ethereum Mainnet (chain id 1)
// ENR source: go-ethereum params/bootnodes.go V5Bootnodes
// Verified from: https://github.com/ethereum/go-ethereum/blob/master/params/bootnodes.go
// ---------------------------------------------------------------------------
std::unique_ptr<IBootnodeSource> ChainBootnodeRegistry::make_ethereum_mainnet() noexcept
{
static const std::vector<std::string> kEnrUris =
{
// Teku team
"enr:-KG4QMOEswP62yzDjSwWS4YEjtTZ5PO6r65CPqYBkgTTkrpaedQ8uEUo1uMALtJIvb2w_WWEVmg5yt1UAuK1ftxUU7QDhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQEnfA2iXNlY3AyNTZrMaEDfol8oLr6XJ7FsdAYE7lpJhKMls4G_v6qQOGKJUWGb_uDdGNwgiMog3VkcIIjKA",
"enr:-KG4QF4B5WrlFcRhUU6dZETwY5ZzAXnA0vGC__L1Kdw602nDZwXSTs5RFXFIFUnbQJmhNGVU6OIX7KVrCSTODsz1tK4DhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQExNYEiXNlY3AyNTZrMaECQmM9vp7KhaXhI-nqL_R0ovULLCFSFTa9CPPSdb1zPX6DdGNwgiMog3VkcIIjKA",
// Prysm team
"enr:-Ku4QImhMc1z8yCiNJ1TyUxdcfNucje3BGwEHzodEZUan8PherEo4sF7pPHPSIB1NNuSg5fZy7qFsjmUKs2ea1Whi0EBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQOVphkDqal4QzPMksc5wnpuC3gvSC8AfbFOnZY_On34wIN1ZHCCIyg",
"enr:-Ku4QP2xDnEtUXIjzJ_DhlCRN9SN99RYQPJL92TMlSv7U5C1YnYLjwOQHgZIUXw6c-BvRg2Yc2QsZxxoS_pPRVe0yK8Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQMeFF5GrS7UZpAH2Ly84aLK-TyvH-dRo0JM1i8yygH50YN1ZHCCJxA",
// EF bootnodes
"enr:-Ku4QHqVeJ8PPICcWk1vSn_XcSkjOkNiTg6Fmii5j6vUQgvzMc9L1goFnLKgXqBJspJjIsB91LTOleFmyWWrFVATGngBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhAMRHkWJc2VjcDI1NmsxoQKLVXFOhp2uX6jeT0DvvDpPcU8FWMjQdR4wMuORMhpX24N1ZHCCIyg",
"enr:-Ku4QG-2_Md3sZIAUebGYT6g0SMskIml77l6yR-M_JXc-UdNHCmHQeOiMLbylPejyJsdAPsTHJyjJB2sYGDLe0dn8uYBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhBLY-NyJc2VjcDI1NmsxoQORcM6e19T1T9gi7jxEZjk_sjVLGFscUNqAY9obgZaxbIN1ZHCCIyg",
};
return std::make_unique<StaticEnrBootnodeSource>(kEnrUris, "ethereum-mainnet-enr");
}
// ---------------------------------------------------------------------------
// Ethereum Sepolia Testnet (chain id 11155111)
// Source: go-ethereum params/bootnodes.go SepoliaBootnodes
// ---------------------------------------------------------------------------
std::unique_ptr<IBootnodeSource> ChainBootnodeRegistry::make_ethereum_sepolia() noexcept
{
static const std::vector<std::string> kEnodeUris =
{
"enode://4e5e92199ee224a01932a377160aa432f31d0b351f84ab413a8e0a42f4f36476f8fb1cbe914af0d9aef0d51665c214cf653c651c4bbd9d5550a934f241f1682b@138.197.51.181:30303",
"enode://143e11fb766781d22d92a2e33f8f104cddae4411a122295ed1fdb6638de96a6ce65f5b7c964ba3763bba27961738fef7d3ecc739268f3e5e771fb4c87b6234ba@146.190.1.103:30303",
"enode://8b61dc2d06c3f96fddcbebb0efb29d60d3598650275dc469c22229d3e5620369b0d3dedafd929835fe7f489618f19f456fe7c0df572bf2d914a9f4e006f783a9@170.64.250.88:30303",
"enode://10d62eff032205fcef19497f35ca8477bea0eadfff6d769a147e895d8b2b8f8ae6341630c645c30f5df6e67547c03494ced3d9c5764e8622a26587b083b028e8@139.59.49.206:30303",
"enode://9e9492e2e8836114cc75f5b929784f4f46c324ad01daf87d956f98b3b6c5fcba95524d6e5cf9861dc96a2c8a171ea7105bb554a197455058de185fa870970c7c@138.68.123.152:30303",
};
return std::make_unique<StaticEnodeBootnodeSource>(kEnodeUris, "ethereum-sepolia-enode");
}
// ---------------------------------------------------------------------------
// Ethereum Holesky Testnet (chain id 17000)
// Source: go-ethereum params/bootnodes.go HoleskyBootnodes
// ---------------------------------------------------------------------------
std::unique_ptr<IBootnodeSource> ChainBootnodeRegistry::make_ethereum_holesky() noexcept
{
static const std::vector<std::string> kEnodeUris =
{
"enode://ac906289e4b7f12df423d654c5a962b6ebe5b3a74cc9e06292a85221f9a64a6f1cfdd6b714ed6dacef51578f92b34c60ee91e9ede9c7f8fadc4d347326d95e2b@146.190.13.128:30303",
"enode://a3435a0155a3e837c02f5e7f5662a2f1fbc25b48e4dc232016e1c51b544cb5b4510ef633ea3278c0e970fa8ad8141e2d4d0f9f95456c537ff05fdf9b31c15072@178.128.136.233:30303",
};
return std::make_unique<StaticEnodeBootnodeSource>(kEnodeUris, "ethereum-holesky-enode");
}
// ---------------------------------------------------------------------------
// Polygon PoS Mainnet (chain id 137)
// Source: https://docs.polygon.technology/pos/reference/seed-and-bootnodes
// ---------------------------------------------------------------------------
std::unique_ptr<IBootnodeSource> ChainBootnodeRegistry::make_polygon_mainnet() noexcept
{
static const std::vector<std::string> kEnodeUris =
{
"enode://48e6326841ce106f6b4e229a1be7e98a1d12be57e328b08cb461f6744ae4e78f5ec2340996ce9b40928a1a90137aadea13e25ca34774b52a3600d13a52c5c7bb@34.185.209.56:30303",
"enode://b8f1cc9c5d4403703fbf377116469667d2b1823c0daf16b7250aa576bacf399e42c3930ccfcb02c5df6879565a2b8931335565f0e8d3f8e72385ecf4a4bf160a@3.36.224.80:30303",
"enode://8729e0c825f3d9cad382555f3e46dcff21af323e89025a0e6312df541f4a9e73abfa562d64906f5e59c51fe6f0501b3e61b07979606c56329c020ed739910759@54.194.245.5:30303",
};
return std::make_unique<StaticEnodeBootnodeSource>(kEnodeUris, "polygon-mainnet-enode");
}
// ---------------------------------------------------------------------------
// Polygon Amoy Testnet (chain id 80002)
// Source: https://docs.polygon.technology/pos/reference/seed-and-bootnodes
// ---------------------------------------------------------------------------
std::unique_ptr<IBootnodeSource> ChainBootnodeRegistry::make_polygon_amoy() noexcept
{
static const std::vector<std::string> kEnodeUris =
{
"enode://d40ab6b340be9f78179bd1ec7aa4df346d43dc1462d85fb44c5d43f595991d2ec215d7c778a7588906cb4edf175b3df231cecce090986a739678cd3c620bf580@34.89.255.109:30303",
"enode://13abba15caa024325f2209d3566fa77cd864281dda4f73bca4296277bfd919ac68cef4dbb508028e0310a24f6f9e23c761fa41ac735cdc87efdee76d5ff985a7@34.185.137.160:30303",
"enode://fc5bd3856a4ce6389eef1d6bc637ce7617e6ba8013f7d722d9878cf13f1c5a5a95a9e26ccb0b38bcc330343941ce117ab50db9f61e72ba450dd528a1184d8e6a@34.89.119.250:30303",
};
return std::make_unique<StaticEnodeBootnodeSource>(kEnodeUris, "polygon-amoy-enode");
}
// ---------------------------------------------------------------------------
// BNB Smart Chain Mainnet (chain id 56)
// Source: https://github.com/bnb-chain/bsc/blob/master/params/config.go
// Note: BSC uses port 30311 instead of standard 30303.
// ---------------------------------------------------------------------------
std::unique_ptr<IBootnodeSource> ChainBootnodeRegistry::make_bsc_mainnet() noexcept
{
static const std::vector<std::string> kEnodeUris =
{
"enode://433c8bfdf53a3e2268ccb1b829e47f629793291cbddf0c76ae626da802f90532251fc558e2e0d10d6725e759088439bf1cd4714716b03a259a35d4b2e4acfa7f@52.69.102.73:30311",
"enode://bac6a548c7884270d53c3694c93ea43fa87ac1c7219f9f25c9d57f6a2fec9d75441bc4bad1e81d78c049a1c4daf3b1404e2bbb5cd9bf60c0f3a723bbaea110bc@3.255.117.110:30311",
"enode://94e56c84a5a32e2ef744af500d0ddd769c317d3c3dd42d50f5ea95f5f3718a5f81bc5ce32a7a3ea127bc0f10d3f88f4526a67f5b06c1d85f9cdfc6eb46b2b375@3.255.231.219:30311",
};
return std::make_unique<StaticEnodeBootnodeSource>(kEnodeUris, "bsc-mainnet-enode");
}
// ---------------------------------------------------------------------------
// BNB Smart Chain Testnet (chain id 97)
// Source: https://github.com/bnb-chain/bsc/blob/master/params/config.go
// ---------------------------------------------------------------------------
std::unique_ptr<IBootnodeSource> ChainBootnodeRegistry::make_bsc_testnet() noexcept
{
static const std::vector<std::string> kEnodeUris =
{
"enode://1cc4534b14cfe351ab740a1418ab944a234ca2f702915eadb7e558a02010cb7c5a8c295a3b56bcefa7701c07752acd5539cb13df2aab8ae2d98934d712611443@52.71.43.172:30311",
"enode://28b1d16562dac280dacaaf45d54516b85bc6c994252a9825c5cc4e080d3e53446d05f63ba495ea7d44d6c316b54cd92b245c5c328c37da24605c4a93a0d099c4@34.246.65.14:30311",
"enode://5a7b996048d1b0a07683a949662c87c09b55247ce774aeee10bb886892e586e3c604564393292e38ef43c023ee9981e1f8b335766ec4f0f256e57f8640b079d5@35.73.137.11:30311",
};
return std::make_unique<StaticEnodeBootnodeSource>(kEnodeUris, "bsc-testnet-enode");
}
// ---------------------------------------------------------------------------
// Base Mainnet (chain id 8453, OP Stack)
// Source: https://github.com/base-org/op-geth
// https://github.com/base-org/op-node
// Note: Base/OP Stack nodes primarily auto-discover via L1 RPC.
// Check the op-geth and op-node repositories for the latest list.
// ---------------------------------------------------------------------------
std::unique_ptr<IBootnodeSource> ChainBootnodeRegistry::make_base_mainnet() noexcept
{
// Base mainnet uses OP Stack discovery; the canonical seed list lives in
// the op-node repository. Returning an empty source so the caller can
// inject seeds via add_bootnode() at runtime.
return std::make_unique<StaticEnodeBootnodeSource>(
std::vector<std::string>{}, "base-mainnet-enode");
}
// ---------------------------------------------------------------------------
// Base Sepolia Testnet (chain id 84532, OP Stack)
// Source: https://docs.base.org/base-chain/node-operators/run-a-base-node
// ---------------------------------------------------------------------------
std::unique_ptr<IBootnodeSource> ChainBootnodeRegistry::make_base_sepolia() noexcept
{
// Same comment as mainnet — check op-geth/op-node for the latest seeds.
return std::make_unique<StaticEnodeBootnodeSource>(
std::vector<std::string>{}, "base-sepolia-enode");
}
// ===========================================================================
// ChainBootnodeRegistry::for_chain (enum overload)
// Uses a switch on the typed enum — not a string if/else chain (M011).
// ===========================================================================
std::unique_ptr<IBootnodeSource>
ChainBootnodeRegistry::for_chain(ChainId chain_id) noexcept
{
switch (chain_id)
{
case ChainId::kEthereumMainnet: return make_ethereum_mainnet();
case ChainId::kEthereumSepolia: return make_ethereum_sepolia();
case ChainId::kEthereumHolesky: return make_ethereum_holesky();
case ChainId::kPolygonMainnet: return make_polygon_mainnet();
case ChainId::kPolygonAmoy: return make_polygon_amoy();
case ChainId::kBscMainnet: return make_bsc_mainnet();
case ChainId::kBscTestnet: return make_bsc_testnet();
case ChainId::kBaseMainnet: return make_base_mainnet();
case ChainId::kBaseSepolia: return make_base_sepolia();
default: return nullptr;
}
}
// ===========================================================================
// ChainBootnodeRegistry::for_chain (integer overload)
// Uses an unordered_map<uint64_t, ChainId> — no if/else string chain (M011).
// ===========================================================================
std::unique_ptr<IBootnodeSource>
ChainBootnodeRegistry::for_chain(uint64_t chain_id_int) noexcept
{
static const std::unordered_map<uint64_t, ChainId> kChainMap =
{
{ static_cast<uint64_t>(ChainId::kEthereumMainnet), ChainId::kEthereumMainnet },
{ static_cast<uint64_t>(ChainId::kEthereumSepolia), ChainId::kEthereumSepolia },
{ static_cast<uint64_t>(ChainId::kEthereumHolesky), ChainId::kEthereumHolesky },
{ static_cast<uint64_t>(ChainId::kPolygonMainnet), ChainId::kPolygonMainnet },
{ static_cast<uint64_t>(ChainId::kPolygonAmoy), ChainId::kPolygonAmoy },
{ static_cast<uint64_t>(ChainId::kBscMainnet), ChainId::kBscMainnet },
{ static_cast<uint64_t>(ChainId::kBscTestnet), ChainId::kBscTestnet },
{ static_cast<uint64_t>(ChainId::kBaseMainnet), ChainId::kBaseMainnet },
{ static_cast<uint64_t>(ChainId::kBaseSepolia), ChainId::kBaseSepolia },
};
const auto it = kChainMap.find(chain_id_int);
if (it == kChainMap.end())
{
return nullptr;
}
return for_chain(it->second);
}
// ===========================================================================
// ChainBootnodeRegistry::chain_name
// ===========================================================================
const char* ChainBootnodeRegistry::chain_name(ChainId chain_id) noexcept
{
switch (chain_id)
{
case ChainId::kEthereumMainnet: return "ethereum-mainnet";
case ChainId::kEthereumSepolia: return "ethereum-sepolia";
case ChainId::kEthereumHolesky: return "ethereum-holesky";
case ChainId::kPolygonMainnet: return "polygon-mainnet";
case ChainId::kPolygonAmoy: return "polygon-amoy";
case ChainId::kBscMainnet: return "bsc-mainnet";
case ChainId::kBscTestnet: return "bsc-testnet";
case ChainId::kBaseMainnet: return "base-mainnet";
case ChainId::kBaseSepolia: return "base-sepolia";
default: return "unknown";
}
}
} // namespace discv5
Updated on 2026-04-13 at 23:22:46 -0700