| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | // Copyright 2018 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package enode | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"crypto/ecdsa" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"net" | 
					
						
							|  |  |  | 	"reflect" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"sync/atomic" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/p2p/enr" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/p2p/netutil" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	// IP tracker configuration | 
					
						
							|  |  |  | 	iptrackMinStatements = 10 | 
					
						
							|  |  |  | 	iptrackWindow        = 5 * time.Minute | 
					
						
							|  |  |  | 	iptrackContactWindow = 10 * time.Minute | 
					
						
							| 
									
										
										
										
											2021-09-07 13:36:48 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// time needed to wait between two updates to the local ENR | 
					
						
							|  |  |  | 	recordUpdateThrottle = time.Millisecond | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // LocalNode produces the signed node record of a local node, i.e. a node run in the | 
					
						
							|  |  |  | // current process. Setting ENR entries via the Set method updates the record. A new version | 
					
						
							|  |  |  | // of the record is signed on demand when the Node method is called. | 
					
						
							|  |  |  | type LocalNode struct { | 
					
						
							| 
									
										
										
										
											2021-09-07 13:36:48 +03:00
										 |  |  | 	cur atomic.Value // holds a non-nil node pointer while the record is up-to-date | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	id  ID | 
					
						
							|  |  |  | 	key *ecdsa.PrivateKey | 
					
						
							|  |  |  | 	db  *DB | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// everything below is protected by a lock | 
					
						
							| 
									
										
										
										
											2021-09-07 13:36:48 +03:00
										 |  |  | 	mu        sync.RWMutex | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | 	seq       uint64 | 
					
						
							| 
									
										
										
										
											2021-09-07 13:36:48 +03:00
										 |  |  | 	update    time.Time // timestamp when the record was last updated | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | 	entries   map[string]enr.Entry | 
					
						
							|  |  |  | 	endpoint4 lnEndpoint | 
					
						
							|  |  |  | 	endpoint6 lnEndpoint | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type lnEndpoint struct { | 
					
						
							|  |  |  | 	track                *netutil.IPTracker | 
					
						
							|  |  |  | 	staticIP, fallbackIP net.IP | 
					
						
							|  |  |  | 	fallbackUDP          int | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewLocalNode creates a local node. | 
					
						
							|  |  |  | func NewLocalNode(db *DB, key *ecdsa.PrivateKey) *LocalNode { | 
					
						
							|  |  |  | 	ln := &LocalNode{ | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | 		id:      PubkeyToIDV4(&key.PublicKey), | 
					
						
							|  |  |  | 		db:      db, | 
					
						
							|  |  |  | 		key:     key, | 
					
						
							|  |  |  | 		entries: make(map[string]enr.Entry), | 
					
						
							|  |  |  | 		endpoint4: lnEndpoint{ | 
					
						
							|  |  |  | 			track: netutil.NewIPTracker(iptrackWindow, iptrackContactWindow, iptrackMinStatements), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		endpoint6: lnEndpoint{ | 
					
						
							|  |  |  | 			track: netutil.NewIPTracker(iptrackWindow, iptrackContactWindow, iptrackMinStatements), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	ln.seq = db.localSeq(ln.id) | 
					
						
							| 
									
										
										
										
											2021-09-07 13:36:48 +03:00
										 |  |  | 	ln.update = time.Now() | 
					
						
							|  |  |  | 	ln.cur.Store((*Node)(nil)) | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	return ln | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Database returns the node database associated with the local node. | 
					
						
							|  |  |  | func (ln *LocalNode) Database() *DB { | 
					
						
							|  |  |  | 	return ln.db | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Node returns the current version of the local node record. | 
					
						
							|  |  |  | func (ln *LocalNode) Node() *Node { | 
					
						
							| 
									
										
										
										
											2021-09-07 13:36:48 +03:00
										 |  |  | 	// If we have a valid record, return that | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	n := ln.cur.Load().(*Node) | 
					
						
							|  |  |  | 	if n != nil { | 
					
						
							|  |  |  | 		return n | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-09-07 13:36:48 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	// Record was invalidated, sign a new copy. | 
					
						
							|  |  |  | 	ln.mu.Lock() | 
					
						
							|  |  |  | 	defer ln.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2021-09-07 13:36:48 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Double check the current record, since multiple goroutines might be waiting | 
					
						
							|  |  |  | 	// on the write mutex. | 
					
						
							|  |  |  | 	if n = ln.cur.Load().(*Node); n != nil { | 
					
						
							|  |  |  | 		return n | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The initial sequence number is the current timestamp in milliseconds. To ensure | 
					
						
							|  |  |  | 	// that the initial sequence number will always be higher than any previous sequence | 
					
						
							|  |  |  | 	// number (assuming the clock is correct), we want to avoid updating the record faster | 
					
						
							|  |  |  | 	// than once per ms. So we need to sleep here until the next possible update time has | 
					
						
							|  |  |  | 	// arrived. | 
					
						
							|  |  |  | 	lastChange := time.Since(ln.update) | 
					
						
							|  |  |  | 	if lastChange < recordUpdateThrottle { | 
					
						
							|  |  |  | 		time.Sleep(recordUpdateThrottle - lastChange) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	ln.sign() | 
					
						
							| 
									
										
										
										
											2021-09-07 13:36:48 +03:00
										 |  |  | 	ln.update = time.Now() | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	return ln.cur.Load().(*Node) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | // Seq returns the current sequence number of the local node record. | 
					
						
							|  |  |  | func (ln *LocalNode) Seq() uint64 { | 
					
						
							|  |  |  | 	ln.mu.Lock() | 
					
						
							|  |  |  | 	defer ln.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ln.seq | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | // ID returns the local node ID. | 
					
						
							|  |  |  | func (ln *LocalNode) ID() ID { | 
					
						
							|  |  |  | 	return ln.id | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | // Set puts the given entry into the local record, overwriting any existing value. | 
					
						
							|  |  |  | // Use Set*IP and SetFallbackUDP to set IP addresses and UDP port, otherwise they'll | 
					
						
							|  |  |  | // be overwritten by the endpoint predictor. | 
					
						
							| 
									
										
										
										
											2021-09-07 13:36:48 +03:00
										 |  |  | // | 
					
						
							|  |  |  | // Since node record updates are throttled to one per second, Set is asynchronous. | 
					
						
							|  |  |  | // Any update will be queued up and published when at least one second passes from | 
					
						
							|  |  |  | // the last change. | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | func (ln *LocalNode) Set(e enr.Entry) { | 
					
						
							|  |  |  | 	ln.mu.Lock() | 
					
						
							|  |  |  | 	defer ln.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ln.set(e) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ln *LocalNode) set(e enr.Entry) { | 
					
						
							|  |  |  | 	val, exists := ln.entries[e.ENRKey()] | 
					
						
							|  |  |  | 	if !exists || !reflect.DeepEqual(val, e) { | 
					
						
							|  |  |  | 		ln.entries[e.ENRKey()] = e | 
					
						
							|  |  |  | 		ln.invalidate() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Delete removes the given entry from the local record. | 
					
						
							|  |  |  | func (ln *LocalNode) Delete(e enr.Entry) { | 
					
						
							|  |  |  | 	ln.mu.Lock() | 
					
						
							|  |  |  | 	defer ln.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ln.delete(e) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ln *LocalNode) delete(e enr.Entry) { | 
					
						
							|  |  |  | 	_, exists := ln.entries[e.ENRKey()] | 
					
						
							|  |  |  | 	if exists { | 
					
						
							|  |  |  | 		delete(ln.entries, e.ENRKey()) | 
					
						
							|  |  |  | 		ln.invalidate() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | func (ln *LocalNode) endpointForIP(ip net.IP) *lnEndpoint { | 
					
						
							|  |  |  | 	if ip.To4() != nil { | 
					
						
							|  |  |  | 		return &ln.endpoint4 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return &ln.endpoint6 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | // SetStaticIP sets the local IP to the given one unconditionally. | 
					
						
							|  |  |  | // This disables endpoint prediction. | 
					
						
							|  |  |  | func (ln *LocalNode) SetStaticIP(ip net.IP) { | 
					
						
							|  |  |  | 	ln.mu.Lock() | 
					
						
							|  |  |  | 	defer ln.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | 	ln.endpointForIP(ip).staticIP = ip | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	ln.updateEndpoints() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetFallbackIP sets the last-resort IP address. This address is used | 
					
						
							|  |  |  | // if no endpoint prediction can be made and no static IP is set. | 
					
						
							|  |  |  | func (ln *LocalNode) SetFallbackIP(ip net.IP) { | 
					
						
							|  |  |  | 	ln.mu.Lock() | 
					
						
							|  |  |  | 	defer ln.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | 	ln.endpointForIP(ip).fallbackIP = ip | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	ln.updateEndpoints() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | // SetFallbackUDP sets the last-resort UDP-on-IPv4 port. This port is used | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | // if no endpoint prediction can be made. | 
					
						
							|  |  |  | func (ln *LocalNode) SetFallbackUDP(port int) { | 
					
						
							|  |  |  | 	ln.mu.Lock() | 
					
						
							|  |  |  | 	defer ln.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | 	ln.endpoint4.fallbackUDP = port | 
					
						
							|  |  |  | 	ln.endpoint6.fallbackUDP = port | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	ln.updateEndpoints() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // UDPEndpointStatement should be called whenever a statement about the local node's | 
					
						
							|  |  |  | // UDP endpoint is received. It feeds the local endpoint predictor. | 
					
						
							|  |  |  | func (ln *LocalNode) UDPEndpointStatement(fromaddr, endpoint *net.UDPAddr) { | 
					
						
							|  |  |  | 	ln.mu.Lock() | 
					
						
							|  |  |  | 	defer ln.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | 	ln.endpointForIP(endpoint.IP).track.AddStatement(fromaddr.String(), endpoint.String()) | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	ln.updateEndpoints() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // UDPContact should be called whenever the local node has announced itself to another node | 
					
						
							|  |  |  | // via UDP. It feeds the local endpoint predictor. | 
					
						
							|  |  |  | func (ln *LocalNode) UDPContact(toaddr *net.UDPAddr) { | 
					
						
							|  |  |  | 	ln.mu.Lock() | 
					
						
							|  |  |  | 	defer ln.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | 	ln.endpointForIP(toaddr.IP).track.AddContact(toaddr.String()) | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	ln.updateEndpoints() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | // updateEndpoints updates the record with predicted endpoints. | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | func (ln *LocalNode) updateEndpoints() { | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | 	ip4, udp4 := ln.endpoint4.get() | 
					
						
							|  |  |  | 	ip6, udp6 := ln.endpoint6.get() | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | 	if ip4 != nil && !ip4.IsUnspecified() { | 
					
						
							|  |  |  | 		ln.set(enr.IPv4(ip4)) | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | 		ln.delete(enr.IPv4{}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if ip6 != nil && !ip6.IsUnspecified() { | 
					
						
							|  |  |  | 		ln.set(enr.IPv6(ip6)) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ln.delete(enr.IPv6{}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if udp4 != 0 { | 
					
						
							|  |  |  | 		ln.set(enr.UDP(udp4)) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ln.delete(enr.UDP(0)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if udp6 != 0 && udp6 != udp4 { | 
					
						
							|  |  |  | 		ln.set(enr.UDP6(udp6)) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ln.delete(enr.UDP6(0)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // get returns the endpoint with highest precedence. | 
					
						
							|  |  |  | func (e *lnEndpoint) get() (newIP net.IP, newPort int) { | 
					
						
							|  |  |  | 	newPort = e.fallbackUDP | 
					
						
							|  |  |  | 	if e.fallbackIP != nil { | 
					
						
							|  |  |  | 		newIP = e.fallbackIP | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if e.staticIP != nil { | 
					
						
							|  |  |  | 		newIP = e.staticIP | 
					
						
							|  |  |  | 	} else if ip, port := predictAddr(e.track); ip != nil { | 
					
						
							|  |  |  | 		newIP = ip | 
					
						
							|  |  |  | 		newPort = port | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-07 15:31:00 +02:00
										 |  |  | 	return newIP, newPort | 
					
						
							| 
									
										
										
										
											2018-10-12 11:47:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // predictAddr wraps IPTracker.PredictEndpoint, converting from its string-based | 
					
						
							|  |  |  | // endpoint representation to IP and port types. | 
					
						
							|  |  |  | func predictAddr(t *netutil.IPTracker) (net.IP, int) { | 
					
						
							|  |  |  | 	ep := t.PredictEndpoint() | 
					
						
							|  |  |  | 	if ep == "" { | 
					
						
							|  |  |  | 		return nil, 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ipString, portString, _ := net.SplitHostPort(ep) | 
					
						
							|  |  |  | 	ip := net.ParseIP(ipString) | 
					
						
							|  |  |  | 	port, _ := strconv.Atoi(portString) | 
					
						
							|  |  |  | 	return ip, port | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ln *LocalNode) invalidate() { | 
					
						
							|  |  |  | 	ln.cur.Store((*Node)(nil)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ln *LocalNode) sign() { | 
					
						
							|  |  |  | 	if n := ln.cur.Load().(*Node); n != nil { | 
					
						
							|  |  |  | 		return // no changes | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var r enr.Record | 
					
						
							|  |  |  | 	for _, e := range ln.entries { | 
					
						
							|  |  |  | 		r.Set(e) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ln.bumpSeq() | 
					
						
							|  |  |  | 	r.SetSeq(ln.seq) | 
					
						
							|  |  |  | 	if err := SignV4(&r, ln.key); err != nil { | 
					
						
							|  |  |  | 		panic(fmt.Errorf("enode: can't sign record: %v", err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	n, err := New(ValidSchemes, &r) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic(fmt.Errorf("enode: can't verify local record: %v", err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ln.cur.Store(n) | 
					
						
							|  |  |  | 	log.Info("New local node record", "seq", ln.seq, "id", n.ID(), "ip", n.IP(), "udp", n.UDP(), "tcp", n.TCP()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ln *LocalNode) bumpSeq() { | 
					
						
							|  |  |  | 	ln.seq++ | 
					
						
							|  |  |  | 	ln.db.storeLocalSeq(ln.id, ln.seq) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-09-07 13:36:48 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | // nowMilliseconds gives the current timestamp at millisecond precision. | 
					
						
							|  |  |  | func nowMilliseconds() uint64 { | 
					
						
							|  |  |  | 	ns := time.Now().UnixNano() | 
					
						
							|  |  |  | 	if ns < 0 { | 
					
						
							|  |  |  | 		return 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return uint64(ns / 1000 / 1000) | 
					
						
							|  |  |  | } |