github.com/isti4github/eth-ecc@v0.0.0-20201227085832-c337f2d99319/p2p/discover/table_util_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 discover 18 19 import ( 20 "crypto/ecdsa" 21 "encoding/hex" 22 "fmt" 23 "math/rand" 24 "net" 25 "sort" 26 "sync" 27 28 "github.com/Onther-Tech/go-ethereum/crypto" 29 "github.com/Onther-Tech/go-ethereum/log" 30 "github.com/Onther-Tech/go-ethereum/p2p/enode" 31 "github.com/Onther-Tech/go-ethereum/p2p/enr" 32 ) 33 34 var nullNode *enode.Node 35 36 func init() { 37 var r enr.Record 38 r.Set(enr.IP{0, 0, 0, 0}) 39 nullNode = enode.SignNull(&r, enode.ID{}) 40 } 41 42 func newTestTable(t transport) (*Table, *enode.DB) { 43 db, _ := enode.OpenDB("") 44 tab, _ := newTable(t, db, nil, log.Root()) 45 go tab.loop() 46 return tab, db 47 } 48 49 // nodeAtDistance creates a node for which enode.LogDist(base, n.id) == ld. 50 func nodeAtDistance(base enode.ID, ld int, ip net.IP) *node { 51 var r enr.Record 52 r.Set(enr.IP(ip)) 53 return wrapNode(enode.SignNull(&r, idAtDistance(base, ld))) 54 } 55 56 // idAtDistance returns a random hash such that enode.LogDist(a, b) == n 57 func idAtDistance(a enode.ID, n int) (b enode.ID) { 58 if n == 0 { 59 return a 60 } 61 // flip bit at position n, fill the rest with random bits 62 b = a 63 pos := len(a) - n/8 - 1 64 bit := byte(0x01) << (byte(n%8) - 1) 65 if bit == 0 { 66 pos++ 67 bit = 0x80 68 } 69 b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits 70 for i := pos + 1; i < len(a); i++ { 71 b[i] = byte(rand.Intn(255)) 72 } 73 return b 74 } 75 76 func intIP(i int) net.IP { 77 return net.IP{byte(i), 0, 2, byte(i)} 78 } 79 80 // fillBucket inserts nodes into the given bucket until it is full. 81 func fillBucket(tab *Table, n *node) (last *node) { 82 ld := enode.LogDist(tab.self().ID(), n.ID()) 83 b := tab.bucket(n.ID()) 84 for len(b.entries) < bucketSize { 85 b.entries = append(b.entries, nodeAtDistance(tab.self().ID(), ld, intIP(ld))) 86 } 87 return b.entries[bucketSize-1] 88 } 89 90 // fillTable adds nodes the table to the end of their corresponding bucket 91 // if the bucket is not full. The caller must not hold tab.mutex. 92 func fillTable(tab *Table, nodes []*node) { 93 for _, n := range nodes { 94 tab.addSeenNode(n) 95 } 96 } 97 98 type pingRecorder struct { 99 mu sync.Mutex 100 dead, pinged map[enode.ID]bool 101 records map[enode.ID]*enode.Node 102 n *enode.Node 103 } 104 105 func newPingRecorder() *pingRecorder { 106 var r enr.Record 107 r.Set(enr.IP{0, 0, 0, 0}) 108 n := enode.SignNull(&r, enode.ID{}) 109 110 return &pingRecorder{ 111 dead: make(map[enode.ID]bool), 112 pinged: make(map[enode.ID]bool), 113 records: make(map[enode.ID]*enode.Node), 114 n: n, 115 } 116 } 117 118 // setRecord updates a node record. Future calls to ping and 119 // requestENR will return this record. 120 func (t *pingRecorder) updateRecord(n *enode.Node) { 121 t.mu.Lock() 122 defer t.mu.Unlock() 123 t.records[n.ID()] = n 124 } 125 126 // Stubs to satisfy the transport interface. 127 func (t *pingRecorder) Self() *enode.Node { return nullNode } 128 func (t *pingRecorder) lookupSelf() []*enode.Node { return nil } 129 func (t *pingRecorder) lookupRandom() []*enode.Node { return nil } 130 func (t *pingRecorder) close() {} 131 132 // ping simulates a ping request. 133 func (t *pingRecorder) ping(n *enode.Node) (seq uint64, err error) { 134 t.mu.Lock() 135 defer t.mu.Unlock() 136 137 t.pinged[n.ID()] = true 138 if t.dead[n.ID()] { 139 return 0, errTimeout 140 } 141 if t.records[n.ID()] != nil { 142 seq = t.records[n.ID()].Seq() 143 } 144 return seq, nil 145 } 146 147 // requestENR simulates an ENR request. 148 func (t *pingRecorder) RequestENR(n *enode.Node) (*enode.Node, error) { 149 t.mu.Lock() 150 defer t.mu.Unlock() 151 152 if t.dead[n.ID()] || t.records[n.ID()] == nil { 153 return nil, errTimeout 154 } 155 return t.records[n.ID()], nil 156 } 157 158 func hasDuplicates(slice []*node) bool { 159 seen := make(map[enode.ID]bool) 160 for i, e := range slice { 161 if e == nil { 162 panic(fmt.Sprintf("nil *Node at %d", i)) 163 } 164 if seen[e.ID()] { 165 return true 166 } 167 seen[e.ID()] = true 168 } 169 return false 170 } 171 172 func sortedByDistanceTo(distbase enode.ID, slice []*node) bool { 173 return sort.SliceIsSorted(slice, func(i, j int) bool { 174 return enode.DistCmp(distbase, slice[i].ID(), slice[j].ID()) < 0 175 }) 176 } 177 178 func hexEncPrivkey(h string) *ecdsa.PrivateKey { 179 b, err := hex.DecodeString(h) 180 if err != nil { 181 panic(err) 182 } 183 key, err := crypto.ToECDSA(b) 184 if err != nil { 185 panic(err) 186 } 187 return key 188 } 189 190 func hexEncPubkey(h string) (ret encPubkey) { 191 b, err := hex.DecodeString(h) 192 if err != nil { 193 panic(err) 194 } 195 if len(b) != len(ret) { 196 panic("invalid length") 197 } 198 copy(ret[:], b) 199 return ret 200 }