From 69ef5716fc9d5eb861b451b2c9012130351c1430 Mon Sep 17 00:00:00 2001 From: Krish Date: Fri, 19 Jan 2024 17:02:38 +0800 Subject: [PATCH] feat: add static peers on bootnode --- cmd/bootnode/main.go | 16 ++++- cmd/bootnode/static_nodes.go | 110 ++++++++++++++++++++++++++++++++++ core/blockchain.go | 1 - core/state/statedb.go | 1 - p2p/discover/common.go | 4 ++ p2p/discover/table.go | 26 +++++--- p2p/discover/v4_udp.go | 88 +++++++++++++++++++-------- p2p/discover/v4_udp_test.go | 18 ++++++ p2p/discover/v4wire/v4wire.go | 2 +- 9 files changed, 230 insertions(+), 36 deletions(-) create mode 100644 cmd/bootnode/static_nodes.go diff --git a/cmd/bootnode/main.go b/cmd/bootnode/main.go index 748113aa48..14d1494dcd 100644 --- a/cmd/bootnode/main.go +++ b/cmd/bootnode/main.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/discover/v4wire" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/netutil" @@ -45,10 +46,14 @@ func main() { runv5 = flag.Bool("v5", false, "run a v5 topic discovery bootnode") verbosity = flag.Int("verbosity", int(log.LvlInfo), "log verbosity (0-5)") vmodule = flag.String("vmodule", "", "log verbosity pattern") + network = flag.String("network", "", "testnet/mainnet") nodeKey *ecdsa.PrivateKey err error ) + + var staticV4Nodes []v4wire.Node + flag.Parse() glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) @@ -86,6 +91,12 @@ func main() { } } + if *network == "testnet" { + staticV4Nodes = staticV4NodesTestnet + } else { + staticV4Nodes = staticV4NodesMainnet + } + if *writeAddr { fmt.Printf("%x\n", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:]) os.Exit(0) @@ -123,8 +134,9 @@ func main() { db, _ := enode.OpenDB("") ln := enode.NewLocalNode(db, nodeKey) cfg := discover.Config{ - PrivateKey: nodeKey, - NetRestrict: restrictList, + PrivateKey: nodeKey, + NetRestrict: restrictList, + StaticV4Nodes: staticV4Nodes, } if *runv5 { if _, err := discover.ListenV5(conn, ln, cfg); err != nil { diff --git a/cmd/bootnode/static_nodes.go b/cmd/bootnode/static_nodes.go new file mode 100644 index 0000000000..f90a9cb796 --- /dev/null +++ b/cmd/bootnode/static_nodes.go @@ -0,0 +1,110 @@ +package main + +import ( + "encoding/hex" + "net" + + "github.com/ethereum/go-ethereum/p2p/discover/v4wire" +) + +var staticV4NodesTestnet = []v4wire.Node{ + //p2p-0 + + { + IP: net.ParseIP("18.177.245.157").To4(), + UDP: 30303, + TCP: 30303, + ID: decodePubkeyV4("223488870e492f49873b621c21f3e1302f00993aaa5214a077a1c4eb62dfe96675cc7a3360525c3409480d1ec13cc72f432b4d50f5e70f98e60385dc25d4be6b"), + }, + + //p2p-1 + { + IP: net.ParseIP("18.176.219.164").To4(), + UDP: 30303, + TCP: 30303, + ID: decodePubkeyV4("f6a082e7861762da7e5d65ebf92b06e72b9fde81787a1a71ec8ab407345f3a7787e2617c5b9565ea3a1be46f794eeb791aef3059818b23588f2352b1d7973dfd"), + }, +} + +var staticV4NodesMainnet = []v4wire.Node{ + //ap-p2p-0 + + { + IP: net.ParseIP("52.193.218.151").To4(), + UDP: 30303, + TCP: 30303, + ID: decodePubkeyV4("db109c6cac5c8b6225edd3176fc3764c58e0720950fe94c122c80978e706a9c9e976629b718e48b6306ea0f9126e5394d3424c9716c5703549e2e7eba216353b"), + }, + + //ap-p2p-1 + { + IP: net.ParseIP("52.195.105.192").To4(), + UDP: 30303, + TCP: 30303, + ID: decodePubkeyV4("afe18782053bb31fb7ea41e1acf659ab9bd1eec181fb97331f0a6b61871a469b4f75138f903c977796be1cc2a3c985d33150a396e878d3cd6e4723b6040ff9c0"), + }, + //ap-p2p-2 + { + IP: net.ParseIP("18.182.161.116").To4(), + UDP: 30303, + TCP: 30303, + ID: decodePubkeyV4("0cbbf05d39193127e373038f41cdfb520644453dc764bac49f8403b774f2aab7e679b72ac1ee692f19f55cf07cdf07ef99195c841cbe30d263955149de9213cb"), + }, + //us-p2p-2 + { + IP: net.ParseIP("34.205.6.198").To4(), + UDP: 30303, + TCP: 30303, + ID: decodePubkeyV4("ad16edbb25953c36026636427d637fd874f65d1895a589c987009cb820a675cb0f0e1a1dffe34b826a8ef4cc9a0da398cc921ce612de7e6167dd3fdf3db9a1d9"), + }, + //us-p2p-1 + { + IP: net.ParseIP("34.194.74.36").To4(), + UDP: 30303, + TCP: 30303, + ID: decodePubkeyV4("852a9d69b385ccf858227ab741d73821704b7fc4abf6510840e8769a44c0d360d269a6ff6b0c42d7335e1caa494a16e45e24ad8aaa9830509f1d8ff49ebb1288"), + }, + //us-p2p-0 + { + IP: net.ParseIP("54.211.157.22").To4(), + UDP: 30303, + TCP: 30303, + ID: decodePubkeyV4("23538322b4fa60a936395012b37d5b4407717eec54c64232bd4e985b24ad941c3e4dd36d634e053286d926ceed66c725f8f2a72003f59901b963dee9d9983080"), + }, + //eu-p2p-0 + { + IP: net.ParseIP("34.246.100.156").To4(), + UDP: 30303, + TCP: 30303, + ID: decodePubkeyV4("752038ca7a0359e967d5096453935a5c3d5a13864c3551bd60c5d7d8e6547b2d68b1ceb484d872116ac6977b78d1d39fab8ebd92d22e68b032ffc196fa6cecd7"), + }, + //eu-p2p-1 + { + IP: net.ParseIP("99.81.30.183").To4(), + UDP: 30303, + TCP: 30303, + ID: decodePubkeyV4("6c24f4531d755d647ee3d8082f7945f051032c7bc1fc6c90ae6c328092efa2cf1ce429db01e7c4efe26f198eecf996979c2958745ac1f4d831f88231abd0096e"), + }, + //eu-p2p-2 + { + IP: net.ParseIP("34.243.159.16").To4(), + UDP: 30303, + TCP: 30303, + ID: decodePubkeyV4("f39da1c3b027b5683387c724363e0e132c287a6094564a05b43e8f22508e973098b3c7234df09beabcc19827f1d8998bd1e1d960fb5949bac0317bbe7fcb20a4"), + }, +} + +// decodePubkeyV4 +func decodePubkeyV4(hexPubkey string) v4wire.Pubkey { + pubkeyBytes, err := hex.DecodeString(hexPubkey) + if err != nil { + return v4wire.Pubkey{} + } + if len(pubkeyBytes) != 64 { + return v4wire.Pubkey{} + } + + var pubkey v4wire.Pubkey + copy(pubkey[:], pubkeyBytes) + return pubkey +} diff --git a/core/blockchain.go b/core/blockchain.go index 1035ff1703..cead459551 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1826,7 +1826,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) // skip block process if we already have the state, receipts and logs from mining work if !(receiptExist && logExist && stateExist) { - log.Info("Krish debug:") // Retrieve the parent block and it's state to execute on top parent := it.previous() if parent == nil { diff --git a/core/state/statedb.go b/core/state/statedb.go index 952ffa6e94..b4296a9498 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -169,7 +169,6 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) // NewWithSharedPool creates a new state with sharedStorge on layer 1.5 func NewWithSharedPool(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) { - log.Info("debug: NewWithSharedPool called") statedb, err := New(root, db, snaps) if err != nil { return nil, err diff --git a/p2p/discover/common.go b/p2p/discover/common.go index c36e8dcc3a..80455a8c65 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/discover/v4wire" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/netutil" @@ -55,6 +56,9 @@ type Config struct { ValidSchemes enr.IdentityScheme // allowed identity schemes Clock mclock.Clock + + //static v4 nodes + StaticV4Nodes []v4wire.Node } func (cfg Config) withDefaults() Config { diff --git a/p2p/discover/table.go b/p2p/discover/table.go index f9e4747d69..8180ca3394 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -317,14 +317,12 @@ func (tab *Table) loadSeedNodes() { func (tab *Table) doRevalidate(done chan<- struct{}) { defer func() { done <- struct{}{} }() - log.Info("do revalidate") last, bi := tab.nodeToRevalidate() if last == nil { // No non-empty bucket found. return } - log.Info("do revalidate send ping") // Ping the selected node and wait for a pong. remoteSeq, err := tab.net.ping(unwrapNode(last)) @@ -413,13 +411,12 @@ func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) * liveNodes := &nodesByDistance{target: target} for _, b := range &tab.buckets { for _, n := range b.entries { - // 使用xorDistance函数计算节点n与目标ID的距离 distance := xorDistance(target, n.ID()) nodes.push(n, nresults) if preferLive && n.livenessChecks > 0 { liveNodes.push(n, nresults) } - log.Info("ZXL Distance", "Node ID", n.ID(), "Target ID", target, "XOR Distance", distance) + log.Trace("Distance", "Node ID", n.ID(), "Target ID", target, "XOR Distance", distance) } } @@ -451,6 +448,21 @@ func (tab *Table) getAllNodeIDs() []enode.ID { return ids } +// get node by given id +func (tab *Table) getNodeByID(id enode.ID) enode.Node { + tab.mutex.Lock() + defer tab.mutex.Unlock() + + for _, b := range tab.buckets { + for _, n := range b.entries { + if n.ID().String() == id.String() { + return n.Node + } + } + } + return enode.Node{} +} + // get all nodes ids func (tab *Table) getAllNodes() []enode.Node { tab.mutex.Lock() @@ -542,7 +554,7 @@ func (tab *Table) addSeenNode(n *node) { // // The caller must not hold tab.mutex. func (tab *Table) addVerifiedNode(n *node) { - log.Info("ZXL: addVerifiedNode", "nodeIP", n.IP().String(), "nodeId", n.ID().String()) + log.Trace("addVerifiedNode", "nodeIP", n.IP().String(), "nodeId", n.ID().String()) if !tab.isInitDone() { return } @@ -552,9 +564,9 @@ func (tab *Table) addVerifiedNode(n *node) { nodes := tab.getAllNodes() for i, nodeIndex := range nodes { - log.Info("ZXL: current tab content", "index", i, "nodeId", nodeIndex.ID(), "nodeIP", nodeIndex.IP().String()) + log.Trace("current tab content", "index", i, "nodeId", nodeIndex.ID(), "nodeIP", nodeIndex.IP().String()) for j, pair := range nodeIndex.Record().GetPairs() { - log.Info("ZXL: current node content", "node index", i, "pair index", j, "pairKey", pair.GetPairKey(), "pairValue", pair.GetPairValue()) + log.Trace("current node content", "node index", i, "pair index", j, "pairKey", pair.GetPairKey(), "pairValue", pair.GetPairValue()) } } diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index f02efe9cb2..ee92ec3a49 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -25,6 +25,7 @@ import ( "errors" "fmt" "io" + "math/rand" "net" "sync" "time" @@ -48,6 +49,24 @@ var ( errLowPort = errors.New("low port") ) +/* +// decodePubkeyV4 +func decodePubkeyV4(hexPubkey string) (v4wire.Pubkey, error) { + pubkeyBytes, err := hex.DecodeString(hexPubkey) + if err != nil { + return v4wire.Pubkey{}, err + } + if len(pubkeyBytes) != 64 { + return v4wire.Pubkey{}, fmt.Errorf("public key is not 64 bytes long") + } + + var pubkey v4wire.Pubkey + copy(pubkey[:], pubkeyBytes) + return pubkey, nil +} + +*/ + const ( respTimeout = 500 * time.Millisecond expiration = 20 * time.Second @@ -80,6 +99,9 @@ type UDPv4 struct { gotreply chan reply closeCtx context.Context cancelCloseCtx context.CancelFunc + + //static peers + staticNodes []v4wire.Node } // replyMatcher represents a pending reply. @@ -141,6 +163,7 @@ func ListenV4(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) { closeCtx: closeCtx, cancelCloseCtx: cancel, log: cfg.Log, + staticNodes: cfg.StaticV4Nodes, } tab, err := newTable(t, ln.Database(), cfg.Bootnodes, t.log) @@ -216,7 +239,6 @@ func (t *UDPv4) Ping(n *enode.Node) error { // ping sends a ping message to the given node and waits for a reply. func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) { - log.Info("ZXL: sendPing from ping") rm := t.sendPing(n.ID(), &net.UDPAddr{IP: n.IP(), Port: n.UDP()}, nil) if err = <-rm.errc; err == nil { seq = rm.reply.(*v4wire.Pong).ENRSeq @@ -226,11 +248,10 @@ func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) { // sendPing sends a ping message to the given node and invokes the callback // when the reply arrives. -// ZXL 在这里发生的变化 -// 只要给Bootndoe发过就会更替 +// 在这里发生的变化,只要给Bootndoe发过就会更替 func (t *UDPv4) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) *replyMatcher { req := t.makePing(toaddr) - log.Warn("ZXL SendPing", "toID", toid, "fromIP", req.From.IP.String(), "fromPortTCP", req.From.TCP, "fromPortUDP", req.From.UDP) + log.Trace("SendPing", "toID", toid, "fromIP", req.From.IP.String(), "fromPortTCP", req.From.TCP, "fromPortUDP", req.From.UDP) packet, hash, err := v4wire.Encode(t.priv, req) if err != nil { errc := make(chan error, 1) @@ -304,7 +325,7 @@ func (t *UDPv4) newLookup(ctx context.Context, targetKey encPubkey) *lookup { // findnode sends a findnode request to the given node and waits until // the node has sent up to k neighbors. -// ZXL: 处理neighbors逻辑的地方 +// 处理neighbors逻辑的地方 func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target v4wire.Pubkey) ([]*node, error) { t.ensureBond(toid, toaddr) @@ -515,9 +536,11 @@ func (t *UDPv4) send(toaddr *net.UDPAddr, toid enode.ID, req v4wire.Packet) ([]b func (t *UDPv4) write(toaddr *net.UDPAddr, toid enode.ID, what string, packet []byte) error { _, err := t.conn.WriteToUDP(packet, toaddr) t.log.Trace(">> "+what, "id", toid, "addr", toaddr, "err", err) - if what == "FINDNODE/v4" { - log.Info("FINDNODE msg") - } + /* + if what == "FINDNODE/v4" { + log.Info("FINDNODE msg") + } + */ return err } @@ -579,7 +602,7 @@ func (t *UDPv4) checkBond(id enode.ID, ip net.IP) bool { func (t *UDPv4) ensureBond(toid enode.ID, toaddr *net.UDPAddr) { tooOld := time.Since(t.db.LastPingReceived(toid, toaddr.IP)) > bondExpiration if tooOld || t.db.FindFails(toid, toaddr.IP) > maxFindnodeFailures { - log.Info("ZXL: sendPing from ensureBond") + log.Trace("sendPing from ensureBond") rm := t.sendPing(toid, toaddr, nil) <-rm.errc // Wait for them to ping back and process our pong. @@ -676,13 +699,13 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I Expiration: uint64(time.Now().Add(expiration).Unix()), ENRSeq: t.localNode.Node().Seq(), }) - log.Info("ZXL: handlePing,sendPong", "nodeId", fromID, "targetIP", from.IP.String(), "targetPort", from.Port) + log.Trace("handlePing,sendPong", "nodeId", fromID, "targetIP", from.IP.String(), "targetPort", from.Port) // Ping back if our last pong on file is too far in the past. - //ZXL + // TODO n := wrapNode(enode.NewV4(h.senderKey, from.IP, int(req.From.TCP), from.Port)) if time.Since(t.db.LastPongReceived(n.ID(), from.IP)) > bondExpiration { - log.Info("ZXL: sendPing from bondExpiration") + log.Trace("sendPing from bondExpiration") t.sendPing(fromID, from, func() { t.tab.addVerifiedNode(n) }) @@ -719,19 +742,20 @@ func (t *UDPv4) verifyFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno if v4wire.Expired(req.Expiration) { return errExpired } - /** + /* + if !t.checkBond(fromID, from.IP) { + // No endpoint proof poudpng exists, we don't process the packet. This prevents an + // attack vector where the discovery protocol could be used to amplify traffic in a + // DDOS attack. A malicious actor would send a findnode request with the IP address + // and UDP port of the target as the source address. The recipient of the findnode + // packet would then send a neighbors packet (which is a much bigger packet than + // findnode) to the victim. + return errUnknownNode + } - if !t.checkBond(fromID, from.IP) { - // No endpoint proof poudpng exists, we don't process the packet. This prevents an - // attack vector where the discovery protocol could be used to amplify traffic in a - // DDOS attack. A malicious actor would send a findnode request with the IP address - // and UDP port of the target as the source address. The recipient of the findnode - // packet would then send a neighbors packet (which is a much bigger packet than - // findnode) to the victim. - return errUnknownNode - } */ + return nil } @@ -745,6 +769,13 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno // Send neighbors in chunks with at most maxNeighbors per packet // to stay below the packet size limit. p := v4wire.Neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} + + // Add static peers + for i, staticNode := range t.staticNodes { + log.Debug("static nodes", "index", i, "node ID", staticNode.ID.ID().String(), "IP", staticNode.IP.String()) + p.Nodes = append(p.Nodes, staticNode) + } + var sent bool for _, n := range closest { if netutil.CheckRelayIP(from.IP, n.IP()) == nil { @@ -757,17 +788,26 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno } } if len(p.Nodes) > 0 || !sent { + shuffleNodes(p.Nodes) t.send(from, fromID, &p) } } +// shuffleNodes takes a slice of nodes and shuffles them in place. +func shuffleNodes(nodes []v4wire.Node) { + rand.Seed(time.Now().UnixNano()) // Ensure a different sequence each time + rand.Shuffle(len(nodes), func(i, j int) { + nodes[i], nodes[j] = nodes[j], nodes[i] + }) +} + // NEIGHBORS/v4 func (t *UDPv4) verifyNeighbors(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { - log.Info("ZXL: verifyNeighbors", "fromIp", from.IP.String(), "fromPort", from.Port) + log.Debug("verifyNeighbors", "fromIp", from.IP.String(), "fromPort", from.Port) req := h.Packet.(*v4wire.Neighbors) for i, neighbor := range req.Nodes { - log.Info("ZXL: received neighbors", "index", i, "IP", neighbor.IP.String(), "UDP_PORT", neighbor.UDP, "TCP_PORT", neighbor.TCP, "NodeId", neighbor.ID.ID()) + log.Debug("received neighbors", "index", i, "IP", neighbor.IP.String(), "UDP_PORT", neighbor.UDP, "TCP_PORT", neighbor.TCP, "NodeId", neighbor.ID.ID()) } if v4wire.Expired(req.Expiration) { diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 21f0d75172..4dcfe1a4ce 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -21,6 +21,7 @@ import ( "crypto/ecdsa" crand "crypto/rand" "encoding/binary" + "encoding/hex" "errors" "fmt" "io" @@ -664,3 +665,20 @@ func (c *dgramPipe) receive() (dgram, error) { c.queue = c.queue[:len(c.queue)-1] return p, nil } + +func TestPubkeyToID(t *testing.T) { + hexPubkey := "223488870e492f49873b621c21f3e1302f00993aaa5214a077a1c4eb62dfe96675cc7a3360525c3409480d1ec13cc72f432b4d50f5e70f98e60385dc25d4be6b" + + pubkeyBytes, err := hex.DecodeString(hexPubkey) + if err != nil { + t.Fatalf("Error decoding public key: %v", err) + } + + var pubkey v4wire.Pubkey + copy(pubkey[:], pubkeyBytes) + + nodeID := pubkey.ID() + + fmt.Printf("Node ID: %s\n", nodeID.String()) + +} diff --git a/p2p/discover/v4wire/v4wire.go b/p2p/discover/v4wire/v4wire.go index 3935068cd9..89ac9203f2 100644 --- a/p2p/discover/v4wire/v4wire.go +++ b/p2p/discover/v4wire/v4wire.go @@ -103,7 +103,7 @@ type ( ) // MaxNeighbors is the maximum number of neighbor nodes in a Neighbors packet. -const MaxNeighbors = 12 +const MaxNeighbors = 20 // This code computes the MaxNeighbors constant value.