Skip to content

Commit

Permalink
netsync: change isSyncCandidate behavior to include pruned nodes
Browse files Browse the repository at this point in the history
isSyncCandidate is now changed to return true even if the peer is a
pruned node if and only if our chaintip is within 288 blocks of the
peer.

Rationale:
Pruned nodes that signal NODE_NETWORK_LIMITED MUST serve 288 blocks from
their chaintip.  If our chaintip is within that range, this peer can be
a sync candidate even if they aren't an archival node.
  • Loading branch information
kcalvinalvin committed Nov 7, 2023
1 parent a09e7b2 commit b4992fe
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 19 deletions.
61 changes: 48 additions & 13 deletions netsync/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,20 +397,55 @@ func (sm *SyncManager) isSyncCandidate(peer *peerpkg.Peer) bool {
if host != "127.0.0.1" && host != "localhost" {
return false
}
} else {
// The peer is not a candidate for sync if it's not a full
// node. Additionally, if the segwit soft-fork package has
// activated, then the peer must also be upgraded.
segwitActive, err := sm.chain.IsDeploymentActive(chaincfg.DeploymentSegwit)
if err != nil {
log.Errorf("Unable to query for segwit "+
"soft-fork state: %v", err)
}
nodeServices := peer.Services()
if nodeServices&wire.SFNodeNetwork != wire.SFNodeNetwork ||
(segwitActive && !peer.IsWitnessEnabled()) {

// Candidate if all checks passed.
return true
}

// If the segwit soft-fork package has activated, then the peer must
// also be upgraded.
segwitActive, err := sm.chain.IsDeploymentActive(
chaincfg.DeploymentSegwit,
)
if err != nil {
log.Errorf("Unable to query for segwit soft-fork state: %v",
err)
}

if segwitActive && !peer.IsWitnessEnabled() {
return false
}

var (
nodeServices = peer.Services()
fullNode = nodeServices.HasFlag(wire.SFNodeNetwork)
prunedNode = nodeServices.HasFlag(wire.SFNodeNetworkLimited)
)

switch {
case fullNode:
// Node is a sync candidate if it has all the blocks.

case prunedNode:
// Even if the peer is pruned, if they have the node network
// limited flag, they are able to serve 2 days worth of blocks
// from the current tip. Therefore, check if our chaintip is
// within that range.
bestHeight := sm.chain.BestSnapshot().Height
peerLastBlock := peer.LastBlock()

// bestHeight+1 as we need the peer to serve us the next block,
// not the one we already have.
if bestHeight+1 <=
peerLastBlock-wire.NodeNetworkLimitedBlockThreshold {

return false
}

default:
// If the peer isn't an archival node, and it's not signaling
// NODE_NETWORK_LIMITED, we can't sync off of this node.
return false
}

// Candidate if all checks passed.
Expand All @@ -428,7 +463,7 @@ func (sm *SyncManager) handleNewPeerMsg(peer *peerpkg.Peer) {

log.Infof("New valid peer %s (%s)", peer, peer.UserAgent())

// Initialize the peer state
// Initialize the peer state.
isSyncCandidate := sm.isSyncCandidate(peer)
sm.peerStates[peer] = &peerSyncState{
syncCandidate: isSyncCandidate,
Expand Down
12 changes: 6 additions & 6 deletions wire/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ const (
AddrV2Version uint32 = 70016
)

const (
// NodeNetworkLimitedBlockThreshold is the number of blocks that a node
// broadcasting SFNodeNetworkLimited MUST be able to serve from the tip.
NodeNetworkLimitedBlockThreshold = 288
)

// ServiceFlag identifies services supported by a bitcoin peer.
type ServiceFlag uint64

Expand Down Expand Up @@ -156,12 +162,6 @@ func (f ServiceFlag) String() string {
return s
}

const (
// NodeNetworkLimitedBlockThreshold is the number of blocks that a node
// broadcasting SFNodeNetworkLimited MUST be able to serve from the tip.
NodeNetworkLimitedBlockThreshold = 288
)

// BitcoinNet represents which bitcoin network a message belongs to.
type BitcoinNet uint32

Expand Down

0 comments on commit b4992fe

Please sign in to comment.