github.com/elastos/Elastos.ELA.SideChain.ETH@v0.2.2/dpos/routes.go (about) 1 // Copyright (c) 2017-2019 The Elastos Foundation 2 // Use of this source code is governed by an MIT 3 // license that can be found in the LICENSE file. 4 // 5 6 package dpos 7 8 import ( 9 "bytes" 10 "container/list" 11 "fmt" 12 "sync" 13 "sync/atomic" 14 "time" 15 16 "github.com/elastos/Elastos.ELA/common" 17 "github.com/elastos/Elastos.ELA/crypto" 18 "github.com/elastos/Elastos.ELA/dpos/dtime" 19 "github.com/elastos/Elastos.ELA/dpos/p2p/peer" 20 "github.com/elastos/Elastos.ELA/events" 21 "github.com/elastos/Elastos.ELA/p2p/msg" 22 ) 23 24 type IPeer interface { 25 Disconnect() 26 SendELAMessage(msg *ElaMsg) 27 } 28 29 const ( 30 // minPeersToAnnounce defines the minimum connected peers to announce 31 // DPOS address into the P2P network. 32 minPeersToAnnounce = 5 33 34 // retryAnnounceDuration defines the time duration to retry an announce. 35 retryAnnounceDuration = 3 * time.Second 36 37 // maxTimeOffset indicates the maximum time offset with the to accept an 38 // DAddr message. 39 maxTimeOffset = 30 * time.Second 40 41 // minAnnounceDuration indicates the minimum allowed time duration to 42 // announce a new DAddr. 43 minAnnounceDuration = 30 * time.Second 44 45 // maxKnownAddrs indicates the maximum known DAddrs cached in memory. 46 // The maximum of DAddrs can be calculated as [36(current)+72(candidate)]². 47 maxKnownAddrs = 108 * 110 48 ) 49 50 // Config defines the parameters to create a Route instance. 51 type Config struct { 52 // The PID of this peer if it is an producer. 53 PID []byte 54 55 // The network address of this arbiter. 56 Addr string 57 58 // TimeSource is the median time source of the P2P network. 59 TimeSource dtime.MedianTimeSource 60 61 // Sign the addr message of this arbiter. 62 Sign func(data []byte) (signature []byte) 63 64 // IsCurrent returns whether BlockChain synced to best height. 65 IsCurrent func() bool 66 67 // RelayAddr relays the addresses inventory to the P2P network. 68 RelayAddr func(iv *msg.InvVect, data interface{}) 69 70 // OnCipherAddr will be invoked when an address cipher received. 71 OnCipherAddr func(pid peer.PID, cipher []byte) 72 } 73 74 // cache stores the requested DAddrs from a peer. 75 type cache struct { 76 requested map[common.Uint256]struct{} 77 } 78 79 // state stores the DPOS addresses and other additional information tracking 80 // addresses syncing status. 81 type state struct { 82 peers map[peer.PID]struct{} 83 requested map[common.Uint256]struct{} 84 peerCache map[IPeer]*cache 85 } 86 87 type newPeerMsg IPeer 88 89 type peersMsg struct { 90 peers []peer.PID 91 } 92 93 type invMsg struct { 94 peer IPeer 95 msg *msg.Inv 96 } 97 98 type dAddrMsg struct { 99 peer IPeer 100 msg *msg.DAddr 101 } 102 103 type Routes struct { 104 selfPID peer.PID 105 cfg *Config 106 addr string 107 sign func([]byte) []byte 108 109 // The following variables must only be used atomically. 110 started int32 111 stopped int32 112 waiting int32 113 114 addrMtx sync.RWMutex 115 addrIndex map[peer.PID]map[peer.PID]common.Uint256 116 knownAddr map[common.Uint256]*msg.DAddr 117 knownList *list.List 118 119 queue chan interface{} 120 donequeue chan IPeer 121 announce chan struct{} 122 quit chan struct{} 123 } 124 125 // New creates and return a Routes instance. 126 func New(cfg *Config) *Routes { 127 var pid peer.PID 128 copy(pid[:], cfg.PID) 129 130 r := Routes{ 131 selfPID: pid, 132 cfg: cfg, 133 addr: cfg.Addr, 134 sign: cfg.Sign, 135 addrIndex: make(map[peer.PID]map[peer.PID]common.Uint256), 136 knownAddr: make(map[common.Uint256]*msg.DAddr), 137 knownList: list.New(), 138 queue: make(chan interface{}, 125), 139 donequeue: make(chan IPeer, 1), 140 announce: make(chan struct{}, 1), 141 quit: make(chan struct{}), 142 } 143 144 events.Subscribe(func(e *events.Event) { 145 switch e.Type { 146 case events.ETDirectPeersChanged: 147 peersInfo := e.Data.(*peer.PeersInfo) 148 current := peersInfo.CurrentPeers 149 next := peersInfo.NextPeers 150 if next != nil { 151 current = append(current, next...) 152 } 153 go r.PeersChanged(current) 154 case ETElaMsg: 155 go r.ElaMsg(e.Data.(*MsgEvent)) 156 case ETNewPeer: 157 go r.NewPeer(e.Data.(IPeer)) 158 case ETDonePeer: 159 go r.DonePeer(e.Data.(IPeer)) 160 case ETStopRoutes: 161 go r.Stop() 162 case ETAnnounceAddr: 163 go r.AnnounceAddr() 164 } 165 }) 166 return &r 167 } 168 169 func (r *Routes) PeersChanged(peers []peer.PID) { 170 r.queue <- peersMsg{peers: peers} 171 } 172 173 // NewPeer notifies the new connected peer. 174 func (r *Routes) NewPeer(peer IPeer) { 175 r.queue <- newPeerMsg(peer) 176 } 177 178 // DonePeer notifies the disconnected peer. 179 func (r *Routes) DonePeer(peer IPeer) { 180 r.donequeue <- peer 181 } 182 183 func (r *Routes) ElaMsg(msgEvent *MsgEvent) { 184 switch msgEvent.ElaMsg.Type { 185 case Inv: 186 var inv msg.Inv 187 if err := inv.Deserialize(bytes.NewReader(msgEvent.ElaMsg.Msg)); err != nil { 188 Error("ElaMsg error,", err) 189 } 190 r.queue <- invMsg{peer: msgEvent.Peer, msg: &inv} 191 case GetData: 192 var getData msg.GetData 193 if err := getData.Deserialize(bytes.NewReader(msgEvent.ElaMsg.Msg)); err != nil { 194 Error("ElaMsg error,", err) 195 } 196 r.OnGetData(msgEvent.Peer, &getData) 197 case DAddr: 198 var dAddr msg.DAddr 199 if err := dAddr.Deserialize(bytes.NewReader(msgEvent.ElaMsg.Msg)); err != nil { 200 Error("ElaMsg error,", err) 201 } 202 r.queue <- dAddrMsg{peer: msgEvent.Peer, msg: &dAddr} 203 default: 204 Warn("Invalid ElaMsg type") 205 } 206 } 207 208 // Start starts the Routes instance to sync DPOS addresses. 209 func (r *Routes) Start() { 210 if !atomic.CompareAndSwapInt32(&r.started, 0, 1) { 211 return 212 } 213 go r.addrHandler() 214 } 215 216 // Stop quits the syncing address handler. 217 func (r *Routes) Stop() { 218 if !atomic.CompareAndSwapInt32(&r.stopped, 0, 1) { 219 return 220 } 221 close(r.quit) 222 } 223 224 // addrHandler is the main handler to syncing the addresses state. 225 func (r *Routes) addrHandler() { 226 state := &state{ 227 peers: make(map[peer.PID]struct{}), 228 requested: make(map[common.Uint256]struct{}), 229 peerCache: make(map[IPeer]*cache), 230 } 231 232 // lastAnnounce indicates the time when last announce sent. 233 var lastAnnounce time.Time 234 235 // scheduleAnnounce schedules an announce according to the delay time. 236 var scheduleAnnounce = func(delay time.Duration) { 237 time.AfterFunc(delay, func() { 238 r.announce <- struct{}{} 239 }) 240 } 241 242 out: 243 for { 244 select { 245 // Handle the messages from queue. 246 case m := <-r.queue: 247 switch m := m.(type) { 248 case newPeerMsg: 249 r.handleNewPeer(state, m) 250 251 case invMsg: 252 r.handleInv(state, m.peer, m.msg) 253 254 case dAddrMsg: 255 r.handleDAddr(state, m.peer, m.msg) 256 257 case peersMsg: 258 r.handlePeersMsg(state, m.peers) 259 } 260 261 // Handle the announce request. 262 case <-r.announce: 263 // This may be a retry or delayed announce, and the DPoS producers 264 // have been changed. 265 _, ok := state.peers[r.selfPID] 266 if !ok { 267 // Waiting status must reset here or the announce will never 268 // work again. 269 atomic.StoreInt32(&r.waiting, 0) 270 //continue 271 } 272 273 //TODO Temporary cancellation 274 // Do not announce address if connected peers not enough. 275 if len(state.peerCache) < minPeersToAnnounce { 276 // Retry announce after the retry duration. 277 //scheduleAnnounce(retryAnnounceDuration) 278 //continue 279 } 280 281 // Do not announce address too frequent. 282 now := time.Now() 283 if lastAnnounce.Add(minAnnounceDuration).After(now) { 284 // Calculate next announce time and schedule an announce. 285 nextAnnounce := minAnnounceDuration - now.Sub(lastAnnounce) 286 scheduleAnnounce(nextAnnounce) 287 continue 288 } 289 290 // Update last announce time. 291 lastAnnounce = now 292 // Reset waiting state to 0(false). 293 atomic.StoreInt32(&r.waiting, 0) 294 295 for pid := range state.peers { 296 // Do not create address for self. 297 if r.selfPID.Equal(pid) { 298 continue 299 } 300 301 pubKey, err := crypto.DecodePoint(pid[:]) 302 if err != nil { 303 continue 304 } 305 306 // Generate DAddr for the given PID. 307 cipher, err := crypto.Encrypt(pubKey, []byte(r.addr)) 308 if err != nil { 309 Warnf("encrypt addr %s failed %s", r.addr, err) 310 continue 311 } 312 addr := msg.DAddr{ 313 PID: r.selfPID, 314 Timestamp: time.Now(), 315 Encode: pid, 316 Cipher: cipher, 317 } 318 addr.Signature = r.sign(addr.Data()) 319 320 // Append and relay the local address. 321 r.appendAddr(&addr) 322 } 323 case m := <-r.donequeue: 324 r.handleDonePeer(state, m) 325 326 case <-r.quit: 327 break out 328 } 329 } 330 331 cleanup: 332 for { 333 select { 334 case <-r.queue: 335 case <-r.announce: 336 default: 337 break cleanup 338 } 339 } 340 } 341 342 func (r *Routes) handlePeersMsg(state *state, peers []peer.PID) { 343 // Compare current peers and new peers to find the difference. 344 var newPeers = make(map[peer.PID]struct{}) 345 for _, pid := range peers { 346 newPeers[pid] = struct{}{} 347 348 // Initiate address index. 349 r.addrMtx.RLock() 350 _, ok := r.addrIndex[pid] 351 r.addrMtx.RUnlock() 352 if !ok { 353 r.addrMtx.Lock() 354 r.addrIndex[pid] = make(map[peer.PID]common.Uint256) 355 r.addrMtx.Unlock() 356 } 357 } 358 359 // Remove peers that not in new peers list. 360 var delPeers []peer.PID 361 for pid := range state.peers { 362 if _, ok := newPeers[pid]; ok { 363 continue 364 } 365 delPeers = append(delPeers, pid) 366 } 367 368 for _, pid := range delPeers { 369 // Remove from index and known addr. 370 r.addrMtx.RLock() 371 pids, ok := r.addrIndex[pid] 372 r.addrMtx.RUnlock() 373 if !ok { 374 continue 375 } 376 377 r.addrMtx.Lock() 378 for _, pid := range pids { 379 delete(r.knownAddr, pid) 380 } 381 delete(r.addrIndex, pid) 382 r.addrMtx.Unlock() 383 } 384 385 // Update peers list. 386 _, isProducer := newPeers[r.selfPID] 387 _, wasProducer := state.peers[r.selfPID] 388 state.peers = newPeers 389 390 // Announce address into P2P network if we become arbiter. 391 if isProducer && !wasProducer { 392 r.announceAddr() 393 } 394 } 395 396 // AnnounceAddr schedules an local address announce to the P2P network, it used 397 // to re-announce the local address when DPoS network go bad. 398 func (r *Routes) AnnounceAddr() { 399 if atomic.LoadInt32(&r.started) == 0 { 400 return 401 } 402 r.announceAddr() 403 } 404 405 func (r *Routes) announceAddr() { 406 // Ignore if BlockChain not sync to current. 407 if !r.cfg.IsCurrent() { 408 Warn("announce Addr error, blockChain not sync to current") 409 return 410 } 411 412 //Refuse new announce if a previous announce is waiting, 413 //this is to reduce unnecessary announce. 414 if !atomic.CompareAndSwapInt32(&r.waiting, 0, 1) { 415 return 416 } 417 r.announce <- struct{}{} 418 } 419 420 func (r *Routes) handleDAddr(s *state, p IPeer, m *msg.DAddr) { 421 c, exists := s.peerCache[p] 422 if !exists { 423 Warnf("Received getdaddr message for unknown peer %s", p) 424 return 425 } 426 427 hash := m.Hash() 428 429 if _, ok := c.requested[hash]; !ok { 430 Warnf("Got unrequested addr %s from %s -- disconnecting", 431 hash, p) 432 p.Disconnect() 433 return 434 } 435 436 delete(c.requested, hash) 437 delete(s.requested, hash) 438 439 if err := r.verifyDAddr(s, m); err != nil { 440 Warnf("Got invalid addr %s %s from %s -- disconnecting", 441 hash, err, p) 442 p.Disconnect() 443 return 444 } 445 446 _, ok := s.peers[m.PID] 447 if !ok { 448 Debugf("PID not in arbiter list") 449 450 // Peers may have disagree with the current producers, so some times we 451 // receive addresses that not in the producers list. We do not 452 // disconnect the peer even the address not in producers list. 453 return 454 } 455 456 // Append received addr into state. 457 r.appendAddr(m) 458 459 // Notify the received DPOS address if the Encode matches. 460 if r.selfPID.Equal(m.Encode) && r.cfg.OnCipherAddr != nil { 461 r.cfg.OnCipherAddr(m.PID, m.Cipher) 462 } 463 } 464 465 func (r *Routes) appendAddr(m *msg.DAddr) { 466 hash := m.Hash() 467 468 // Append received addr into known addr index. 469 r.addrMtx.Lock() 470 //r.addrIndex[m.PID][m.Encode] = hash 471 r.knownAddr[hash] = m 472 if len(r.knownAddr) > maxKnownAddrs { 473 node := r.knownList.Back() 474 lru := node.Value.(common.Uint256) 475 476 delete(r.knownAddr, lru) 477 478 node.Value = hash 479 r.knownList.MoveToFront(node) 480 } else { 481 r.knownList.PushFront(hash) 482 } 483 r.addrMtx.Unlock() 484 485 // Relay addr to the P2P network. 486 iv := msg.NewInvVect(msg.InvTypeAddress, &hash) 487 r.cfg.RelayAddr(iv, m) 488 } 489 490 func (r *Routes) handleNewPeer(s *state, p IPeer) { 491 // Create state for the new peer. 492 s.peerCache[p] = &cache{requested: make(map[common.Uint256]struct{})} 493 } 494 495 func (r *Routes) handleDonePeer(s *state, p IPeer) { 496 c, exists := s.peerCache[p] 497 if !exists { 498 Warnf("Received done peer message for unknown peer %s", p) 499 return 500 } 501 502 // Remove done peer from peer state. 503 delete(s.peerCache, p) 504 505 // Clear cached information. 506 for pid := range c.requested { 507 delete(c.requested, pid) 508 } 509 } 510 511 func (r *Routes) handleInv(s *state, p IPeer, m *msg.Inv) { 512 c, exists := s.peerCache[p] 513 if !exists { 514 Warnf("Received inv message for unknown peer %s", p) 515 return 516 } 517 518 // Push GetData message according to the Inv message. 519 getData := msg.NewGetData() 520 for _, iv := range m.InvList { 521 switch iv.Type { 522 case msg.InvTypeAddress: 523 default: 524 continue 525 } 526 527 // Add the inventory to the cache of known inventory 528 // for the peer. 529 //p.AddKnownInventory(iv) 530 531 r.addrMtx.RLock() 532 _, ok := r.knownAddr[iv.Hash] 533 r.addrMtx.RUnlock() 534 if ok { 535 continue 536 } 537 538 if _, ok := s.requested[iv.Hash]; ok { 539 continue 540 } 541 542 c.requested[iv.Hash] = struct{}{} 543 s.requested[iv.Hash] = struct{}{} 544 getData.AddInvVect(msg.NewInvVect(msg.InvTypeAddress, &iv.Hash)) 545 } 546 547 if len(getData.InvList) > 0 { 548 getDataBuf := new(bytes.Buffer) 549 getData.Serialize(getDataBuf) 550 p.SendELAMessage(&ElaMsg{ 551 Type: GetData, 552 Msg: getDataBuf.Bytes(), 553 }) 554 } 555 } 556 557 // verifyDAddr verifies if this is a valid DPOS address message. 558 func (r *Routes) verifyDAddr(s *state, m *msg.DAddr) error { 559 // Verify signature of the message. 560 pubKey, err := crypto.DecodePoint(m.PID[:]) 561 if err != nil { 562 return fmt.Errorf("invalid public key") 563 } 564 err = crypto.Verify(*pubKey, m.Data(), m.Signature) 565 if err != nil { 566 return fmt.Errorf("invalid signature") 567 } 568 569 // Verify timestamp of the message. A DAddr to same arbiter can not be sent 570 // frequently to prevent attack, and a DAddr timestamp must not to far from 571 // the P2P network median time. 572 r.addrMtx.RLock() 573 defer r.addrMtx.RUnlock() 574 if index, ok := r.addrIndex[m.PID]; ok { 575 if hash, ok := index[m.Encode]; ok { 576 ka, ok := r.knownAddr[hash] 577 if !ok { 578 // This may happen if the known DAddr has been deleted because 579 // maxKnownAddrs arrived. In this case we do not return any 580 // error. 581 Debugf("unknown addr %s", hash) 582 return nil 583 } 584 585 // Abandon address older than the known address to the same arbiter. 586 if ka.Timestamp.After(m.Timestamp) { 587 return fmt.Errorf("timestamp is older than known") 588 } 589 590 //TODO add adjustedtime 591 //// Check if timestamp out of median time offset. 592 medianTime := r.cfg.TimeSource.AdjustedTime() 593 minTime := medianTime.Add(-maxTimeOffset) 594 maxTime := medianTime.Add(maxTimeOffset) 595 if m.Timestamp.Before(minTime) || m.Timestamp.After(maxTime) { 596 return fmt.Errorf("timestamp out of offset range") 597 } 598 599 // Check if the address announces too frequent. 600 if ka.Timestamp.Add(minAnnounceDuration).After(m.Timestamp) { 601 return fmt.Errorf("address announce too frequent") 602 } 603 } 604 } 605 606 return nil 607 } 608 609 // OnGetData handles the passed GetData message of the peer. 610 func (r *Routes) OnGetData(p IPeer, m *msg.GetData) { 611 for _, iv := range m.InvList { 612 switch iv.Type { 613 case msg.InvTypeAddress: 614 // Attempt to fetch the requested addr. 615 r.addrMtx.RLock() 616 addr, ok := r.knownAddr[iv.Hash] 617 r.addrMtx.RUnlock() 618 if !ok { 619 Warnf("%s for DAddr not found", iv.Hash) 620 continue 621 } 622 addrBuf := new(bytes.Buffer) 623 addr.Serialize(addrBuf) 624 p.SendELAMessage(&ElaMsg{ 625 Type: DAddr, 626 Msg: addrBuf.Bytes(), 627 }) 628 629 default: 630 continue 631 } 632 } 633 } 634 635 // QueueInv adds the passed Inv message and peer to the addr handling queue. 636 func (r *Routes) QueueInv(p IPeer, m *msg.Inv) { 637 // Filter non-address inventory messages. 638 for _, iv := range m.InvList { 639 if iv.Type == msg.InvTypeAddress { 640 r.queue <- invMsg{peer: p, msg: m} 641 return 642 } 643 } 644 }