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