github.com/theQRL/go-zond@v0.1.1/p2p/enode/localnode.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 enode 18 19 import ( 20 "crypto/ecdsa" 21 "fmt" 22 "net" 23 "reflect" 24 "strconv" 25 "sync" 26 "sync/atomic" 27 "time" 28 29 "github.com/theQRL/go-zond/log" 30 "github.com/theQRL/go-zond/p2p/enr" 31 "github.com/theQRL/go-zond/p2p/netutil" 32 ) 33 34 const ( 35 // IP tracker configuration 36 iptrackMinStatements = 10 37 iptrackWindow = 5 * time.Minute 38 iptrackContactWindow = 10 * time.Minute 39 40 // time needed to wait between two updates to the local ENR 41 recordUpdateThrottle = time.Millisecond 42 ) 43 44 // LocalNode produces the signed node record of a local node, i.e. a node run in the 45 // current process. Setting ENR entries via the Set method updates the record. A new version 46 // of the record is signed on demand when the Node method is called. 47 type LocalNode struct { 48 cur atomic.Value // holds a non-nil node pointer while the record is up-to-date 49 50 id ID 51 key *ecdsa.PrivateKey 52 db *DB 53 54 // everything below is protected by a lock 55 mu sync.RWMutex 56 seq uint64 57 update time.Time // timestamp when the record was last updated 58 entries map[string]enr.Entry 59 endpoint4 lnEndpoint 60 endpoint6 lnEndpoint 61 } 62 63 type lnEndpoint struct { 64 track *netutil.IPTracker 65 staticIP, fallbackIP net.IP 66 fallbackUDP uint16 // port 67 } 68 69 // NewLocalNode creates a local node. 70 func NewLocalNode(db *DB, key *ecdsa.PrivateKey) *LocalNode { 71 ln := &LocalNode{ 72 id: PubkeyToIDV4(&key.PublicKey), 73 db: db, 74 key: key, 75 entries: make(map[string]enr.Entry), 76 endpoint4: lnEndpoint{ 77 track: netutil.NewIPTracker(iptrackWindow, iptrackContactWindow, iptrackMinStatements), 78 }, 79 endpoint6: lnEndpoint{ 80 track: netutil.NewIPTracker(iptrackWindow, iptrackContactWindow, iptrackMinStatements), 81 }, 82 } 83 ln.seq = db.localSeq(ln.id) 84 ln.update = time.Now() 85 ln.cur.Store((*Node)(nil)) 86 return ln 87 } 88 89 // Database returns the node database associated with the local node. 90 func (ln *LocalNode) Database() *DB { 91 return ln.db 92 } 93 94 // Node returns the current version of the local node record. 95 func (ln *LocalNode) Node() *Node { 96 // If we have a valid record, return that 97 n := ln.cur.Load().(*Node) 98 if n != nil { 99 return n 100 } 101 102 // Record was invalidated, sign a new copy. 103 ln.mu.Lock() 104 defer ln.mu.Unlock() 105 106 // Double check the current record, since multiple goroutines might be waiting 107 // on the write mutex. 108 if n = ln.cur.Load().(*Node); n != nil { 109 return n 110 } 111 112 // The initial sequence number is the current timestamp in milliseconds. To ensure 113 // that the initial sequence number will always be higher than any previous sequence 114 // number (assuming the clock is correct), we want to avoid updating the record faster 115 // than once per ms. So we need to sleep here until the next possible update time has 116 // arrived. 117 lastChange := time.Since(ln.update) 118 if lastChange < recordUpdateThrottle { 119 time.Sleep(recordUpdateThrottle - lastChange) 120 } 121 122 ln.sign() 123 ln.update = time.Now() 124 return ln.cur.Load().(*Node) 125 } 126 127 // Seq returns the current sequence number of the local node record. 128 func (ln *LocalNode) Seq() uint64 { 129 ln.mu.Lock() 130 defer ln.mu.Unlock() 131 132 return ln.seq 133 } 134 135 // ID returns the local node ID. 136 func (ln *LocalNode) ID() ID { 137 return ln.id 138 } 139 140 // Set puts the given entry into the local record, overwriting any existing value. 141 // Use Set*IP and SetFallbackUDP to set IP addresses and UDP port, otherwise they'll 142 // be overwritten by the endpoint predictor. 143 // 144 // Since node record updates are throttled to one per second, Set is asynchronous. 145 // Any update will be queued up and published when at least one second passes from 146 // the last change. 147 func (ln *LocalNode) Set(e enr.Entry) { 148 ln.mu.Lock() 149 defer ln.mu.Unlock() 150 151 ln.set(e) 152 } 153 154 func (ln *LocalNode) set(e enr.Entry) { 155 val, exists := ln.entries[e.ENRKey()] 156 if !exists || !reflect.DeepEqual(val, e) { 157 ln.entries[e.ENRKey()] = e 158 ln.invalidate() 159 } 160 } 161 162 // Delete removes the given entry from the local record. 163 func (ln *LocalNode) Delete(e enr.Entry) { 164 ln.mu.Lock() 165 defer ln.mu.Unlock() 166 167 ln.delete(e) 168 } 169 170 func (ln *LocalNode) delete(e enr.Entry) { 171 _, exists := ln.entries[e.ENRKey()] 172 if exists { 173 delete(ln.entries, e.ENRKey()) 174 ln.invalidate() 175 } 176 } 177 178 func (ln *LocalNode) endpointForIP(ip net.IP) *lnEndpoint { 179 if ip.To4() != nil { 180 return &ln.endpoint4 181 } 182 return &ln.endpoint6 183 } 184 185 // SetStaticIP sets the local IP to the given one unconditionally. 186 // This disables endpoint prediction. 187 func (ln *LocalNode) SetStaticIP(ip net.IP) { 188 ln.mu.Lock() 189 defer ln.mu.Unlock() 190 191 ln.endpointForIP(ip).staticIP = ip 192 ln.updateEndpoints() 193 } 194 195 // SetFallbackIP sets the last-resort IP address. This address is used 196 // if no endpoint prediction can be made and no static IP is set. 197 func (ln *LocalNode) SetFallbackIP(ip net.IP) { 198 ln.mu.Lock() 199 defer ln.mu.Unlock() 200 201 ln.endpointForIP(ip).fallbackIP = ip 202 ln.updateEndpoints() 203 } 204 205 // SetFallbackUDP sets the last-resort UDP-on-IPv4 port. This port is used 206 // if no endpoint prediction can be made. 207 func (ln *LocalNode) SetFallbackUDP(port int) { 208 ln.mu.Lock() 209 defer ln.mu.Unlock() 210 211 ln.endpoint4.fallbackUDP = uint16(port) 212 ln.endpoint6.fallbackUDP = uint16(port) 213 ln.updateEndpoints() 214 } 215 216 // UDPEndpointStatement should be called whenever a statement about the local node's 217 // UDP endpoint is received. It feeds the local endpoint predictor. 218 func (ln *LocalNode) UDPEndpointStatement(fromaddr, endpoint *net.UDPAddr) { 219 ln.mu.Lock() 220 defer ln.mu.Unlock() 221 222 ln.endpointForIP(endpoint.IP).track.AddStatement(fromaddr.String(), endpoint.String()) 223 ln.updateEndpoints() 224 } 225 226 // UDPContact should be called whenever the local node has announced itself to another node 227 // via UDP. It feeds the local endpoint predictor. 228 func (ln *LocalNode) UDPContact(toaddr *net.UDPAddr) { 229 ln.mu.Lock() 230 defer ln.mu.Unlock() 231 232 ln.endpointForIP(toaddr.IP).track.AddContact(toaddr.String()) 233 ln.updateEndpoints() 234 } 235 236 // updateEndpoints updates the record with predicted endpoints. 237 func (ln *LocalNode) updateEndpoints() { 238 ip4, udp4 := ln.endpoint4.get() 239 ip6, udp6 := ln.endpoint6.get() 240 241 if ip4 != nil && !ip4.IsUnspecified() { 242 ln.set(enr.IPv4(ip4)) 243 } else { 244 ln.delete(enr.IPv4{}) 245 } 246 if ip6 != nil && !ip6.IsUnspecified() { 247 ln.set(enr.IPv6(ip6)) 248 } else { 249 ln.delete(enr.IPv6{}) 250 } 251 if udp4 != 0 { 252 ln.set(enr.UDP(udp4)) 253 } else { 254 ln.delete(enr.UDP(0)) 255 } 256 if udp6 != 0 && udp6 != udp4 { 257 ln.set(enr.UDP6(udp6)) 258 } else { 259 ln.delete(enr.UDP6(0)) 260 } 261 } 262 263 // get returns the endpoint with highest precedence. 264 func (e *lnEndpoint) get() (newIP net.IP, newPort uint16) { 265 newPort = e.fallbackUDP 266 if e.fallbackIP != nil { 267 newIP = e.fallbackIP 268 } 269 if e.staticIP != nil { 270 newIP = e.staticIP 271 } else if ip, port := predictAddr(e.track); ip != nil { 272 newIP = ip 273 newPort = port 274 } 275 return newIP, newPort 276 } 277 278 // predictAddr wraps IPTracker.PredictEndpoint, converting from its string-based 279 // endpoint representation to IP and port types. 280 func predictAddr(t *netutil.IPTracker) (net.IP, uint16) { 281 ep := t.PredictEndpoint() 282 if ep == "" { 283 return nil, 0 284 } 285 ipString, portString, _ := net.SplitHostPort(ep) 286 ip := net.ParseIP(ipString) 287 port, err := strconv.ParseUint(portString, 10, 16) 288 if err != nil { 289 return nil, 0 290 } 291 return ip, uint16(port) 292 } 293 294 func (ln *LocalNode) invalidate() { 295 ln.cur.Store((*Node)(nil)) 296 } 297 298 func (ln *LocalNode) sign() { 299 if n := ln.cur.Load().(*Node); n != nil { 300 return // no changes 301 } 302 303 var r enr.Record 304 for _, e := range ln.entries { 305 r.Set(e) 306 } 307 ln.bumpSeq() 308 r.SetSeq(ln.seq) 309 if err := SignV4(&r, ln.key); err != nil { 310 panic(fmt.Errorf("enode: can't sign record: %v", err)) 311 } 312 n, err := New(ValidSchemes, &r) 313 if err != nil { 314 panic(fmt.Errorf("enode: can't verify local record: %v", err)) 315 } 316 ln.cur.Store(n) 317 log.Info("New local node record", "seq", ln.seq, "id", n.ID(), "ip", n.IP(), "udp", n.UDP(), "tcp", n.TCP()) 318 } 319 320 func (ln *LocalNode) bumpSeq() { 321 ln.seq++ 322 ln.db.storeLocalSeq(ln.id, ln.seq) 323 } 324 325 // nowMilliseconds gives the current timestamp at millisecond precision. 326 func nowMilliseconds() uint64 { 327 ns := time.Now().UnixNano() 328 if ns < 0 { 329 return 0 330 } 331 return uint64(ns / 1000 / 1000) 332 }