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