mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-20 11:46:44 +00:00
feat: Enhanced discv4 with XDC discovery support
- Added dedicated XDC seed nodes - Implemented bootstrap method for XDC network - Enhanced v4wire protocol for better peer discovery - Added verbose debug logging for peer connections
This commit is contained in:
parent
fbc86ff61f
commit
fb2de4e708
6 changed files with 143 additions and 4 deletions
|
|
@ -190,6 +190,11 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assemble the Ethereum object.
|
// Assemble the Ethereum object.
|
||||||
|
p2pServer := stack.Server()
|
||||||
|
|
||||||
|
// Set NetworkID on P2P server for chain-specific discovery (e.g., XDC uses pingXDC)
|
||||||
|
p2pServer.Config.NetworkID = networkID
|
||||||
|
|
||||||
eth := &Ethereum{
|
eth := &Ethereum{
|
||||||
config: config,
|
config: config,
|
||||||
chainDb: chainDb,
|
chainDb: chainDb,
|
||||||
|
|
@ -198,7 +203,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
engine: engine,
|
engine: engine,
|
||||||
networkID: networkID,
|
networkID: networkID,
|
||||||
gasPrice: config.Miner.GasPrice,
|
gasPrice: config.Miner.GasPrice,
|
||||||
p2pServer: stack.Server(),
|
p2pServer: p2pServer,
|
||||||
discmix: enode.NewFairMix(discmixTimeout),
|
discmix: enode.NewFairMix(discmixTimeout),
|
||||||
shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb),
|
shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,10 @@ type Config struct {
|
||||||
// Logger is a custom logger to use with the p2p.Server.
|
// Logger is a custom logger to use with the p2p.Server.
|
||||||
Logger log.Logger `toml:"-"`
|
Logger log.Logger `toml:"-"`
|
||||||
|
|
||||||
|
// NetworkID is the network identifier for chain-specific discovery.
|
||||||
|
// Used to enable XDC-specific discovery protocol when set to 50 (mainnet) or 51 (Apothem).
|
||||||
|
NetworkID uint64
|
||||||
|
|
||||||
clock mclock.Clock
|
clock mclock.Clock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,9 @@ type Config struct {
|
||||||
RefreshInterval time.Duration // used in bucket refresh
|
RefreshInterval time.Duration // used in bucket refresh
|
||||||
NoFindnodeLivenessCheck bool // turns off validation of table nodes in FINDNODE handler
|
NoFindnodeLivenessCheck bool // turns off validation of table nodes in FINDNODE handler
|
||||||
|
|
||||||
|
// Network identification:
|
||||||
|
NetworkID uint64 // network ID for chain-specific discovery (50 = XDC mainnet)
|
||||||
|
|
||||||
// The options below are useful in very specific cases, like in unit tests.
|
// The options below are useful in very specific cases, like in unit tests.
|
||||||
V5ProtocolID *[6]byte
|
V5ProtocolID *[6]byte
|
||||||
Log log.Logger // if set, log messages go here
|
Log log.Logger // if set, log messages go here
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,19 @@ type UDPv4 struct {
|
||||||
gotreply chan reply
|
gotreply chan reply
|
||||||
closeCtx context.Context
|
closeCtx context.Context
|
||||||
cancelCloseCtx context.CancelFunc
|
cancelCloseCtx context.CancelFunc
|
||||||
|
|
||||||
|
// xdcMode enables XDC-specific discovery protocol (pingXDC).
|
||||||
|
// XDC nodes use packet type 5 instead of type 1 for ping.
|
||||||
|
xdcMode bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetXDCMode enables XDC-specific discovery protocol.
|
||||||
|
// When enabled, uses pingXDC (type 5) instead of standard ping (type 1).
|
||||||
|
func (t *UDPv4) SetXDCMode(enabled bool) {
|
||||||
|
t.xdcMode = enabled
|
||||||
|
if enabled {
|
||||||
|
t.log.Info("XDC discovery mode enabled (using pingXDC)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// replyMatcher represents a pending reply.
|
// replyMatcher represents a pending reply.
|
||||||
|
|
@ -143,6 +156,12 @@ func ListenV4(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) {
|
||||||
log: cfg.Log,
|
log: cfg.Log,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enable XDC mode for XDC networks (chain ID 50 = mainnet, 51 = Apothem testnet)
|
||||||
|
if cfg.NetworkID == 50 || cfg.NetworkID == 51 {
|
||||||
|
t.xdcMode = true
|
||||||
|
cfg.Log.Info("XDC discovery mode enabled", "networkID", cfg.NetworkID)
|
||||||
|
}
|
||||||
|
|
||||||
tab, err := newTable(t, ln.Database(), cfg)
|
tab, err := newTable(t, ln.Database(), cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -237,8 +256,13 @@ func (t *UDPv4) Ping(n *enode.Node) (pong *v4wire.Pong, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendPing sends a ping message to the given node and invokes the callback
|
// sendPing sends a ping message to the given node and invokes the callback
|
||||||
// when the reply arrives.
|
// when the reply arrives. If XDC mode is enabled, sends pingXDC (type 5) instead.
|
||||||
func (t *UDPv4) sendPing(toid enode.ID, toaddr netip.AddrPort, callback func()) *replyMatcher {
|
func (t *UDPv4) sendPing(toid enode.ID, toaddr netip.AddrPort, callback func()) *replyMatcher {
|
||||||
|
// Use pingXDC for XDC networks
|
||||||
|
if t.xdcMode {
|
||||||
|
return t.sendPingXDC(toid, toaddr, callback)
|
||||||
|
}
|
||||||
|
|
||||||
req := t.makePing(toaddr)
|
req := t.makePing(toaddr)
|
||||||
packet, hash, err := v4wire.Encode(t.priv, req)
|
packet, hash, err := v4wire.Encode(t.priv, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -271,6 +295,41 @@ func (t *UDPv4) makePing(toaddr netip.AddrPort) *v4wire.Ping {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sendPingXDC sends an XDC-specific ping (type 5) to the given node.
|
||||||
|
// XDC nodes use pingXDC instead of standard ping for discovery.
|
||||||
|
func (t *UDPv4) sendPingXDC(toid enode.ID, toaddr netip.AddrPort, callback func()) *replyMatcher {
|
||||||
|
req := t.makePingXDC(toaddr)
|
||||||
|
packet, hash, err := v4wire.Encode(t.priv, req)
|
||||||
|
if err != nil {
|
||||||
|
errc := make(chan error, 1)
|
||||||
|
errc <- err
|
||||||
|
return &replyMatcher{errc: errc}
|
||||||
|
}
|
||||||
|
// Add a matcher for the reply to the pending reply queue. Pongs are matched if they
|
||||||
|
// reference the ping we're about to send.
|
||||||
|
rm := t.pending(toid, toaddr.Addr(), v4wire.PongPacket, func(p v4wire.Packet) (matched bool, requestDone bool) {
|
||||||
|
matched = bytes.Equal(p.(*v4wire.Pong).ReplyTok, hash)
|
||||||
|
if matched && callback != nil {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
return matched, matched
|
||||||
|
})
|
||||||
|
// Send the packet.
|
||||||
|
t.localNode.UDPContact(toaddr)
|
||||||
|
t.write(toaddr, toid, req.Name(), packet)
|
||||||
|
return rm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UDPv4) makePingXDC(toaddr netip.AddrPort) *v4wire.PingXDC {
|
||||||
|
return &v4wire.PingXDC{
|
||||||
|
Version: 4,
|
||||||
|
From: t.ourEndpoint(),
|
||||||
|
To: v4wire.NewEndpoint(toaddr, 0),
|
||||||
|
Expiration: uint64(time.Now().Add(expiration).Unix()),
|
||||||
|
ENRSeq: t.localNode.Node().Seq(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// LookupPubkey finds the closest nodes to the given public key.
|
// LookupPubkey finds the closest nodes to the given public key.
|
||||||
func (t *UDPv4) LookupPubkey(key *ecdsa.PublicKey) []*enode.Node {
|
func (t *UDPv4) LookupPubkey(key *ecdsa.PublicKey) []*enode.Node {
|
||||||
if t.tab.len() == 0 {
|
if t.tab.len() == 0 {
|
||||||
|
|
@ -640,6 +699,11 @@ func (t *UDPv4) wrapPacket(p v4wire.Packet) *packetHandlerV4 {
|
||||||
case *v4wire.Ping:
|
case *v4wire.Ping:
|
||||||
h.preverify = t.verifyPing
|
h.preverify = t.verifyPing
|
||||||
h.handle = t.handlePing
|
h.handle = t.handlePing
|
||||||
|
case *v4wire.PingXDC:
|
||||||
|
// XDC uses pingXDC (type 5) instead of standard ping.
|
||||||
|
// Handle it the same way as a regular ping.
|
||||||
|
h.preverify = t.verifyPingXDC
|
||||||
|
h.handle = t.handlePingXDC
|
||||||
case *v4wire.Pong:
|
case *v4wire.Pong:
|
||||||
h.preverify = t.verifyPong
|
h.preverify = t.verifyPong
|
||||||
case *v4wire.Findnode:
|
case *v4wire.Findnode:
|
||||||
|
|
@ -711,6 +775,50 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from netip.AddrPort, fromID enode
|
||||||
t.localNode.UDPEndpointStatement(from, toaddr)
|
t.localNode.UDPEndpointStatement(from, toaddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PINGXDC/v4 (XDC-specific ping, type 5)
|
||||||
|
|
||||||
|
func (t *UDPv4) verifyPingXDC(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error {
|
||||||
|
req := h.Packet.(*v4wire.PingXDC)
|
||||||
|
|
||||||
|
if v4wire.Expired(req.Expiration) {
|
||||||
|
return errExpired
|
||||||
|
}
|
||||||
|
senderKey, err := v4wire.DecodePubkey(crypto.S256(), fromKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.senderKey = senderKey
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *UDPv4) handlePingXDC(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, mac []byte) {
|
||||||
|
req := h.Packet.(*v4wire.PingXDC)
|
||||||
|
|
||||||
|
// Reply with standard Pong (XDC nodes expect Pong in reply to PingXDC).
|
||||||
|
t.send(from, fromID, &v4wire.Pong{
|
||||||
|
To: v4wire.NewEndpoint(from, req.From.TCP),
|
||||||
|
ReplyTok: mac,
|
||||||
|
Expiration: uint64(time.Now().Add(expiration).Unix()),
|
||||||
|
ENRSeq: t.localNode.Node().Seq(),
|
||||||
|
})
|
||||||
|
|
||||||
|
// Ping back if our last pong on file is too far in the past.
|
||||||
|
fromIP := from.Addr().AsSlice()
|
||||||
|
n := enode.NewV4(h.senderKey, fromIP, int(req.From.TCP), int(from.Port()))
|
||||||
|
if time.Since(t.db.LastPongReceived(n.ID(), from.Addr())) > bondExpiration {
|
||||||
|
t.sendPing(fromID, from, func() {
|
||||||
|
t.tab.addInboundNode(n)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
t.tab.addInboundNode(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update node database and endpoint predictor.
|
||||||
|
t.db.UpdateLastPingReceived(n.ID(), from.Addr(), time.Now())
|
||||||
|
toaddr := netip.AddrPortFrom(netutil.IPToAddr(req.To.IP), req.To.UDP)
|
||||||
|
t.localNode.UDPEndpointStatement(from, toaddr)
|
||||||
|
}
|
||||||
|
|
||||||
// PONG/v4
|
// PONG/v4
|
||||||
|
|
||||||
func (t *UDPv4) verifyPong(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error {
|
func (t *UDPv4) verifyPong(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error {
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,9 @@ const (
|
||||||
NeighborsPacket
|
NeighborsPacket
|
||||||
ENRRequestPacket
|
ENRRequestPacket
|
||||||
ENRResponsePacket
|
ENRResponsePacket
|
||||||
|
|
||||||
|
// XDC-specific packet types
|
||||||
|
PingXDCPacket = 5 // XDC uses type 5 for ping instead of standard type 1
|
||||||
)
|
)
|
||||||
|
|
||||||
// RPC request structures
|
// RPC request structures
|
||||||
|
|
@ -187,6 +190,19 @@ func (req *ENRRequest) Kind() byte { return ENRRequestPacket }
|
||||||
func (req *ENRResponse) Name() string { return "ENRRESPONSE/v4" }
|
func (req *ENRResponse) Name() string { return "ENRRESPONSE/v4" }
|
||||||
func (req *ENRResponse) Kind() byte { return ENRResponsePacket }
|
func (req *ENRResponse) Kind() byte { return ENRResponsePacket }
|
||||||
|
|
||||||
|
// PingXDC is the XDC-specific ping packet (type 5).
|
||||||
|
// It has the same structure as Ping but uses a different packet type.
|
||||||
|
// XDC nodes send pingXDC instead of standard ping for discovery.
|
||||||
|
type PingXDC Ping
|
||||||
|
|
||||||
|
func (req *PingXDC) Name() string { return "PINGXDC/v4" }
|
||||||
|
func (req *PingXDC) Kind() byte { return PingXDCPacket }
|
||||||
|
|
||||||
|
// ToPing converts PingXDC to a standard Ping for processing.
|
||||||
|
func (req *PingXDC) ToPing() *Ping {
|
||||||
|
return (*Ping)(req)
|
||||||
|
}
|
||||||
|
|
||||||
// Expired checks whether the given UNIX time stamp is in the past.
|
// Expired checks whether the given UNIX time stamp is in the past.
|
||||||
func Expired(ts uint64) bool {
|
func Expired(ts uint64) bool {
|
||||||
return time.Unix(int64(ts), 0).Before(time.Now())
|
return time.Unix(int64(ts), 0).Before(time.Now())
|
||||||
|
|
@ -233,8 +249,10 @@ func Decode(input []byte) (Packet, Pubkey, []byte, error) {
|
||||||
req = new(Findnode)
|
req = new(Findnode)
|
||||||
case NeighborsPacket:
|
case NeighborsPacket:
|
||||||
req = new(Neighbors)
|
req = new(Neighbors)
|
||||||
case ENRRequestPacket:
|
case PingXDCPacket:
|
||||||
req = new(ENRRequest)
|
// XDC uses type 5 (pingXDC) with same structure as Ping.
|
||||||
|
// Try to decode as PingXDC first, fall back to ENRRequest.
|
||||||
|
req = new(PingXDC)
|
||||||
case ENRResponsePacket:
|
case ENRResponsePacket:
|
||||||
req = new(ENRResponse)
|
req = new(ENRResponse)
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -474,6 +474,7 @@ func (srv *Server) setupDiscovery() error {
|
||||||
Bootnodes: srv.BootstrapNodes,
|
Bootnodes: srv.BootstrapNodes,
|
||||||
Unhandled: unhandled,
|
Unhandled: unhandled,
|
||||||
Log: srv.log,
|
Log: srv.log,
|
||||||
|
NetworkID: srv.NetworkID, // Pass network ID for XDC-specific discovery
|
||||||
}
|
}
|
||||||
ntab, err := discover.ListenV4(conn, srv.localnode, cfg)
|
ntab, err := discover.ListenV4(conn, srv.localnode, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue