github.com/ethereum/go-ethereum@v1.16.1/p2p/netutil/iptrack_test.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package netutil 18 19 import ( 20 crand "crypto/rand" 21 "fmt" 22 "net/netip" 23 "testing" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common/mclock" 27 ) 28 29 const ( 30 opStatement = iota 31 opContact 32 opPredict 33 opCheckFullCone 34 ) 35 36 type iptrackTestEvent struct { 37 op int 38 time int // absolute, in milliseconds 39 ip, from string 40 } 41 42 func TestIPTracker(t *testing.T) { 43 tests := map[string][]iptrackTestEvent{ 44 "minStatements": { 45 {opPredict, 0, "", ""}, 46 {opStatement, 0, "127.0.0.1:8000", "127.0.0.2"}, 47 {opPredict, 1000, "", ""}, 48 {opStatement, 1000, "127.0.0.1:8000", "127.0.0.3"}, 49 {opPredict, 1000, "", ""}, 50 {opStatement, 1000, "127.0.0.1:8000", "127.0.0.4"}, 51 {opPredict, 1000, "127.0.0.1:8000", ""}, 52 }, 53 "window": { 54 {opStatement, 0, "127.0.0.1:8000", "127.0.0.2"}, 55 {opStatement, 2000, "127.0.0.1:8000", "127.0.0.3"}, 56 {opStatement, 3000, "127.0.0.1:8000", "127.0.0.4"}, 57 {opPredict, 10000, "127.0.0.1:8000", ""}, 58 {opPredict, 10001, "", ""}, // first statement expired 59 {opStatement, 10100, "127.0.0.1:8000", "127.0.0.2"}, 60 {opPredict, 10200, "127.0.0.1:8000", ""}, 61 }, 62 "fullcone": { 63 {opContact, 0, "", "127.0.0.2"}, 64 {opStatement, 10, "127.0.0.1:8000", "127.0.0.2"}, 65 {opContact, 2000, "", "127.0.0.3"}, 66 {opStatement, 2010, "127.0.0.1:8000", "127.0.0.3"}, 67 {opContact, 3000, "", "127.0.0.4"}, 68 {opStatement, 3010, "127.0.0.1:8000", "127.0.0.4"}, 69 {opCheckFullCone, 3500, "false", ""}, 70 }, 71 "fullcone_2": { 72 {opContact, 0, "", "127.0.0.2"}, 73 {opStatement, 10, "127.0.0.1:8000", "127.0.0.2"}, 74 {opContact, 2000, "", "127.0.0.3"}, 75 {opStatement, 2010, "127.0.0.1:8000", "127.0.0.3"}, 76 {opStatement, 3000, "127.0.0.1:8000", "127.0.0.4"}, 77 {opContact, 3010, "", "127.0.0.4"}, 78 {opCheckFullCone, 3500, "true", ""}, 79 }, 80 } 81 for name, test := range tests { 82 t.Run(name, func(t *testing.T) { runIPTrackerTest(t, test) }) 83 } 84 } 85 86 func runIPTrackerTest(t *testing.T, evs []iptrackTestEvent) { 87 var ( 88 clock mclock.Simulated 89 it = NewIPTracker(10*time.Second, 10*time.Second, 3) 90 ) 91 it.clock = &clock 92 for i, ev := range evs { 93 evtime := time.Duration(ev.time) * time.Millisecond 94 clock.Run(evtime - time.Duration(clock.Now())) 95 switch ev.op { 96 case opStatement: 97 it.AddStatement(netip.MustParseAddr(ev.from), netip.MustParseAddrPort(ev.ip)) 98 case opContact: 99 it.AddContact(netip.MustParseAddr(ev.from)) 100 case opPredict: 101 pred := it.PredictEndpoint() 102 if ev.ip == "" { 103 if pred.IsValid() { 104 t.Errorf("op %d: wrong prediction %v, expected invalid", i, pred) 105 } 106 } else { 107 if pred != netip.MustParseAddrPort(ev.ip) { 108 t.Errorf("op %d: wrong prediction %v, want %q", i, pred, ev.ip) 109 } 110 } 111 case opCheckFullCone: 112 pred := fmt.Sprintf("%t", it.PredictFullConeNAT()) 113 if pred != ev.ip { 114 t.Errorf("op %d: wrong prediction %s, want %s", i, pred, ev.ip) 115 } 116 } 117 } 118 } 119 120 // This checks that old statements and contacts are GCed even if Predict* isn't called. 121 func TestIPTrackerForceGC(t *testing.T) { 122 var ( 123 clock mclock.Simulated 124 window = 10 * time.Second 125 rate = 50 * time.Millisecond 126 max = int(window/rate) + 1 127 it = NewIPTracker(window, window, 3) 128 ) 129 it.clock = &clock 130 131 for i := 0; i < 5*max; i++ { 132 var e1, e2 [4]byte 133 crand.Read(e1[:]) 134 crand.Read(e2[:]) 135 it.AddStatement(netip.AddrFrom4(e1), netip.AddrPortFrom(netip.AddrFrom4(e2), 9000)) 136 it.AddContact(netip.AddrFrom4(e1)) 137 clock.Run(rate) 138 } 139 if len(it.contact) > 2*max { 140 t.Errorf("contacts not GCed, have %d", len(it.contact)) 141 } 142 if len(it.statements) > 2*max { 143 t.Errorf("statements not GCed, have %d", len(it.statements)) 144 } 145 }