mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 19:30: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.
|
||||
p2pServer := stack.Server()
|
||||
|
||||
// Set NetworkID on P2P server for chain-specific discovery (e.g., XDC uses pingXDC)
|
||||
p2pServer.Config.NetworkID = networkID
|
||||
|
||||
eth := &Ethereum{
|
||||
config: config,
|
||||
chainDb: chainDb,
|
||||
|
|
@ -198,7 +203,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
engine: engine,
|
||||
networkID: networkID,
|
||||
gasPrice: config.Miner.GasPrice,
|
||||
p2pServer: stack.Server(),
|
||||
p2pServer: p2pServer,
|
||||
discmix: enode.NewFairMix(discmixTimeout),
|
||||
shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,6 +124,10 @@ type Config struct {
|
|||
// Logger is a custom logger to use with the p2p.Server.
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,9 @@ type Config struct {
|
|||
RefreshInterval time.Duration // used in bucket refresh
|
||||
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.
|
||||
V5ProtocolID *[6]byte
|
||||
Log log.Logger // if set, log messages go here
|
||||
|
|
|
|||
|
|
@ -80,6 +80,19 @@ type UDPv4 struct {
|
|||
gotreply chan reply
|
||||
closeCtx context.Context
|
||||
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.
|
||||
|
|
@ -143,6 +156,12 @@ func ListenV4(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) {
|
|||
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)
|
||||
if err != nil {
|
||||
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
|
||||
// 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 {
|
||||
// Use pingXDC for XDC networks
|
||||
if t.xdcMode {
|
||||
return t.sendPingXDC(toid, toaddr, callback)
|
||||
}
|
||||
|
||||
req := t.makePing(toaddr)
|
||||
packet, hash, err := v4wire.Encode(t.priv, req)
|
||||
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.
|
||||
func (t *UDPv4) LookupPubkey(key *ecdsa.PublicKey) []*enode.Node {
|
||||
if t.tab.len() == 0 {
|
||||
|
|
@ -640,6 +699,11 @@ func (t *UDPv4) wrapPacket(p v4wire.Packet) *packetHandlerV4 {
|
|||
case *v4wire.Ping:
|
||||
h.preverify = t.verifyPing
|
||||
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:
|
||||
h.preverify = t.verifyPong
|
||||
case *v4wire.Findnode:
|
||||
|
|
@ -711,6 +775,50 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from netip.AddrPort, fromID enode
|
|||
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
|
||||
|
||||
func (t *UDPv4) verifyPong(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ const (
|
|||
NeighborsPacket
|
||||
ENRRequestPacket
|
||||
ENRResponsePacket
|
||||
|
||||
// XDC-specific packet types
|
||||
PingXDCPacket = 5 // XDC uses type 5 for ping instead of standard type 1
|
||||
)
|
||||
|
||||
// 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) 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.
|
||||
func Expired(ts uint64) bool {
|
||||
return time.Unix(int64(ts), 0).Before(time.Now())
|
||||
|
|
@ -233,8 +249,10 @@ func Decode(input []byte) (Packet, Pubkey, []byte, error) {
|
|||
req = new(Findnode)
|
||||
case NeighborsPacket:
|
||||
req = new(Neighbors)
|
||||
case ENRRequestPacket:
|
||||
req = new(ENRRequest)
|
||||
case PingXDCPacket:
|
||||
// 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:
|
||||
req = new(ENRResponse)
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -474,6 +474,7 @@ func (srv *Server) setupDiscovery() error {
|
|||
Bootnodes: srv.BootstrapNodes,
|
||||
Unhandled: unhandled,
|
||||
Log: srv.log,
|
||||
NetworkID: srv.NetworkID, // Pass network ID for XDC-specific discovery
|
||||
}
|
||||
ntab, err := discover.ListenV4(conn, srv.localnode, cfg)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue