|
29 | 29 | import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; |
30 | 30 | import org.hyperledger.besu.ethereum.p2p.peers.Peer; |
31 | 31 | import org.hyperledger.besu.ethereum.p2p.peers.PeerId; |
32 | | -import org.hyperledger.besu.ethereum.p2p.rlpx.ConnectCallback; |
33 | 32 | import org.hyperledger.besu.ethereum.p2p.rlpx.RlpxAgent; |
34 | 33 | import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection; |
35 | 34 | import org.hyperledger.besu.ethereum.p2p.rlpx.wire.PeerClientName; |
@@ -557,80 +556,95 @@ public String toString() { |
557 | 556 |
|
558 | 557 | private void ethPeerStatusExchanged(final EthPeer peer) { |
559 | 558 | // We have a connection to a peer that is on the right chain and is willing to connect to us. |
560 | | - // Find out what the EthPeer block height is and whether it can serve snap data (if we are doing |
561 | | - // snap sync) |
562 | 559 | LOG.debug("Peer {} status exchanged", peer); |
563 | 560 | assert tracker != null : "ChainHeadTracker must be set before EthPeers can be used"; |
564 | | - CompletableFuture<BlockHeader> future = tracker.getBestHeaderFromPeer(peer); |
565 | | - |
566 | | - future.whenComplete( |
567 | | - (peerHeadBlockHeader, error) -> { |
568 | | - if (peerHeadBlockHeader == null) { |
569 | | - LOG.debug( |
570 | | - "Failed to retrieve chain head info. Disconnecting {}... {}", |
571 | | - peer.getLoggableId(), |
572 | | - error); |
573 | | - peer.disconnect( |
574 | | - DisconnectMessage.DisconnectReason.USELESS_PEER_FAILED_TO_RETRIEVE_CHAIN_HEAD); |
575 | | - } else { |
576 | | - |
577 | | - // we can check trailing peers now |
578 | | - final TrailingPeerRequirements trailingPeerRequirements = |
579 | | - trailingPeerRequirementsSupplier.get(); |
580 | | - if (trailingPeerRequirements != null) { |
581 | | - if (peer.chainState().getEstimatedHeight() |
582 | | - < trailingPeerRequirements.getMinimumHeightToBeUpToDate()) { |
583 | | - if (!(getNumTrailingPeers(trailingPeerRequirements.getMinimumHeightToBeUpToDate()) |
584 | | - < trailingPeerRequirements.getMaxTrailingPeers())) { |
585 | | - LOG.atTrace() |
586 | | - .setMessage( |
587 | | - "Adding trailing peer {} would exceed max trailing peers {}. Disconnecting...") |
588 | | - .addArgument(peer.getLoggableId()) |
589 | | - .addArgument(trailingPeerRequirements.getMaxTrailingPeers()) |
590 | | - .log(); |
591 | | - peer.disconnect( |
592 | | - DisconnectMessage.DisconnectReason.USELESS_PEER_EXCEEDS_TRAILING_PEERS); |
593 | | - return; |
594 | | - } |
595 | | - } |
596 | | - } |
597 | 561 |
|
598 | | - peer.chainState().updateHeightEstimate(peerHeadBlockHeader.getNumber()); |
599 | | - CompletableFuture<Void> isServingSnapFuture; |
600 | | - if (syncMode == SyncMode.SNAP || syncMode == SyncMode.CHECKPOINT) { |
601 | | - // even if we have finished the snap sync, we still want to know if the peer is a snap |
602 | | - // server |
603 | | - isServingSnapFuture = |
604 | | - CompletableFuture.runAsync( |
605 | | - () -> { |
606 | | - try { |
607 | | - checkIsSnapServer(peer, peerHeadBlockHeader); |
608 | | - } catch (Exception e) { |
609 | | - throw new RuntimeException(e); |
610 | | - } |
611 | | - }); |
| 562 | + // Handle chain head tracking based on protocol compatibility. |
| 563 | + if (EthProtocol.isEth69Compatible(peer.getMaxAgreedCapability())) { |
| 564 | + // For Eth69-compatible peers, the chain head information is included in the status message. |
| 565 | + // Skip fetching the chain head separately and directly check trailing peer requirements. |
| 566 | + checkTrailingPeerRequirements(peer); |
| 567 | + } else { |
| 568 | + // For non-Eth69-compatible peers, fetch the chain head before checking trailing requirements. |
| 569 | + CompletableFuture<BlockHeader> future = tracker.getBestHeaderFromPeer(peer); |
| 570 | + future.whenComplete( |
| 571 | + (peerHeadBlockHeader, error) -> { |
| 572 | + // If we successfully retrieved the chain head, check trailing peer requirements and |
| 573 | + // update |
| 574 | + // the peer's estimated height. |
| 575 | + if (peerHeadBlockHeader != null) { |
| 576 | + checkTrailingPeerRequirements(peer); |
| 577 | + peer.chainState().updateHeightEstimate(peerHeadBlockHeader.getNumber()); |
612 | 578 | } else { |
613 | | - isServingSnapFuture = CompletableFuture.completedFuture(null); |
| 579 | + LOG.debug( |
| 580 | + "Failed to retrieve chain head info. Disconnecting {}... {}", |
| 581 | + peer.getLoggableId(), |
| 582 | + error); |
| 583 | + peer.disconnect( |
| 584 | + DisconnectMessage.DisconnectReason.USELESS_PEER_FAILED_TO_RETRIEVE_CHAIN_HEAD); |
614 | 585 | } |
615 | | - isServingSnapFuture.thenRun( |
616 | | - () -> { |
617 | | - if (!peer.getConnection().isDisconnected() && addPeerToEthPeers(peer)) { |
618 | | - connectedPeersCounter.inc(); |
619 | | - connectCallbacks.forEach(cb -> cb.onPeerConnected(peer)); |
620 | | - } |
621 | | - }); |
| 586 | + }); |
| 587 | + } |
| 588 | + |
| 589 | + // If we are doing snap sync, check if the peer is a snap server |
| 590 | + checkSnapServer(peer); |
| 591 | + } |
| 592 | + |
| 593 | + private void checkTrailingPeerRequirements(final EthPeer peer) { |
| 594 | + // we can check trailing peers now |
| 595 | + final TrailingPeerRequirements trailingPeerRequirements = |
| 596 | + trailingPeerRequirementsSupplier.get(); |
| 597 | + if (trailingPeerRequirements != null) { |
| 598 | + if (peer.chainState().getEstimatedHeight() |
| 599 | + < trailingPeerRequirements.getMinimumHeightToBeUpToDate()) { |
| 600 | + if (!(getNumTrailingPeers(trailingPeerRequirements.getMinimumHeightToBeUpToDate()) |
| 601 | + < trailingPeerRequirements.getMaxTrailingPeers())) { |
| 602 | + LOG.atTrace() |
| 603 | + .setMessage( |
| 604 | + "Adding trailing peer {} would exceed max trailing peers {}. Disconnecting...") |
| 605 | + .addArgument(peer.getLoggableId()) |
| 606 | + .addArgument(trailingPeerRequirements.getMaxTrailingPeers()) |
| 607 | + .log(); |
| 608 | + peer.disconnect(DisconnectMessage.DisconnectReason.USELESS_PEER_EXCEEDS_TRAILING_PEERS); |
| 609 | + } |
| 610 | + } |
| 611 | + } |
| 612 | + } |
| 613 | + |
| 614 | + private void checkSnapServer(final EthPeer peer) { |
| 615 | + CompletableFuture<Void> isServingSnapFuture; |
| 616 | + if (syncMode == SyncMode.SNAP || syncMode == SyncMode.CHECKPOINT) { |
| 617 | + // even if we have finished the snap sync, we still want to know if the peer is a snap |
| 618 | + // server |
| 619 | + isServingSnapFuture = |
| 620 | + CompletableFuture.runAsync( |
| 621 | + () -> { |
| 622 | + try { |
| 623 | + checkIsSnapServer(peer); |
| 624 | + } catch (Exception e) { |
| 625 | + throw new RuntimeException(e); |
| 626 | + } |
| 627 | + }); |
| 628 | + } else { |
| 629 | + isServingSnapFuture = CompletableFuture.completedFuture(null); |
| 630 | + } |
| 631 | + isServingSnapFuture.thenRun( |
| 632 | + () -> { |
| 633 | + if (!peer.getConnection().isDisconnected() && addPeerToEthPeers(peer)) { |
| 634 | + connectedPeersCounter.inc(); |
| 635 | + connectCallbacks.forEach(cb -> cb.onPeerConnected(peer)); |
622 | 636 | } |
623 | 637 | }); |
624 | 638 | } |
625 | 639 |
|
626 | | - private void checkIsSnapServer(final EthPeer peer, final BlockHeader peersHeadBlockHeader) { |
| 640 | + private void checkIsSnapServer(final EthPeer peer) { |
627 | 641 | if (peer.getAgreedCapabilities().contains(SnapProtocol.SNAP1)) { |
628 | 642 | if (snapServerChecker != null) { |
629 | 643 | // set that peer is a snap server for doing the test |
630 | 644 | peer.setIsServingSnap(true); |
631 | 645 | Boolean isServer; |
632 | 646 | try { |
633 | | - isServer = snapServerChecker.check(peer, peersHeadBlockHeader).get(6L, TimeUnit.SECONDS); |
| 647 | + isServer = snapServerChecker.check(peer).get(6L, TimeUnit.SECONDS); |
634 | 648 | } catch (Exception e) { |
635 | 649 | LOG.atTrace() |
636 | 650 | .setMessage("Error checking if peer {} is a snap server. Setting to false.") |
|
0 commit comments