github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/eth/peer.go (about) 1 // Copyright 2019 The ebakus/go-ebakus Authors 2 // This file is part of the ebakus/go-ebakus library. 3 // 4 // The ebakus/go-ebakus 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 ebakus/go-ebakus 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 ebakus/go-ebakus library. If not, see <http://www.gnu.org/licenses/>. 16 17 package eth 18 19 import ( 20 "errors" 21 "fmt" 22 "math/big" 23 "sync" 24 "time" 25 26 mapset "github.com/deckarep/golang-set" 27 "github.com/ebakus/go-ebakus/common" 28 "github.com/ebakus/go-ebakus/core/forkid" 29 "github.com/ebakus/go-ebakus/core/types" 30 "github.com/ebakus/go-ebakus/metrics" 31 "github.com/ebakus/go-ebakus/p2p" 32 "github.com/ebakus/go-ebakus/rlp" 33 ) 34 35 var ( 36 propBlockOutTimer = metrics.GetOrRegisterTimer("eth/prop/blocks/out", nil) 37 ) 38 39 var ( 40 errClosed = errors.New("peer set is closed") 41 errAlreadyRegistered = errors.New("peer is already registered") 42 errNotRegistered = errors.New("peer is not registered") 43 ) 44 45 const ( 46 maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS) 47 maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS) 48 49 // maxQueuedTxs is the maximum number of transaction lists to queue up before 50 // dropping broadcasts. This is a sensitive number as a transaction list might 51 // contain a single transaction, or thousands. 52 maxQueuedTxs = 128 53 54 // maxQueuedProps is the maximum number of block propagations to queue up before 55 // dropping broadcasts. There's not much point in queueing stale blocks, so a few 56 // that might cover uncles should be enough. 57 maxQueuedProps = 4 58 59 // maxQueuedAnns is the maximum number of block announcements to queue up before 60 // dropping broadcasts. Similarly to block propagations, there's no point to queue 61 // above some healthy uncle limit, so use that. 62 maxQueuedAnns = 4 63 64 handshakeTimeout = 5 * time.Second 65 ) 66 67 // PeerInfo represents a short summary of the Ebakus sub-protocol metadata known 68 // about a connected peer. 69 type PeerInfo struct { 70 Version int `json:"version"` // Ebakus protocol version negotiated 71 HeadNumber *big.Int `json:"headNumber"` // Head number of the peer's blockchain 72 Head string `json:"head"` // SHA3 hash of the peer's best owned block 73 } 74 75 // propEvent is a block propagation, waiting for its turn in the broadcast queue. 76 type propEvent struct { 77 block *types.Block 78 td *big.Int 79 } 80 81 type peer struct { 82 id string 83 84 *p2p.Peer 85 rw p2p.MsgReadWriter 86 87 version int // Protocol version negotiated 88 syncDrop *time.Timer // Timed connection dropper if sync progress isn't validated in time 89 90 head common.Hash 91 HeadNumber *big.Int 92 lock sync.RWMutex 93 94 knownTxs mapset.Set // Set of transaction hashes known to be known by this peer 95 knownBlocks mapset.Set // Set of block hashes known to be known by this peer 96 queuedTxs chan []*types.Transaction // Queue of transactions to broadcast to the peer 97 queuedProps chan *propEvent // Queue of blocks to broadcast to the peer 98 queuedAnns chan *types.Block // Queue of blocks to announce to the peer 99 term chan struct{} // Termination channel to stop the broadcaster 100 } 101 102 func newPeer(version int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { 103 return &peer{ 104 Peer: p, 105 rw: rw, 106 version: version, 107 id: fmt.Sprintf("%x", p.ID().Bytes()[:8]), 108 knownTxs: mapset.NewSet(), 109 knownBlocks: mapset.NewSet(), 110 queuedTxs: make(chan []*types.Transaction, maxQueuedTxs), 111 queuedProps: make(chan *propEvent, maxQueuedProps), 112 queuedAnns: make(chan *types.Block, maxQueuedAnns), 113 term: make(chan struct{}), 114 } 115 } 116 117 // broadcast is a write loop that multiplexes block propagations, announcements 118 // and transaction broadcasts into the remote peer. The goal is to have an async 119 // writer that does not lock up node internals. 120 func (p *peer) broadcast() { 121 for { 122 select { 123 case txs := <-p.queuedTxs: 124 if err := p.SendTransactions(txs); err != nil { 125 return 126 } 127 p.Log().Trace("Broadcast transactions", "count", len(txs)) 128 129 case prop := <-p.queuedProps: 130 if err := p.SendNewBlock(prop.block); err != nil { 131 return 132 } 133 p.Log().Trace("Propagated block", "number", prop.block.Number(), "hash", prop.block.Hash(), "td", prop.td) 134 135 case block := <-p.queuedAnns: 136 if err := p.SendNewBlockHashes([]common.Hash{block.Hash()}, []uint64{block.NumberU64()}); err != nil { 137 return 138 } 139 p.Log().Trace("Announced block", "number", block.Number(), "hash", block.Hash()) 140 141 case <-p.term: 142 return 143 } 144 } 145 } 146 147 // close signals the broadcast goroutine to terminate. 148 func (p *peer) close() { 149 close(p.term) 150 } 151 152 // Info gathers and returns a collection of metadata known about a peer. 153 func (p *peer) Info() *PeerInfo { 154 hash, td := p.Head() 155 156 return &PeerInfo{ 157 Version: p.version, 158 HeadNumber: td, 159 Head: hash.Hex(), 160 } 161 } 162 163 // Head retrieves a copy of the current head hash and total difficulty of the 164 // peer. 165 func (p *peer) Head() (hash common.Hash, td *big.Int) { 166 p.lock.RLock() 167 defer p.lock.RUnlock() 168 169 copy(hash[:], p.head[:]) 170 return hash, new(big.Int).Set(p.HeadNumber) 171 } 172 173 // SetHead updates the head hash and total difficulty of the peer. 174 func (p *peer) SetHead(hash common.Hash, td *big.Int) { 175 p.lock.Lock() 176 defer p.lock.Unlock() 177 178 copy(p.head[:], hash[:]) 179 p.HeadNumber.Set(td) 180 } 181 182 // MarkBlock marks a block as known for the peer, ensuring that the block will 183 // never be propagated to this particular peer. 184 func (p *peer) MarkBlock(hash common.Hash) { 185 // If we reached the memory allowance, drop a previously known block hash 186 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 187 p.knownBlocks.Pop() 188 } 189 p.knownBlocks.Add(hash) 190 } 191 192 // MarkTransaction marks a transaction as known for the peer, ensuring that it 193 // will never be propagated to this particular peer. 194 func (p *peer) MarkTransaction(hash common.Hash) { 195 // If we reached the memory allowance, drop a previously known transaction hash 196 for p.knownTxs.Cardinality() >= maxKnownTxs { 197 p.knownTxs.Pop() 198 } 199 p.knownTxs.Add(hash) 200 } 201 202 // SendTransactions sends transactions to the peer and includes the hashes 203 // in its transaction hash set for future reference. 204 func (p *peer) SendTransactions(txs types.Transactions) error { 205 // Mark all the transactions as known, but ensure we don't overflow our limits 206 for _, tx := range txs { 207 p.knownTxs.Add(tx.Hash()) 208 } 209 for p.knownTxs.Cardinality() >= maxKnownTxs { 210 p.knownTxs.Pop() 211 } 212 return p2p.Send(p.rw, TxMsg, txs) 213 } 214 215 // AsyncSendTransactions queues list of transactions propagation to a remote 216 // peer. If the peer's broadcast queue is full, the event is silently dropped. 217 func (p *peer) AsyncSendTransactions(txs []*types.Transaction) { 218 select { 219 case p.queuedTxs <- txs: 220 // Mark all the transactions as known, but ensure we don't overflow our limits 221 for _, tx := range txs { 222 p.knownTxs.Add(tx.Hash()) 223 } 224 for p.knownTxs.Cardinality() >= maxKnownTxs { 225 p.knownTxs.Pop() 226 } 227 default: 228 p.Log().Debug("Dropping transaction propagation", "count", len(txs)) 229 } 230 } 231 232 // SendNewBlockHashes announces the availability of a number of blocks through 233 // a hash notification. 234 func (p *peer) SendNewBlockHashes(hashes []common.Hash, numbers []uint64) error { 235 // Mark all the block hashes as known, but ensure we don't overflow our limits 236 for _, hash := range hashes { 237 p.knownBlocks.Add(hash) 238 } 239 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 240 p.knownBlocks.Pop() 241 } 242 request := make(newBlockHashesData, len(hashes)) 243 for i := 0; i < len(hashes); i++ { 244 request[i].Hash = hashes[i] 245 request[i].Number = numbers[i] 246 } 247 return p2p.Send(p.rw, NewBlockHashesMsg, request) 248 } 249 250 // AsyncSendNewBlockHash queues the availability of a block for propagation to a 251 // remote peer. If the peer's broadcast queue is full, the event is silently 252 // dropped. 253 func (p *peer) AsyncSendNewBlockHash(block *types.Block) { 254 select { 255 case p.queuedAnns <- block: 256 // Mark all the block hash as known, but ensure we don't overflow our limits 257 p.knownBlocks.Add(block.Hash()) 258 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 259 p.knownBlocks.Pop() 260 } 261 default: 262 p.Log().Debug("Dropping block announcement", "number", block.NumberU64(), "hash", block.Hash()) 263 } 264 } 265 266 // SendNewBlock propagates an entire block to a remote peer. 267 func (p *peer) SendNewBlock(block *types.Block) error { 268 defer propBlockOutTimer.UpdateSince(time.Now()) 269 270 // Mark all the block hash as known, but ensure we don't overflow our limits 271 p.knownBlocks.Add(block.Hash()) 272 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 273 p.knownBlocks.Pop() 274 } 275 return p2p.Send(p.rw, NewBlockMsg, block) 276 } 277 278 // AsyncSendNewBlock queues an entire block for propagation to a remote peer. If 279 // the peer's broadcast queue is full, the event is silently dropped. 280 func (p *peer) AsyncSendNewBlock(block *types.Block) { 281 select { 282 case p.queuedProps <- &propEvent{block: block, td: big.NewInt(0)}: 283 // Mark all the block hash as known, but ensure we don't overflow our limits 284 p.knownBlocks.Add(block.Hash()) 285 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 286 p.knownBlocks.Pop() 287 } 288 default: 289 p.Log().Debug("Dropping block propagation", "number", block.NumberU64(), "hash", block.Hash()) 290 } 291 } 292 293 // SendBlockHeaders sends a batch of block headers to the remote peer. 294 func (p *peer) SendBlockHeaders(headers []*types.Header) error { 295 return p2p.Send(p.rw, BlockHeadersMsg, headers) 296 } 297 298 // SendBlockBodies sends a batch of block contents to the remote peer. 299 func (p *peer) SendBlockBodies(bodies []*blockBody) error { 300 return p2p.Send(p.rw, BlockBodiesMsg, blockBodiesData(bodies)) 301 } 302 303 // SendBlockBodiesRLP sends a batch of block contents to the remote peer from 304 // an already RLP encoded format. 305 func (p *peer) SendBlockBodiesRLP(bodies []rlp.RawValue) error { 306 return p2p.Send(p.rw, BlockBodiesMsg, bodies) 307 } 308 309 // SendNodeDataRLP sends a batch of arbitrary internal data, corresponding to the 310 // hashes requested. 311 func (p *peer) SendNodeData(data [][]byte) error { 312 return p2p.Send(p.rw, NodeDataMsg, data) 313 } 314 315 // SendReceiptsRLP sends a batch of transaction receipts, corresponding to the 316 // ones requested from an already RLP encoded format. 317 func (p *peer) SendReceiptsRLP(receipts []rlp.RawValue) error { 318 return p2p.Send(p.rw, ReceiptsMsg, receipts) 319 } 320 321 // RequestOneHeader is a wrapper around the header query functions to fetch a 322 // single header. It is used solely by the fetcher. 323 func (p *peer) RequestOneHeader(hash common.Hash) error { 324 p.Log().Debug("Fetching single header", "hash", hash) 325 return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}, Amount: uint64(1), Skip: uint64(0), Reverse: false}) 326 } 327 328 // RequestHeadersByHash fetches a batch of blocks' headers corresponding to the 329 // specified header query, based on the hash of an origin block. 330 func (p *peer) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { 331 p.Log().Debug("Fetching batch of headers", "count", amount, "fromhash", origin, "skip", skip, "reverse", reverse) 332 return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Hash: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse}) 333 } 334 335 // RequestHeadersByNumber fetches a batch of blocks' headers corresponding to the 336 // specified header query, based on the number of an origin block. 337 func (p *peer) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 338 p.Log().Debug("Fetching batch of headers", "count", amount, "fromnum", origin, "skip", skip, "reverse", reverse) 339 return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Number: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse}) 340 } 341 342 // RequestBodies fetches a batch of blocks' bodies corresponding to the hashes 343 // specified. 344 func (p *peer) RequestBodies(hashes []common.Hash) error { 345 p.Log().Debug("Fetching batch of block bodies", "count", len(hashes)) 346 return p2p.Send(p.rw, GetBlockBodiesMsg, hashes) 347 } 348 349 // RequestNodeData fetches a batch of arbitrary data from a node's known state 350 // data, corresponding to the specified hashes. 351 func (p *peer) RequestNodeData(hashes []common.Hash) error { 352 p.Log().Debug("Fetching batch of state data", "count", len(hashes)) 353 return p2p.Send(p.rw, GetNodeDataMsg, hashes) 354 } 355 356 // RequestReceipts fetches a batch of transaction receipts from a remote node. 357 func (p *peer) RequestReceipts(hashes []common.Hash) error { 358 p.Log().Debug("Fetching batch of receipts", "count", len(hashes)) 359 return p2p.Send(p.rw, GetReceiptsMsg, hashes) 360 } 361 362 // Handshake executes the eth protocol handshake, negotiating version number, 363 // network IDs, difficulties, head and genesis blocks. 364 func (p *peer) Handshake(network uint64, headNumber *big.Int, head common.Hash, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter) error { 365 // Send out own handshake in a new thread 366 errc := make(chan error, 2) 367 368 var ( 369 status63 statusData63 // safe to read after two values have been received from errc 370 status statusData // safe to read after two values have been received from errc 371 ) 372 go func() { 373 switch { 374 case p.version == eth63: 375 errc <- p2p.Send(p.rw, StatusMsg, &statusData63{ 376 ProtocolVersion: uint32(p.version), 377 NetworkId: network, 378 HeadNumber: headNumber, 379 CurrentBlock: head, 380 GenesisBlock: genesis, 381 }) 382 case p.version == eth64: 383 errc <- p2p.Send(p.rw, StatusMsg, &statusData{ 384 ProtocolVersion: uint32(p.version), 385 NetworkID: network, 386 HeadNumber: headNumber, 387 Head: head, 388 Genesis: genesis, 389 ForkID: forkID, 390 }) 391 default: 392 panic(fmt.Sprintf("unsupported eth protocol version: %d", p.version)) 393 } 394 }() 395 go func() { 396 switch { 397 case p.version == eth63: 398 errc <- p.readStatusLegacy(network, &status63, genesis) 399 case p.version == eth64: 400 errc <- p.readStatus(network, &status, genesis, forkFilter) 401 default: 402 panic(fmt.Sprintf("unsupported eth protocol version: %d", p.version)) 403 } 404 }() 405 timeout := time.NewTimer(handshakeTimeout) 406 defer timeout.Stop() 407 for i := 0; i < 2; i++ { 408 select { 409 case err := <-errc: 410 if err != nil { 411 return err 412 } 413 case <-timeout.C: 414 return p2p.DiscReadTimeout 415 } 416 } 417 switch { 418 case p.version == eth63: 419 p.HeadNumber, p.head = status63.HeadNumber, status63.CurrentBlock 420 case p.version == eth64: 421 p.HeadNumber, p.head = status.HeadNumber, status.Head 422 default: 423 panic(fmt.Sprintf("unsupported eth protocol version: %d", p.version)) 424 } 425 return nil 426 } 427 428 func (p *peer) readStatusLegacy(network uint64, status *statusData63, genesis common.Hash) error { 429 msg, err := p.rw.ReadMsg() 430 if err != nil { 431 return err 432 } 433 if msg.Code != StatusMsg { 434 return errResp(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg) 435 } 436 if msg.Size > protocolMaxMsgSize { 437 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, protocolMaxMsgSize) 438 } 439 // Decode the handshake and make sure everything matches 440 if err := msg.Decode(&status); err != nil { 441 return errResp(ErrDecode, "msg %v: %v", msg, err) 442 } 443 if status.GenesisBlock != genesis { 444 return errResp(ErrGenesisMismatch, "%x (!= %x)", status.GenesisBlock[:8], genesis[:8]) 445 } 446 if status.NetworkId != network { 447 return errResp(ErrNetworkIDMismatch, "%d (!= %d)", status.NetworkId, network) 448 } 449 if int(status.ProtocolVersion) != p.version { 450 return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.version) 451 } 452 return nil 453 } 454 455 func (p *peer) readStatus(network uint64, status *statusData, genesis common.Hash, forkFilter forkid.Filter) error { 456 msg, err := p.rw.ReadMsg() 457 if err != nil { 458 return err 459 } 460 if msg.Code != StatusMsg { 461 return errResp(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg) 462 } 463 if msg.Size > protocolMaxMsgSize { 464 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, protocolMaxMsgSize) 465 } 466 // Decode the handshake and make sure everything matches 467 if err := msg.Decode(&status); err != nil { 468 return errResp(ErrDecode, "msg %v: %v", msg, err) 469 } 470 if status.NetworkID != network { 471 return errResp(ErrNetworkIDMismatch, "%d (!= %d)", status.NetworkID, network) 472 } 473 if int(status.ProtocolVersion) != p.version { 474 return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.version) 475 } 476 if status.Genesis != genesis { 477 return errResp(ErrGenesisMismatch, "%x (!= %x)", status.Genesis, genesis) 478 } 479 if err := forkFilter(status.ForkID); err != nil { 480 return errResp(ErrForkIDRejected, "%v", err) 481 } 482 return nil 483 } 484 485 // String implements fmt.Stringer. 486 func (p *peer) String() string { 487 return fmt.Sprintf("Peer %s [%s]", p.id, 488 fmt.Sprintf("eth/%2d", p.version), 489 ) 490 } 491 492 // peerSet represents the collection of active peers currently participating in 493 // the Ebakus sub-protocol. 494 type peerSet struct { 495 peers map[string]*peer 496 lock sync.RWMutex 497 closed bool 498 } 499 500 // newPeerSet creates a new peer set to track the active participants. 501 func newPeerSet() *peerSet { 502 return &peerSet{ 503 peers: make(map[string]*peer), 504 } 505 } 506 507 // Register injects a new peer into the working set, or returns an error if the 508 // peer is already known. If a new peer it registered, its broadcast loop is also 509 // started. 510 func (ps *peerSet) Register(p *peer) error { 511 ps.lock.Lock() 512 defer ps.lock.Unlock() 513 514 if ps.closed { 515 return errClosed 516 } 517 if _, ok := ps.peers[p.id]; ok { 518 return errAlreadyRegistered 519 } 520 ps.peers[p.id] = p 521 go p.broadcast() 522 523 return nil 524 } 525 526 // Unregister removes a remote peer from the active set, disabling any further 527 // actions to/from that particular entity. 528 func (ps *peerSet) Unregister(id string) error { 529 ps.lock.Lock() 530 defer ps.lock.Unlock() 531 532 p, ok := ps.peers[id] 533 if !ok { 534 return errNotRegistered 535 } 536 delete(ps.peers, id) 537 p.close() 538 539 return nil 540 } 541 542 // Peer retrieves the registered peer with the given id. 543 func (ps *peerSet) Peer(id string) *peer { 544 ps.lock.RLock() 545 defer ps.lock.RUnlock() 546 547 return ps.peers[id] 548 } 549 550 // Len returns if the current number of peers in the set. 551 func (ps *peerSet) Len() int { 552 ps.lock.RLock() 553 defer ps.lock.RUnlock() 554 555 return len(ps.peers) 556 } 557 558 // PeersWithoutBlock retrieves a list of peers that do not have a given block in 559 // their set of known hashes. 560 func (ps *peerSet) PeersWithoutBlock(hash common.Hash) []*peer { 561 ps.lock.RLock() 562 defer ps.lock.RUnlock() 563 564 list := make([]*peer, 0, len(ps.peers)) 565 for _, p := range ps.peers { 566 if !p.knownBlocks.Contains(hash) { 567 list = append(list, p) 568 } 569 } 570 return list 571 } 572 573 // PeersWithoutTx retrieves a list of peers that do not have a given transaction 574 // in their set of known hashes. 575 func (ps *peerSet) PeersWithoutTx(hash common.Hash) []*peer { 576 ps.lock.RLock() 577 defer ps.lock.RUnlock() 578 579 list := make([]*peer, 0, len(ps.peers)) 580 for _, p := range ps.peers { 581 if !p.knownTxs.Contains(hash) { 582 list = append(list, p) 583 } 584 } 585 return list 586 } 587 588 // BestPeer retrieves the known peer with the currently highest total difficulty. 589 func (ps *peerSet) BestPeer() *peer { 590 ps.lock.RLock() 591 defer ps.lock.RUnlock() 592 593 var ( 594 bestPeer *peer 595 bestTd *big.Int 596 ) 597 for _, p := range ps.peers { 598 if _, td := p.Head(); bestPeer == nil || td.Cmp(bestTd) > 0 { 599 bestPeer, bestTd = p, td 600 } 601 } 602 return bestPeer 603 } 604 605 // Close disconnects all peers. 606 // No new peers can be registered after Close has returned. 607 func (ps *peerSet) Close() { 608 ps.lock.Lock() 609 defer ps.lock.Unlock() 610 611 for _, p := range ps.peers { 612 p.Disconnect(p2p.DiscQuitting) 613 } 614 ps.closed = true 615 }