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  }