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