From 4cc632f4482d4c9c40dc41684956a434d6ec5cd8 Mon Sep 17 00:00:00 2001 From: "larry.lx" Date: Tue, 23 May 2023 19:47:51 +0800 Subject: [PATCH] fix: support trust mode --- eth/handler.go | 28 +++++++++++++++++----------- eth/handler_eth_test.go | 32 ++++++++++++++++++++++++-------- p2p/peer.go | 6 +++++- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/eth/handler.go b/eth/handler.go index 6cce481e56..95bfc8bc93 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -391,22 +391,23 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { } } // Ignore maxPeers if this is a trusted peer - if !peer.Peer.Info().Network.Trusted { + peerInfo := peer.Peer.Info() + if !peerInfo.Network.Trusted { if reject || h.peers.len() >= h.maxPeers { return p2p.DiscTooManyPeers } } - remoteAddr := peer.Peer.Info().Network.RemoteAddress + remoteAddr := peerInfo.Network.RemoteAddress indexIp := strings.LastIndex(remoteAddr, ":") if indexIp == -1 { // there could be no IP address, such as a pipe peer.Log().Debug("runEthPeer", "no ip address, remoteAddress", remoteAddr) - } else { + } else if !peerInfo.Network.Trusted { remoteIp := remoteAddr[:indexIp] if num, ok := h.peersPerIp[remoteIp]; ok && num >= h.maxPeersPerIp { peer.Log().Info("The IP has too many peers", "ip", remoteIp, "maxPeersPerIp", h.maxPeersPerIp, - "name", peer.Peer.Info().Name, "Enode", peer.Peer.Info().Enode) + "name", peerInfo.Name, "Enode", peerInfo.Enode) return p2p.DiscTooManyPeers } @@ -647,17 +648,22 @@ func (h *handler) unregisterPeer(id string) { logger.Error("Ethereum peer removal failed", "err", err) } - remoteAddr := peer.Peer.Info().Network.RemoteAddress + peerInfo := peer.Peer.Info() + remoteAddr := peerInfo.Network.RemoteAddress indexIp := strings.LastIndex(remoteAddr, ":") if indexIp == -1 { // there could be no IP address, such as a pipe - peer.Log().Debug("unregisterPeer", "name", peer.Peer.Info().Name, "no ip address, remoteAddress", remoteAddr) - } else { + peer.Log().Debug("unregisterPeer", "name", peerInfo.Name, "no ip address, remoteAddress", remoteAddr) + } else if !peerInfo.Network.Trusted { remoteIp := remoteAddr[:indexIp] - h.peersPerIp[remoteIp] = h.peersPerIp[remoteIp] - 1 - logger.Debug("unregisterPeer", "name", peer.Peer.Info().Name, "connectNum", h.peersPerIp[remoteIp]) - if h.peersPerIp[remoteIp] == 0 { - delete(h.peersPerIp, remoteIp) + if h.peersPerIp[remoteIp] <= 0 { + peer.Log().Error("unregisterPeer without record", "name", peerInfo.Name, "remoteAddress", remoteAddr) + } else { + h.peersPerIp[remoteIp] = h.peersPerIp[remoteIp] - 1 + logger.Debug("unregisterPeer", "name", peerInfo.Name, "connectNum", h.peersPerIp[remoteIp]) + if h.peersPerIp[remoteIp] == 0 { + delete(h.peersPerIp, remoteIp) + } } } } diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 942b30fd46..a0cf06b5c4 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -944,7 +944,7 @@ func TestOptionMaxPeersPerIp(t *testing.T) { uniPort = 1000 ) - tryFunc := func(tryNum int, ip1 string, ip2 string, doneCh chan struct{}) { + tryFunc := func(tryNum int, ip1 string, ip2 string, trust bool, doneCh chan struct{}) { // Create a source peer to send messages through and a sink handler to receive them p2pSrc, p2pSink := p2p.MsgPipe() defer p2pSrc.Close() @@ -954,6 +954,9 @@ func TestOptionMaxPeersPerIp(t *testing.T) { peer1.UpdateTestRemoteAddr(ip1 + strconv.Itoa(uniPort)) peer2 := p2p.NewPeerPipe(enode.ID{byte(uniPort)}, "", nil, p2pSink) peer2.UpdateTestRemoteAddr(ip2 + strconv.Itoa(uniPort)) + if trust { + peer2.UpdateTrustFlagTest() + } uniPort++ src := eth.NewPeer(eth.ETH66, peer1, p2pSrc, handler.txpool) @@ -970,17 +973,22 @@ func TestOptionMaxPeersPerIp(t *testing.T) { }) // err is nil, connection ok and it is closed by the doneCh if err == nil { - // if num > maxPeersPerIp, then err should be p2p.DiscTooManyPeers - if num > maxPeersPerIp { - t.Errorf("current num is %d, maxPeersPerIp is %d, should failed", num, maxPeersPerIp) + if trust || num <= maxPeersPerIp { + return } + // if num > maxPeersPerIp and not trust, should report: p2p.DiscTooManyPeers + t.Errorf("current num is %d, maxPeersPerIp is %d, should failed", num, maxPeersPerIp) return } wg.Done() + if trust { + t.Errorf("trust node should not failed, num is %d, maxPeersPerIp is %d, but failed:%s", num, maxPeersPerIp, err) + } // err should be p2p.DiscTooManyPeers and num > maxPeersPerIp if err == p2p.DiscTooManyPeers && num > maxPeersPerIp { return } + t.Errorf("current num is %d, maxPeersPerIp is %d, but failed:%s", num, maxPeersPerIp, err) }(tryNum) @@ -994,28 +1002,36 @@ func TestOptionMaxPeersPerIp(t *testing.T) { // case 1: normal case doneCh1 := make(chan struct{}) for tryNum := 1; tryNum <= 4; tryNum++ { - tryFunc(tryNum, "1.2.3.11:", "1.2.3.22:", doneCh1) + tryFunc(tryNum, "1.2.3.11:", "1.2.3.22:", false, doneCh1) } close(doneCh1) // case 2: once the previous connection was unregisterred, new connections with same IP can be accepted. doneCh2 := make(chan struct{}) for tryNum := 1; tryNum <= 4; tryNum++ { - tryFunc(tryNum, "1.2.3.11:", "1.2.3.22:", doneCh2) + tryFunc(tryNum, "1.2.3.11:", "1.2.3.22:", false, doneCh2) } close(doneCh2) // case 3: ipv6 address, like: [2001:db8::1]:80 doneCh3 := make(chan struct{}) for tryNum := 1; tryNum <= 4; tryNum++ { - tryFunc(tryNum, "[2001:db8::11]:", "[2001:db8::22]:", doneCh3) + tryFunc(tryNum, "[2001:db8::11]:", "[2001:db8::22]:", false, doneCh3) } close(doneCh3) // case 4: same as case 2, but for ipv6 doneCh4 := make(chan struct{}) for tryNum := 1; tryNum <= 4; tryNum++ { - tryFunc(tryNum, "[2001:db8::11]:", "[2001:db8::22]:", doneCh4) + tryFunc(tryNum, "[2001:db8::11]:", "[2001:db8::22]:", false, doneCh4) } close(doneCh4) + + // case 5: test trust node + doneCh5 := make(chan struct{}) + for tryNum := 1; tryNum <= 4; tryNum++ { + tryFunc(tryNum, "[2001:db8::11]:", "[2001:db8::22]:", true, doneCh5) + } + close(doneCh5) + } diff --git a/p2p/peer.go b/p2p/peer.go index 978323c09d..cfebfdcdd9 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -213,10 +213,14 @@ func (p *Peer) RemoteAddr() net.Addr { return p.rw.fd.RemoteAddr() } -func (p *Peer) UpdateTestRemoteAddr(addr string) { +func (p *Peer) UpdateTestRemoteAddr(addr string) { // test purpose only p.testRemoteAddr = addr } +func (p *Peer) UpdateTrustFlagTest() { // test purpose only + p.rw.set(trustedConn, true) +} + // LocalAddr returns the local address of the network connection. func (p *Peer) LocalAddr() net.Addr { return p.rw.fd.LocalAddr()