From 30cc637d0d7f856dda976518f6dbf57a3251d88a Mon Sep 17 00:00:00 2001 From: Krish Date: Tue, 17 Oct 2023 09:31:42 +0800 Subject: [PATCH 1/8] feat: add dockerfile for bootnode build --- .github/workflows/docker-release.yml | 33 ++++++++++++++++++++++++ cmd/bootnode/Dockerfile | 33 ++++++++++++++++++++++++ cmd/bootnode/Makefile | 38 ++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 cmd/bootnode/Dockerfile create mode 100644 cmd/bootnode/Makefile diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index be1d1ec01d..281bf4eefb 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -42,3 +42,36 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + + push-op-geth-bootnode: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to GHCR + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: image meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ghcr.io/${{ github.repository_owner }}/op-geth-bootnode + tags: | + type=ref,event=branch + type=ref,event=tag + type=semver,pattern={{version}} + type=sha + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + file: ./cmd/bootnode/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/cmd/bootnode/Dockerfile b/cmd/bootnode/Dockerfile new file mode 100644 index 0000000000..8dacdf5728 --- /dev/null +++ b/cmd/bootnode/Dockerfile @@ -0,0 +1,33 @@ +# Support setting various labels on the final image +ARG COMMIT="" +ARG VERSION="" +ARG BUILDNUM="" + +# Build Geth in a stock Go builder container +FROM golang:1.20-alpine as builder + +RUN apk add --no-cache gcc musl-dev linux-headers git + +# Get dependencies - will also be cached if we won't change go.mod/go.sum +COPY go.mod /go-ethereum/ +COPY go.sum /go-ethereum/ +RUN cd /go-ethereum && go mod download + +ADD . /go-ethereum +RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/bootnode + +# Pull Geth into a second stage deploy alpine container +FROM alpine:latest + +RUN apk add --no-cache ca-certificates +COPY --from=builder /go-ethereum/build/bin/bootnode /usr/local/bin/ + +EXPOSE 8545 8546 30303 30303/udp +ENTRYPOINT ["bootnode"] + +# Add some metadata labels to help programatic image consumption +ARG COMMIT="" +ARG VERSION="" +ARG BUILDNUM="" + +LABEL commit="$COMMIT" version="$VERSION" buildnum="$BUILDNUM" diff --git a/cmd/bootnode/Makefile b/cmd/bootnode/Makefile new file mode 100644 index 0000000000..e6286da7fb --- /dev/null +++ b/cmd/bootnode/Makefile @@ -0,0 +1,38 @@ +# This Makefile is meant to be used by people that do not usually work +# with Go source code. If you know what GOPATH is then you probably +# don't need to bother with make. + +.PHONY: geth android ios evm all test clean + +GOBIN = ./build/bin +GO ?= latest +GORUN = env GO111MODULE=on go run + +geth: + $(GORUN) build/ci.go install ./cmd/geth + @echo "Done building." + @echo "Run \"$(GOBIN)/geth\" to launch geth." + +all: + $(GORUN) build/ci.go install + +test: all + $(GORUN) build/ci.go test + +lint: ## Run linters. + $(GORUN) build/ci.go lint + +clean: + env GO111MODULE=on go clean -cache + rm -fr build/_workspace/pkg/ $(GOBIN)/* + +# The devtools target installs tools required for 'go generate'. +# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'. + +devtools: + env GOBIN= go install golang.org/x/tools/cmd/stringer@latest + env GOBIN= go install github.com/fjl/gencodec@latest + env GOBIN= go install github.com/golang/protobuf/protoc-gen-go@latest + env GOBIN= go install ./cmd/abigen + @type "solc" 2> /dev/null || echo 'Please install solc' + @type "protoc" 2> /dev/null || echo 'Please install protoc' From 2ec70baeecb51d9d673a91bcc7ce61dc0cec70d8 Mon Sep 17 00:00:00 2001 From: Krish Date: Thu, 30 Nov 2023 11:43:18 +0800 Subject: [PATCH 2/8] debug: add more trace for UDP discovery --- p2p/discover/table.go | 1 + p2p/discover/v4_udp.go | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 0bcb540062..caa664ad2e 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -501,6 +501,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(), "nodePort", "nodeId", n.ID().String()) if !tab.isInitDone() { return } diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index cbf396df3f..00ba912a7b 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -224,8 +224,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 在这里发生的变化 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) packet, hash, err := v4wire.Encode(t.priv, req) if err != nil { errc := make(chan error, 1) @@ -299,6 +301,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逻辑的地方 func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target v4wire.Pubkey) ([]*node, error) { t.ensureBond(toid, toaddr) @@ -497,6 +500,7 @@ func (t *UDPv4) loop() { } } +// 通用send? send func (t *UDPv4) send(toaddr *net.UDPAddr, toid enode.ID, req v4wire.Packet) ([]byte, error) { packet, hash, err := v4wire.Encode(t.priv, req) if err != nil { @@ -508,6 +512,9 @@ 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") + } return err } @@ -665,8 +672,10 @@ 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) // Ping back if our last pong on file is too far in the past. + //ZXL 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 { t.sendPing(fromID, from, func() { @@ -706,7 +715,7 @@ func (t *UDPv4) verifyFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno return errExpired } if !t.checkBond(fromID, from.IP) { - // No endpoint proof pong exists, we don't process the packet. This prevents an + // 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 From f8178ce50785cc4514dfadf1ee6dc434e4db629e Mon Sep 17 00:00:00 2001 From: Krish Date: Wed, 6 Dec 2023 12:08:44 +0800 Subject: [PATCH 3/8] debug: add debug info --- core/blockchain.go | 1 + core/state/state_object.go | 12 ++++++++++++ p2p/discover/table.go | 2 +- p2p/discover/v4_udp.go | 4 ++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/core/blockchain.go b/core/blockchain.go index 2b51883f81..d8b09a2312 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1821,6 +1821,7 @@ 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/state_object.go b/core/state/state_object.go index 2bf9dd2f4e..5a4828d604 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -178,20 +179,31 @@ func (s *stateObject) getOriginStorage(key common.Hash) (common.Hash, bool) { } // if L1 cache miss, try to get it from shared pool if s.sharedOriginStorage != nil { + log.Info("debug: sharedOriginStorage not nil", "sharedOriginStorage enabled?", s.db.writeOnSharedStorage) val, ok := s.sharedOriginStorage.Load(key) if !ok { + log.Info("debug: get OriginStorage", "key", key, "value", val, "db address", fmt.Sprintf("%p", s)) return common.Hash{}, false } s.originStorage[key] = val.(common.Hash) return val.(common.Hash), true + } else if s.db.writeOnSharedStorage { + log.Info("debug: sharedOriginStorage is nil", "sharedOriginStorage enabled?", s.db.writeOnSharedStorage) } return common.Hash{}, false } func (s *stateObject) setOriginStorage(key common.Hash, value common.Hash) { if s.db.writeOnSharedStorage && s.sharedOriginStorage != nil { + log.Info("debug: set OriginStorage", "key", key, "value", value) s.sharedOriginStorage.Store(key, value) } + if s.db.writeOnSharedStorage && s.sharedOriginStorage == nil { + log.Info("debug: OriginStorage enabled?", "enabled", s.db.writeOnSharedStorage, "sharedOriginStorage is null", "true") + } + if !s.db.writeOnSharedStorage && s.sharedOriginStorage != nil { + log.Info("debug: OriginStorage enabled?", "enabled", s.db.writeOnSharedStorage, "sharedOriginStorage is null?", "not null") + } s.originStorage[key] = value } diff --git a/p2p/discover/table.go b/p2p/discover/table.go index caa664ad2e..4b01373750 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -501,7 +501,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(), "nodePort", "nodeId", n.ID().String()) + log.Info("ZXL: addVerifiedNode", "nodeIP", n.IP().String(), "nodeId", n.ID().String()) if !tab.isInitDone() { return } diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 00ba912a7b..ba21269137 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -755,7 +755,11 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno // 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) 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()) + } if v4wire.Expired(req.Expiration) { return errExpired From 0cabd94a54b687d592df117c58d8805fb717af43 Mon Sep 17 00:00:00 2001 From: Krish Date: Wed, 10 Jan 2024 18:02:38 +0800 Subject: [PATCH 4/8] debug: add more logs --- p2p/discover/table.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 4b01373750..74f0fa8dc7 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -424,6 +424,20 @@ func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) * return nodes } +// get all nodes ids +func (tab *Table) getAllNodeIDs() []enode.ID { + tab.mutex.Lock() + defer tab.mutex.Unlock() + + var ids []enode.ID + for _, b := range tab.buckets { + for _, n := range b.entries { + ids = append(ids, n.ID()) + } + } + return ids +} + // len returns the number of nodes in the table. func (tab *Table) len() (n int) { tab.mutex.Lock() @@ -508,6 +522,11 @@ func (tab *Table) addVerifiedNode(n *node) { if n.ID() == tab.self().ID() { return } + nodeIDs := tab.getAllNodeIDs() + + for i, id := range nodeIDs { + log.Info("ZXL: current tab content", "index", i, "nodeId", id.String()) + } tab.mutex.Lock() defer tab.mutex.Unlock() From a985316f6adb9857073c530daa933a5c0f0541ad Mon Sep 17 00:00:00 2001 From: Krish Date: Wed, 10 Jan 2024 18:07:54 +0800 Subject: [PATCH 5/8] fix: update dockerfile --- cmd/bootnode/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/bootnode/Dockerfile b/cmd/bootnode/Dockerfile index 8dacdf5728..f1d1272d53 100644 --- a/cmd/bootnode/Dockerfile +++ b/cmd/bootnode/Dockerfile @@ -6,6 +6,7 @@ ARG BUILDNUM="" # Build Geth in a stock Go builder container FROM golang:1.20-alpine as builder +RUN apk add --no-cache build-base libc-dev RUN apk add --no-cache gcc musl-dev linux-headers git # Get dependencies - will also be cached if we won't change go.mod/go.sum @@ -14,6 +15,8 @@ COPY go.sum /go-ethereum/ RUN cd /go-ethereum && go mod download ADD . /go-ethereum +ENV CGO_CFLAGS="-O -D__BLST_PORTABLE__" +ENV CGO_CFLAGS_ALLOW="-O -D__BLST_PORTABLE__" RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/bootnode # Pull Geth into a second stage deploy alpine container From b9c67d0cc95eccc6237bff8b6969be4b41ec4ef7 Mon Sep 17 00:00:00 2001 From: Krish Date: Wed, 10 Jan 2024 19:12:36 +0800 Subject: [PATCH 6/8] test: remove pong bond verify --- p2p/discover/v4_udp.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index ba21269137..5d6f2b20e7 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -714,6 +714,9 @@ 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 @@ -723,6 +726,7 @@ func (t *UDPv4) verifyFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno // findnode) to the victim. return errUnknownNode } + */ return nil } @@ -778,9 +782,12 @@ func (t *UDPv4) verifyENRRequest(h *packetHandlerV4, from *net.UDPAddr, fromID e if v4wire.Expired(req.Expiration) { return errExpired } - if !t.checkBond(fromID, from.IP) { - return errUnknownNode - } + /* + if !t.checkBond(fromID, from.IP) { + return errUnknownNode + } + + */ return nil } From 22fa6fdce093b2a0afaf4e896eb0f63476f5c60a Mon Sep 17 00:00:00 2001 From: Krish Date: Fri, 12 Jan 2024 17:26:42 +0800 Subject: [PATCH 7/8] debug: add more logs --- p2p/discover/table.go | 37 ++++++++++++++++++++++++++++++++++--- p2p/discover/v4_udp.go | 10 ++++++++++ p2p/enr/enr.go | 12 ++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 74f0fa8dc7..f9e4747d69 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -317,12 +317,14 @@ 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)) @@ -411,10 +413,14 @@ 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) + } } @@ -424,6 +430,13 @@ func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) * return nodes } +func xorDistance(a, b enode.ID) (distance enode.ID) { + for i := range a { + distance[i] = a[i] ^ b[i] + } + return distance +} + // get all nodes ids func (tab *Table) getAllNodeIDs() []enode.ID { tab.mutex.Lock() @@ -438,6 +451,20 @@ func (tab *Table) getAllNodeIDs() []enode.ID { return ids } +// get all nodes ids +func (tab *Table) getAllNodes() []enode.Node { + tab.mutex.Lock() + defer tab.mutex.Unlock() + + var nodes []enode.Node + for _, b := range tab.buckets { + for _, n := range b.entries { + nodes = append(nodes, n.Node) + } + } + return nodes +} + // len returns the number of nodes in the table. func (tab *Table) len() (n int) { tab.mutex.Lock() @@ -522,10 +549,14 @@ func (tab *Table) addVerifiedNode(n *node) { if n.ID() == tab.self().ID() { return } - nodeIDs := tab.getAllNodeIDs() + nodes := tab.getAllNodes() - for i, id := range nodeIDs { - log.Info("ZXL: current tab content", "index", i, "nodeId", id.String()) + for i, nodeIndex := range nodes { + log.Info("ZXL: 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()) + + } } tab.mutex.Lock() diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 5d6f2b20e7..f02efe9cb2 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -209,12 +209,14 @@ func (t *UDPv4) ourEndpoint() v4wire.Endpoint { // Ping sends a ping message to the given node. func (t *UDPv4) Ping(n *enode.Node) error { + log.Info("send ping from ping-ping") _, err := t.ping(n) return err } // 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 @@ -225,6 +227,7 @@ 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发过就会更替 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) @@ -576,6 +579,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") rm := t.sendPing(toid, toaddr, nil) <-rm.errc // Wait for them to ping back and process our pong. @@ -678,6 +682,7 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I //ZXL 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") t.sendPing(fromID, from, func() { t.tab.addVerifiedNode(n) }) @@ -792,6 +797,11 @@ func (t *UDPv4) verifyENRRequest(h *packetHandlerV4, from *net.UDPAddr, fromID e } func (t *UDPv4) handleENRRequest(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) { + log.Info("handle ENR reqeust", "from", from, "fromID", fromID) + record := t.localNode.Node().Record() + for i, p := range record.GetPairs() { + log.Info("ENR pairs", "index", i, "key", p.GetPairKey(), "value", p.GetPairValue()) + } t.send(from, fromID, &v4wire.ENRResponse{ ReplyTok: mac, Record: *t.localNode.Node().Record(), diff --git a/p2p/enr/enr.go b/p2p/enr/enr.go index 2b093b2f1a..697e942639 100644 --- a/p2p/enr/enr.go +++ b/p2p/enr/enr.go @@ -90,12 +90,24 @@ type Record struct { pairs []pair // sorted list of all key/value pairs } +func (r *Record) GetPairs() []pair { + return r.pairs +} + // pair is a key/value pair in a record. type pair struct { k string v rlp.RawValue } +func (r *pair) GetPairKey() string { + return r.k +} + +func (r *pair) GetPairValue() rlp.RawValue { + return r.v +} + // Size returns the encoded size of the record. func (r *Record) Size() uint64 { if r.raw != nil { From 69ef5716fc9d5eb861b451b2c9012130351c1430 Mon Sep 17 00:00:00 2001 From: Krish Date: Fri, 19 Jan 2024 17:02:38 +0800 Subject: [PATCH 8/8] 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.