github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/enode/localnode.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:41</date>
    10  //</624450104329244672>
    11  
    12  
    13  package enode
    14  
    15  import (
    16  	"crypto/ecdsa"
    17  	"fmt"
    18  	"net"
    19  	"reflect"
    20  	"strconv"
    21  	"sync"
    22  	"sync/atomic"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/log"
    26  	"github.com/ethereum/go-ethereum/p2p/enr"
    27  	"github.com/ethereum/go-ethereum/p2p/netutil"
    28  )
    29  
    30  const (
    31  //IP跟踪器配置
    32  	iptrackMinStatements = 10
    33  	iptrackWindow        = 5 * time.Minute
    34  	iptrackContactWindow = 10 * time.Minute
    35  )
    36  
    37  //local node生成本地节点的签名节点记录,即在
    38  //当前进程。通过set方法设置enr条目将更新记录。新版本
    39  //当调用node方法时,将根据需要对记录进行签名。
    40  type LocalNode struct {
    41  cur atomic.Value //当记录是最新的时,保存一个非零节点指针。
    42  	id  ID
    43  	key *ecdsa.PrivateKey
    44  	db  *DB
    45  
    46  //下面的一切都有锁保护
    47  	mu          sync.Mutex
    48  	seq         uint64
    49  	entries     map[string]enr.Entry
    50  udpTrack    *netutil.IPTracker //预测外部UDP终结点
    51  	staticIP    net.IP
    52  	fallbackIP  net.IP
    53  	fallbackUDP int
    54  }
    55  
    56  //newlocalnode创建本地节点。
    57  func NewLocalNode(db *DB, key *ecdsa.PrivateKey) *LocalNode {
    58  	ln := &LocalNode{
    59  		id:       PubkeyToIDV4(&key.PublicKey),
    60  		db:       db,
    61  		key:      key,
    62  		udpTrack: netutil.NewIPTracker(iptrackWindow, iptrackContactWindow, iptrackMinStatements),
    63  		entries:  make(map[string]enr.Entry),
    64  	}
    65  	ln.seq = db.localSeq(ln.id)
    66  	ln.invalidate()
    67  	return ln
    68  }
    69  
    70  //数据库返回与本地节点关联的节点数据库。
    71  func (ln *LocalNode) Database() *DB {
    72  	return ln.db
    73  }
    74  
    75  //node返回本地节点记录的当前版本。
    76  func (ln *LocalNode) Node() *Node {
    77  	n := ln.cur.Load().(*Node)
    78  	if n != nil {
    79  		return n
    80  	}
    81  //记录无效,请重新签名。
    82  	ln.mu.Lock()
    83  	defer ln.mu.Unlock()
    84  	ln.sign()
    85  	return ln.cur.Load().(*Node)
    86  }
    87  
    88  //id返回本地节点id。
    89  func (ln *LocalNode) ID() ID {
    90  	return ln.id
    91  }
    92  
    93  //set将给定条目放入本地记录中,覆盖
    94  //任何现有值。
    95  func (ln *LocalNode) Set(e enr.Entry) {
    96  	ln.mu.Lock()
    97  	defer ln.mu.Unlock()
    98  
    99  	ln.set(e)
   100  }
   101  
   102  func (ln *LocalNode) set(e enr.Entry) {
   103  	val, exists := ln.entries[e.ENRKey()]
   104  	if !exists || !reflect.DeepEqual(val, e) {
   105  		ln.entries[e.ENRKey()] = e
   106  		ln.invalidate()
   107  	}
   108  }
   109  
   110  //删除从本地记录中删除给定条目。
   111  func (ln *LocalNode) Delete(e enr.Entry) {
   112  	ln.mu.Lock()
   113  	defer ln.mu.Unlock()
   114  
   115  	ln.delete(e)
   116  }
   117  
   118  func (ln *LocalNode) delete(e enr.Entry) {
   119  	_, exists := ln.entries[e.ENRKey()]
   120  	if exists {
   121  		delete(ln.entries, e.ENRKey())
   122  		ln.invalidate()
   123  	}
   124  }
   125  
   126  //setstaticip无条件地将本地IP设置为给定IP。
   127  //这将禁用端点预测。
   128  func (ln *LocalNode) SetStaticIP(ip net.IP) {
   129  	ln.mu.Lock()
   130  	defer ln.mu.Unlock()
   131  
   132  	ln.staticIP = ip
   133  	ln.updateEndpoints()
   134  }
   135  
   136  //setfallbackip设置最后的IP地址。这个地址被使用了
   137  //如果无法进行端点预测,并且未设置静态IP。
   138  func (ln *LocalNode) SetFallbackIP(ip net.IP) {
   139  	ln.mu.Lock()
   140  	defer ln.mu.Unlock()
   141  
   142  	ln.fallbackIP = ip
   143  	ln.updateEndpoints()
   144  }
   145  
   146  //setfallbackudp设置最后的手段udp端口。此端口已被使用
   147  //如果无法进行端点预测。
   148  func (ln *LocalNode) SetFallbackUDP(port int) {
   149  	ln.mu.Lock()
   150  	defer ln.mu.Unlock()
   151  
   152  	ln.fallbackUDP = port
   153  	ln.updateEndpoints()
   154  }
   155  
   156  //每当有关本地节点的语句
   157  //接收到UDP终结点。它为本地端点预测器提供数据。
   158  func (ln *LocalNode) UDPEndpointStatement(fromaddr, endpoint *net.UDPAddr) {
   159  	ln.mu.Lock()
   160  	defer ln.mu.Unlock()
   161  
   162  	ln.udpTrack.AddStatement(fromaddr.String(), endpoint.String())
   163  	ln.updateEndpoints()
   164  }
   165  
   166  //每当本地节点向另一个节点通告自己时,都应调用udpcontact。
   167  //通过UDP。它为本地端点预测器提供数据。
   168  func (ln *LocalNode) UDPContact(toaddr *net.UDPAddr) {
   169  	ln.mu.Lock()
   170  	defer ln.mu.Unlock()
   171  
   172  	ln.udpTrack.AddContact(toaddr.String())
   173  	ln.updateEndpoints()
   174  }
   175  
   176  func (ln *LocalNode) updateEndpoints() {
   177  //确定端点。
   178  	newIP := ln.fallbackIP
   179  	newUDP := ln.fallbackUDP
   180  	if ln.staticIP != nil {
   181  		newIP = ln.staticIP
   182  	} else if ip, port := predictAddr(ln.udpTrack); ip != nil {
   183  		newIP = ip
   184  		newUDP = port
   185  	}
   186  
   187  //更新记录。
   188  	if newIP != nil && !newIP.IsUnspecified() {
   189  		ln.set(enr.IP(newIP))
   190  		if newUDP != 0 {
   191  			ln.set(enr.UDP(newUDP))
   192  		} else {
   193  			ln.delete(enr.UDP(0))
   194  		}
   195  	} else {
   196  		ln.delete(enr.IP{})
   197  	}
   198  }
   199  
   200  //PredictAddr包装iptracker.PredictEndpoint,从其基于字符串的转换
   201  //IP和端口类型的端点表示。
   202  func predictAddr(t *netutil.IPTracker) (net.IP, int) {
   203  	ep := t.PredictEndpoint()
   204  	if ep == "" {
   205  		return nil, 0
   206  	}
   207  	ipString, portString, _ := net.SplitHostPort(ep)
   208  	ip := net.ParseIP(ipString)
   209  	port, _ := strconv.Atoi(portString)
   210  	return ip, port
   211  }
   212  
   213  func (ln *LocalNode) invalidate() {
   214  	ln.cur.Store((*Node)(nil))
   215  }
   216  
   217  func (ln *LocalNode) sign() {
   218  	if n := ln.cur.Load().(*Node); n != nil {
   219  return //没有变化
   220  	}
   221  
   222  	var r enr.Record
   223  	for _, e := range ln.entries {
   224  		r.Set(e)
   225  	}
   226  	ln.bumpSeq()
   227  	r.SetSeq(ln.seq)
   228  	if err := SignV4(&r, ln.key); err != nil {
   229  		panic(fmt.Errorf("enode: can't sign record: %v", err))
   230  	}
   231  	n, err := New(ValidSchemes, &r)
   232  	if err != nil {
   233  		panic(fmt.Errorf("enode: can't verify local record: %v", err))
   234  	}
   235  	ln.cur.Store(n)
   236  	log.Info("New local node record", "seq", ln.seq, "id", n.ID(), "ip", n.IP(), "udp", n.UDP(), "tcp", n.TCP())
   237  }
   238  
   239  func (ln *LocalNode) bumpSeq() {
   240  	ln.seq++
   241  	ln.db.storeLocalSeq(ln.id, ln.seq)
   242  }
   243