github.com/core-coin/go-core/v2@v2.1.9/xcb/peer.go (about) 1 // Copyright 2015 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package xcb 18 19 import ( 20 "errors" 21 "fmt" 22 "math/big" 23 "sync" 24 "time" 25 26 mapset "github.com/deckarep/golang-set" 27 28 "github.com/core-coin/go-core/v2/common" 29 "github.com/core-coin/go-core/v2/core/forkid" 30 "github.com/core-coin/go-core/v2/core/types" 31 "github.com/core-coin/go-core/v2/p2p" 32 "github.com/core-coin/go-core/v2/rlp" 33 ) 34 35 var ( 36 errClosed = errors.New("peer set is closed") 37 errAlreadyRegistered = errors.New("peer is already registered") 38 errNotRegistered = errors.New("peer is not registered") 39 ) 40 41 const ( 42 maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS) 43 maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS) 44 45 // maxQueuedTxs is the maximum number of transactions to queue up before dropping 46 // older broadcasts. 47 maxQueuedTxs = 4096 48 49 // maxQueuedTxAnns is the maximum number of transaction announcements to queue up 50 // before dropping older announcements. 51 maxQueuedTxAnns = 4096 52 53 // maxQueuedBlocks is the maximum number of block propagations to queue up before 54 // dropping broadcasts. There's not much point in queueing stale blocks, so a few 55 // that might cover uncles should be enough. 56 maxQueuedBlocks = 4 57 58 // maxQueuedBlockAnns is the maximum number of block announcements to queue up before 59 // dropping broadcasts. Similarly to block propagations, there's no point to queue 60 // above some healthy uncle limit, so use that. 61 maxQueuedBlockAnns = 4 62 63 handshakeTimeout = 5 * time.Second 64 ) 65 66 // max is a helper function which returns the larger of the two given integers. 67 func max(a, b int) int { 68 if a > b { 69 return a 70 } 71 return b 72 } 73 74 // PeerInfo represents a short summary of the Core sub-protocol metadata known 75 // about a connected peer. 76 type PeerInfo struct { 77 Version int `json:"version"` // Core protocol version negotiated 78 Difficulty *big.Int `json:"difficulty"` // Total difficulty of the peer's blockchain 79 Head string `json:"head"` // SHA3 hash of the peer's best owned block 80 } 81 82 // propEvent is a block propagation, waiting for its turn in the broadcast queue. 83 type propEvent struct { 84 block *types.Block 85 td *big.Int 86 } 87 88 type peer struct { 89 id string 90 91 *p2p.Peer 92 rw p2p.MsgReadWriter 93 94 version int // Protocol version negotiated 95 syncDrop *time.Timer // Timed connection dropper if sync progress isn't validated in time 96 97 head common.Hash 98 td *big.Int 99 lock sync.RWMutex 100 101 knownBlocks mapset.Set // Set of block hashes known to be known by this peer 102 queuedBlocks chan *propEvent // Queue of blocks to broadcast to the peer 103 queuedBlockAnns chan *types.Block // Queue of blocks to announce to the peer 104 105 knownTxs mapset.Set // Set of transaction hashes known to be known by this peer 106 txBroadcast chan []common.Hash // Channel used to queue transaction propagation requests 107 txAnnounce chan []common.Hash // Channel used to queue transaction announcement requests 108 getPooledTx func(common.Hash) *types.Transaction // Callback used to retrieve transaction from txpool 109 110 term chan struct{} // Termination channel to stop the broadcaster 111 } 112 113 func newPeer(version int, p *p2p.Peer, rw p2p.MsgReadWriter, getPooledTx func(hash common.Hash) *types.Transaction) *peer { 114 return &peer{ 115 Peer: p, 116 rw: rw, 117 version: version, 118 id: fmt.Sprintf("%x", p.ID().Bytes()[:8]), 119 knownTxs: mapset.NewSet(), 120 knownBlocks: mapset.NewSet(), 121 queuedBlocks: make(chan *propEvent, maxQueuedBlocks), 122 queuedBlockAnns: make(chan *types.Block, maxQueuedBlockAnns), 123 txBroadcast: make(chan []common.Hash), 124 txAnnounce: make(chan []common.Hash), 125 getPooledTx: getPooledTx, 126 term: make(chan struct{}), 127 } 128 } 129 130 // broadcastBlocks is a write loop that multiplexes blocks and block accouncements 131 // to the remote peer. The goal is to have an async writer that does not lock up 132 // node internals and at the same time rate limits queued data. 133 func (p *peer) broadcastBlocks(removePeer func(string)) { 134 for { 135 select { 136 case prop := <-p.queuedBlocks: 137 if err := p.SendNewBlock(prop.block, prop.td); err != nil { 138 removePeer(p.id) 139 return 140 } 141 p.Log().Trace("Propagated block", "number", prop.block.Number(), "hash", prop.block.Hash(), "td", prop.td) 142 143 case block := <-p.queuedBlockAnns: 144 if err := p.SendNewBlockHashes([]common.Hash{block.Hash()}, []uint64{block.NumberU64()}); err != nil { 145 removePeer(p.id) 146 return 147 } 148 p.Log().Trace("Announced block", "number", block.Number(), "hash", block.Hash()) 149 150 case <-p.term: 151 return 152 } 153 } 154 } 155 156 // broadcastTransactions is a write loop that schedules transaction broadcasts 157 // to the remote peer. The goal is to have an async writer that does not lock up 158 // node internals and at the same time rate limits queued data. 159 func (p *peer) broadcastTransactions(removePeer func(string)) { 160 var ( 161 queue []common.Hash // Queue of hashes to broadcast as full transactions 162 done chan struct{} // Non-nil if background broadcaster is running 163 fail = make(chan error, 1) // Channel used to receive network error 164 ) 165 for { 166 // If there's no in-flight broadcast running, check if a new one is needed 167 if done == nil && len(queue) > 0 { 168 // Pile transaction until we reach our allowed network limit 169 var ( 170 hashes []common.Hash 171 txs []*types.Transaction 172 size common.StorageSize 173 ) 174 for i := 0; i < len(queue) && size < txsyncPackSize; i++ { 175 if tx := p.getPooledTx(queue[i]); tx != nil { 176 txs = append(txs, tx) 177 size += tx.Size() 178 } 179 hashes = append(hashes, queue[i]) 180 } 181 queue = queue[:copy(queue, queue[len(hashes):])] 182 183 // If there's anything available to transfer, fire up an async writer 184 if len(txs) > 0 { 185 done = make(chan struct{}) 186 go func() { 187 if err := p.sendTransactions(txs); err != nil { 188 fail <- err 189 return 190 } 191 close(done) 192 p.Log().Trace("Sent transactions", "count", len(txs)) 193 }() 194 } 195 } 196 // Transfer goroutine may or may not have been started, listen for events 197 select { 198 case hashes := <-p.txBroadcast: 199 // New batch of transactions to be broadcast, queue them (with cap) 200 queue = append(queue, hashes...) 201 if len(queue) > maxQueuedTxs { 202 // Fancy copy and resize to ensure buffer doesn't grow indefinitely 203 queue = queue[:copy(queue, queue[len(queue)-maxQueuedTxs:])] 204 } 205 206 case <-done: 207 done = nil 208 209 case <-fail: 210 removePeer(p.id) 211 return 212 213 case <-p.term: 214 return 215 } 216 } 217 } 218 219 // announceTransactions is a write loop that schedules transaction broadcasts 220 // to the remote peer. The goal is to have an async writer that does not lock up 221 // node internals and at the same time rate limits queued data. 222 func (p *peer) announceTransactions(removePeer func(string)) { 223 var ( 224 queue []common.Hash // Queue of hashes to announce as transaction stubs 225 done chan struct{} // Non-nil if background announcer is running 226 fail = make(chan error, 1) // Channel used to receive network error 227 ) 228 for { 229 // If there's no in-flight announce running, check if a new one is needed 230 if done == nil && len(queue) > 0 { 231 // Pile transaction hashes until we reach our allowed network limit 232 var ( 233 hashes []common.Hash 234 pending []common.Hash 235 size common.StorageSize 236 ) 237 for i := 0; i < len(queue) && size < txsyncPackSize; i++ { 238 if p.getPooledTx(queue[i]) != nil { 239 pending = append(pending, queue[i]) 240 size += common.HashLength 241 } 242 hashes = append(hashes, queue[i]) 243 } 244 queue = queue[:copy(queue, queue[len(hashes):])] 245 246 // If there's anything available to transfer, fire up an async writer 247 if len(pending) > 0 { 248 done = make(chan struct{}) 249 go func() { 250 if err := p.sendPooledTransactionHashes(pending); err != nil { 251 fail <- err 252 return 253 } 254 close(done) 255 p.Log().Trace("Sent transaction announcements", "count", len(pending)) 256 }() 257 } 258 } 259 // Transfer goroutine may or may not have been started, listen for events 260 select { 261 case hashes := <-p.txAnnounce: 262 // New batch of transactions to be broadcast, queue them (with cap) 263 queue = append(queue, hashes...) 264 if len(queue) > maxQueuedTxAnns { 265 // Fancy copy and resize to ensure buffer doesn't grow indefinitely 266 queue = queue[:copy(queue, queue[len(queue)-maxQueuedTxAnns:])] 267 } 268 269 case <-done: 270 done = nil 271 272 case <-fail: 273 removePeer(p.id) 274 return 275 276 case <-p.term: 277 return 278 } 279 } 280 } 281 282 // close signals the broadcast goroutine to terminate. 283 func (p *peer) close() { 284 close(p.term) 285 } 286 287 // Info gathers and returns a collection of metadata known about a peer. 288 func (p *peer) Info() *PeerInfo { 289 hash, td := p.Head() 290 291 return &PeerInfo{ 292 Version: p.version, 293 Difficulty: td, 294 Head: hash.Hex(), 295 } 296 } 297 298 // Head retrieves a copy of the current head hash and total difficulty of the 299 // peer. 300 func (p *peer) Head() (hash common.Hash, td *big.Int) { 301 p.lock.RLock() 302 defer p.lock.RUnlock() 303 304 copy(hash[:], p.head[:]) 305 return hash, new(big.Int).Set(p.td) 306 } 307 308 // SetHead updates the head hash and total difficulty of the peer. 309 func (p *peer) SetHead(hash common.Hash, td *big.Int) { 310 p.lock.Lock() 311 defer p.lock.Unlock() 312 313 copy(p.head[:], hash[:]) 314 p.td.Set(td) 315 } 316 317 // MarkBlock marks a block as known for the peer, ensuring that the block will 318 // never be propagated to this particular peer. 319 func (p *peer) MarkBlock(hash common.Hash) { 320 // If we reached the memory allowance, drop a previously known block hash 321 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 322 p.knownBlocks.Pop() 323 } 324 p.knownBlocks.Add(hash) 325 } 326 327 // MarkTransaction marks a transaction as known for the peer, ensuring that it 328 // will never be propagated to this particular peer. 329 func (p *peer) MarkTransaction(hash common.Hash) { 330 // If we reached the memory allowance, drop a previously known transaction hash 331 for p.knownTxs.Cardinality() >= maxKnownTxs { 332 p.knownTxs.Pop() 333 } 334 p.knownTxs.Add(hash) 335 } 336 337 // SendTransactions64 sends transactions to the peer and includes the hashes 338 // in its transaction hash set for future reference. 339 // 340 // This method is legacy support for initial transaction exchange in xcb/64 and 341 // prior. For xcb/65 and higher use SendPooledTransactionHashes. 342 func (p *peer) SendTransactions64(txs types.Transactions) error { 343 return p.sendTransactions(txs) 344 } 345 346 // sendTransactions sends transactions to the peer and includes the hashes 347 // in its transaction hash set for future reference. 348 // 349 // This method is a helper used by the async transaction sender. Don't call it 350 // directly as the queueing (memory) and transmission (bandwidth) costs should 351 // not be managed directly. 352 func (p *peer) sendTransactions(txs types.Transactions) error { 353 // Mark all the transactions as known, but ensure we don't overflow our limits 354 for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(txs)) { 355 p.knownTxs.Pop() 356 } 357 for _, tx := range txs { 358 p.knownTxs.Add(tx.Hash()) 359 } 360 return p2p.Send(p.rw, TransactionMsg, txs) 361 } 362 363 // AsyncSendTransactions queues a list of transactions (by hash) to eventually 364 // propagate to a remote peer. The number of pending sends are capped (new ones 365 // will force old sends to be dropped) 366 func (p *peer) AsyncSendTransactions(hashes []common.Hash) { 367 select { 368 case p.txBroadcast <- hashes: 369 // Mark all the transactions as known, but ensure we don't overflow our limits 370 for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) { 371 p.knownTxs.Pop() 372 } 373 for _, hash := range hashes { 374 p.knownTxs.Add(hash) 375 } 376 case <-p.term: 377 p.Log().Debug("Dropping transaction propagation", "count", len(hashes)) 378 } 379 } 380 381 // sendPooledTransactionHashes sends transaction hashes to the peer and includes 382 // them in its transaction hash set for future reference. 383 // 384 // This method is a helper used by the async transaction announcer. Don't call it 385 // directly as the queueing (memory) and transmission (bandwidth) costs should 386 // not be managed directly. 387 func (p *peer) sendPooledTransactionHashes(hashes []common.Hash) error { 388 // Mark all the transactions as known, but ensure we don't overflow our limits 389 for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) { 390 p.knownTxs.Pop() 391 } 392 for _, hash := range hashes { 393 p.knownTxs.Add(hash) 394 } 395 return p2p.Send(p.rw, NewPooledTransactionHashesMsg, hashes) 396 } 397 398 // AsyncSendPooledTransactionHashes queues a list of transactions hashes to eventually 399 // announce to a remote peer. The number of pending sends are capped (new ones 400 // will force old sends to be dropped) 401 func (p *peer) AsyncSendPooledTransactionHashes(hashes []common.Hash) { 402 select { 403 case p.txAnnounce <- hashes: 404 // Mark all the transactions as known, but ensure we don't overflow our limits 405 for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) { 406 p.knownTxs.Pop() 407 } 408 for _, hash := range hashes { 409 p.knownTxs.Add(hash) 410 } 411 case <-p.term: 412 p.Log().Debug("Dropping transaction announcement", "count", len(hashes)) 413 } 414 } 415 416 // SendPooledTransactionsRLP sends requested transactions to the peer and adds the 417 // hashes in its transaction hash set for future reference. 418 // 419 // Note, the method assumes the hashes are correct and correspond to the list of 420 // transactions being sent. 421 func (p *peer) SendPooledTransactionsRLP(hashes []common.Hash, txs []rlp.RawValue) error { 422 // Mark all the transactions as known, but ensure we don't overflow our limits 423 for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) { 424 p.knownTxs.Pop() 425 } 426 for _, hash := range hashes { 427 p.knownTxs.Add(hash) 428 } 429 return p2p.Send(p.rw, PooledTransactionsMsg, txs) 430 } 431 432 // SendNewBlockHashes announces the availability of a number of blocks through 433 // a hash notification. 434 func (p *peer) SendNewBlockHashes(hashes []common.Hash, numbers []uint64) error { 435 // Mark all the block hashes as known, but ensure we don't overflow our limits 436 for p.knownBlocks.Cardinality() > max(0, maxKnownBlocks-len(hashes)) { 437 p.knownBlocks.Pop() 438 } 439 for _, hash := range hashes { 440 p.knownBlocks.Add(hash) 441 } 442 request := make(newBlockHashesData, len(hashes)) 443 for i := 0; i < len(hashes); i++ { 444 request[i].Hash = hashes[i] 445 request[i].Number = numbers[i] 446 } 447 return p2p.Send(p.rw, NewBlockHashesMsg, request) 448 } 449 450 // AsyncSendNewBlockHash queues the availability of a block for propagation to a 451 // remote peer. If the peer's broadcast queue is full, the event is silently 452 // dropped. 453 func (p *peer) AsyncSendNewBlockHash(block *types.Block) { 454 select { 455 case p.queuedBlockAnns <- block: 456 // Mark all the block hash as known, but ensure we don't overflow our limits 457 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 458 p.knownBlocks.Pop() 459 } 460 p.knownBlocks.Add(block.Hash()) 461 default: 462 p.Log().Debug("Dropping block announcement", "number", block.NumberU64(), "hash", block.Hash()) 463 } 464 } 465 466 // SendNewBlock propagates an entire block to a remote peer. 467 func (p *peer) SendNewBlock(block *types.Block, td *big.Int) error { 468 // Mark all the block hash as known, but ensure we don't overflow our limits 469 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 470 p.knownBlocks.Pop() 471 } 472 p.knownBlocks.Add(block.Hash()) 473 return p2p.Send(p.rw, NewBlockMsg, []interface{}{block, td}) 474 } 475 476 // AsyncSendNewBlock queues an entire block for propagation to a remote peer. If 477 // the peer's broadcast queue is full, the event is silently dropped. 478 func (p *peer) AsyncSendNewBlock(block *types.Block, td *big.Int) { 479 select { 480 case p.queuedBlocks <- &propEvent{block: block, td: td}: 481 // Mark all the block hash as known, but ensure we don't overflow our limits 482 for p.knownBlocks.Cardinality() >= maxKnownBlocks { 483 p.knownBlocks.Pop() 484 } 485 p.knownBlocks.Add(block.Hash()) 486 default: 487 p.Log().Debug("Dropping block propagation", "number", block.NumberU64(), "hash", block.Hash()) 488 } 489 } 490 491 // SendBlockHeaders sends a batch of block headers to the remote peer. 492 func (p *peer) SendBlockHeaders(headers []*types.Header) error { 493 return p2p.Send(p.rw, BlockHeadersMsg, headers) 494 } 495 496 // SendBlockBodies sends a batch of block contents to the remote peer. 497 func (p *peer) SendBlockBodies(bodies []*blockBody) error { 498 return p2p.Send(p.rw, BlockBodiesMsg, blockBodiesData(bodies)) 499 } 500 501 // SendBlockBodiesRLP sends a batch of block contents to the remote peer from 502 // an already RLP encoded format. 503 func (p *peer) SendBlockBodiesRLP(bodies []rlp.RawValue) error { 504 return p2p.Send(p.rw, BlockBodiesMsg, bodies) 505 } 506 507 // SendNodeDataRLP sends a batch of arbitrary internal data, corresponding to the 508 // hashes requested. 509 func (p *peer) SendNodeData(data [][]byte) error { 510 return p2p.Send(p.rw, NodeDataMsg, data) 511 } 512 513 // SendReceiptsRLP sends a batch of transaction receipts, corresponding to the 514 // ones requested from an already RLP encoded format. 515 func (p *peer) SendReceiptsRLP(receipts []rlp.RawValue) error { 516 return p2p.Send(p.rw, ReceiptsMsg, receipts) 517 } 518 519 // RequestOneHeader is a wrapper around the header query functions to fetch a 520 // single header. It is used solely by the fetcher. 521 func (p *peer) RequestOneHeader(hash common.Hash) error { 522 p.Log().Debug("Fetching single header", "hash", hash) 523 return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}, Amount: uint64(1), Skip: uint64(0), Reverse: false}) 524 } 525 526 // RequestHeadersByHash fetches a batch of blocks' headers corresponding to the 527 // specified header query, based on the hash of an origin block. 528 func (p *peer) RequestHeadersByHash(origin common.Hash, amount int, skip int, reverse bool) error { 529 p.Log().Debug("Fetching batch of headers", "count", amount, "fromhash", origin, "skip", skip, "reverse", reverse) 530 return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Hash: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse}) 531 } 532 533 // RequestHeadersByNumber fetches a batch of blocks' headers corresponding to the 534 // specified header query, based on the number of an origin block. 535 func (p *peer) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool) error { 536 p.Log().Debug("Fetching batch of headers", "count", amount, "fromnum", origin, "skip", skip, "reverse", reverse) 537 return p2p.Send(p.rw, GetBlockHeadersMsg, &getBlockHeadersData{Origin: hashOrNumber{Number: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse}) 538 } 539 540 // RequestBodies fetches a batch of blocks' bodies corresponding to the hashes 541 // specified. 542 func (p *peer) RequestBodies(hashes []common.Hash) error { 543 p.Log().Debug("Fetching batch of block bodies", "count", len(hashes)) 544 return p2p.Send(p.rw, GetBlockBodiesMsg, hashes) 545 } 546 547 // RequestNodeData fetches a batch of arbitrary data from a node's known state 548 // data, corresponding to the specified hashes. 549 func (p *peer) RequestNodeData(hashes []common.Hash) error { 550 p.Log().Debug("Fetching batch of state data", "count", len(hashes)) 551 return p2p.Send(p.rw, GetNodeDataMsg, hashes) 552 } 553 554 // RequestReceipts fetches a batch of transaction receipts from a remote node. 555 func (p *peer) RequestReceipts(hashes []common.Hash) error { 556 p.Log().Debug("Fetching batch of receipts", "count", len(hashes)) 557 return p2p.Send(p.rw, GetReceiptsMsg, hashes) 558 } 559 560 // RequestTxs fetches a batch of transactions from a remote node. 561 func (p *peer) RequestTxs(hashes []common.Hash) error { 562 p.Log().Debug("Fetching batch of transactions", "count", len(hashes)) 563 return p2p.Send(p.rw, GetPooledTransactionsMsg, hashes) 564 } 565 566 // Handshake executes the xcb protocol handshake, negotiating version number, 567 // network IDs, difficulties, head and genesis blocks. 568 func (p *peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter) error { 569 // Send out own handshake in a new thread 570 errc := make(chan error, 2) 571 572 var ( 573 status63 statusData63 // safe to read after two values have been received from errc 574 status statusData // safe to read after two values have been received from errc 575 ) 576 go func() { 577 switch { 578 case p.version == xcb63: 579 errc <- p2p.Send(p.rw, StatusMsg, &statusData63{ 580 ProtocolVersion: uint32(p.version), 581 NetworkId: network, 582 TD: td, 583 CurrentBlock: head, 584 GenesisBlock: genesis, 585 }) 586 case p.version >= xcb64: 587 errc <- p2p.Send(p.rw, StatusMsg, &statusData{ 588 ProtocolVersion: uint32(p.version), 589 NetworkID: network, 590 TD: td, 591 Head: head, 592 Genesis: genesis, 593 ForkID: forkID, 594 }) 595 default: 596 panic(fmt.Sprintf("unsupported xcb protocol version: %d", p.version)) 597 } 598 }() 599 go func() { 600 switch { 601 case p.version == xcb63: 602 errc <- p.readStatusLegacy(network, &status63, genesis) 603 case p.version >= xcb64: 604 errc <- p.readStatus(network, &status, genesis, forkFilter) 605 default: 606 panic(fmt.Sprintf("unsupported xcb protocol version: %d", p.version)) 607 } 608 }() 609 timeout := time.NewTimer(handshakeTimeout) 610 defer timeout.Stop() 611 for i := 0; i < 2; i++ { 612 select { 613 case err := <-errc: 614 if err != nil { 615 return err 616 } 617 case <-timeout.C: 618 return p2p.DiscReadTimeout 619 } 620 } 621 switch { 622 case p.version == xcb63: 623 p.td, p.head = status63.TD, status63.CurrentBlock 624 case p.version >= xcb64: 625 p.td, p.head = status.TD, status.Head 626 default: 627 panic(fmt.Sprintf("unsupported xcb protocol version: %d", p.version)) 628 } 629 return nil 630 } 631 632 func (p *peer) readStatusLegacy(network uint64, status *statusData63, genesis common.Hash) error { 633 msg, err := p.rw.ReadMsg() 634 if err != nil { 635 return err 636 } 637 if msg.Code != StatusMsg { 638 return errResp(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg) 639 } 640 if msg.Size > protocolMaxMsgSize { 641 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, protocolMaxMsgSize) 642 } 643 // Decode the handshake and make sure everything matches 644 if err := msg.Decode(&status); err != nil { 645 return errResp(ErrDecode, "msg %v: %v", msg, err) 646 } 647 if status.GenesisBlock != genesis { 648 return errResp(ErrGenesisMismatch, "%x (!= %x)", status.GenesisBlock[:8], genesis[:8]) 649 } 650 if status.NetworkId != network { 651 return errResp(ErrNetworkIDMismatch, "%d (!= %d)", status.NetworkId, network) 652 } 653 if int(status.ProtocolVersion) != p.version { 654 return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.version) 655 } 656 return nil 657 } 658 659 func (p *peer) readStatus(network uint64, status *statusData, genesis common.Hash, forkFilter forkid.Filter) error { 660 msg, err := p.rw.ReadMsg() 661 if err != nil { 662 return err 663 } 664 if msg.Code != StatusMsg { 665 return errResp(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg) 666 } 667 if msg.Size > protocolMaxMsgSize { 668 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, protocolMaxMsgSize) 669 } 670 // Decode the handshake and make sure everything matches 671 if err := msg.Decode(&status); err != nil { 672 return errResp(ErrDecode, "msg %v: %v", msg, err) 673 } 674 if status.NetworkID != network { 675 return errResp(ErrNetworkIDMismatch, "%d (!= %d)", status.NetworkID, network) 676 } 677 if int(status.ProtocolVersion) != p.version { 678 return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.version) 679 } 680 if status.Genesis != genesis { 681 return errResp(ErrGenesisMismatch, "%x (!= %x)", status.Genesis, genesis) 682 } 683 if err := forkFilter(status.ForkID); err != nil { 684 return errResp(ErrForkIDRejected, "%v", err) 685 } 686 return nil 687 } 688 689 // String implements fmt.Stringer. 690 func (p *peer) String() string { 691 return fmt.Sprintf("Peer %s [%s]", p.id, 692 fmt.Sprintf("xcb/%2d", p.version), 693 ) 694 } 695 696 // peerSet represents the collection of active peers currently participating in 697 // the Core sub-protocol. 698 type peerSet struct { 699 peers map[string]*peer 700 lock sync.RWMutex 701 closed bool 702 } 703 704 // newPeerSet creates a new peer set to track the active participants. 705 func newPeerSet() *peerSet { 706 return &peerSet{ 707 peers: make(map[string]*peer), 708 } 709 } 710 711 // Register injects a new peer into the working set, or returns an error if the 712 // peer is already known. If a new peer it registered, its broadcast loop is also 713 // started. 714 func (ps *peerSet) Register(p *peer, removePeer func(string)) error { 715 ps.lock.Lock() 716 defer ps.lock.Unlock() 717 718 if ps.closed { 719 return errClosed 720 } 721 if _, ok := ps.peers[p.id]; ok { 722 return errAlreadyRegistered 723 } 724 ps.peers[p.id] = p 725 726 go p.broadcastBlocks(removePeer) 727 go p.broadcastTransactions(removePeer) 728 if p.version >= xcb65 { 729 go p.announceTransactions(removePeer) 730 } 731 return nil 732 } 733 734 // Unregister removes a remote peer from the active set, disabling any further 735 // actions to/from that particular entity. 736 func (ps *peerSet) Unregister(id string) error { 737 ps.lock.Lock() 738 defer ps.lock.Unlock() 739 740 p, ok := ps.peers[id] 741 if !ok { 742 return errNotRegistered 743 } 744 delete(ps.peers, id) 745 p.close() 746 747 return nil 748 } 749 750 // Peer retrieves the registered peer with the given id. 751 func (ps *peerSet) Peer(id string) *peer { 752 ps.lock.RLock() 753 defer ps.lock.RUnlock() 754 755 return ps.peers[id] 756 } 757 758 // Len returns if the current number of peers in the set. 759 func (ps *peerSet) Len() int { 760 ps.lock.RLock() 761 defer ps.lock.RUnlock() 762 763 return len(ps.peers) 764 } 765 766 // PeersWithoutBlock retrieves a list of peers that do not have a given block in 767 // their set of known hashes. 768 func (ps *peerSet) PeersWithoutBlock(hash common.Hash) []*peer { 769 ps.lock.RLock() 770 defer ps.lock.RUnlock() 771 772 list := make([]*peer, 0, len(ps.peers)) 773 for _, p := range ps.peers { 774 if !p.knownBlocks.Contains(hash) { 775 list = append(list, p) 776 } 777 } 778 return list 779 } 780 781 // PeersWithoutTx retrieves a list of peers that do not have a given transaction 782 // in their set of known hashes. 783 func (ps *peerSet) PeersWithoutTx(hash common.Hash) []*peer { 784 ps.lock.RLock() 785 defer ps.lock.RUnlock() 786 787 list := make([]*peer, 0, len(ps.peers)) 788 for _, p := range ps.peers { 789 if !p.knownTxs.Contains(hash) { 790 list = append(list, p) 791 } 792 } 793 return list 794 } 795 796 // BestPeer retrieves the known peer with the currently highest total difficulty. 797 func (ps *peerSet) BestPeer() *peer { 798 ps.lock.RLock() 799 defer ps.lock.RUnlock() 800 801 var ( 802 bestPeer *peer 803 bestTd *big.Int 804 ) 805 for _, p := range ps.peers { 806 if _, td := p.Head(); bestPeer == nil || td.Cmp(bestTd) > 0 { 807 bestPeer, bestTd = p, td 808 } 809 } 810 return bestPeer 811 } 812 813 // Close disconnects all peers. 814 // No new peers can be registered after Close has returned. 815 func (ps *peerSet) Close() { 816 ps.lock.Lock() 817 defer ps.lock.Unlock() 818 819 for _, p := range ps.peers { 820 p.Disconnect(p2p.DiscQuitting) 821 } 822 ps.closed = true 823 }