Skip to content

Commit

Permalink
Merge pull request #2035 from kcalvinalvin/2023-09-25-change-is-sync-…
Browse files Browse the repository at this point in the history
…candidate-behavior

wire, netsync: change isSyncCandidate behavior
  • Loading branch information
Roasbeef authored Dec 9, 2023
2 parents 9091065 + b4992fe commit 55ac06b
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 14 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
11 changes: 11 additions & 0 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 @@ -126,6 +132,11 @@ var orderedSFStrings = []ServiceFlag{
SFNodeNetworkLimited,
}

// HasFlag returns a bool indicating if the service has the given flag.
func (f ServiceFlag) HasFlag(s ServiceFlag) bool {
return f&s == s
}

// String returns the ServiceFlag in human-readable form.
func (f ServiceFlag) String() string {
// No flags are set.
Expand Down
22 changes: 21 additions & 1 deletion wire/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

package wire

import "testing"
import (
"testing"

"github.com/stretchr/testify/require"
)

// TestServiceFlagStringer tests the stringized output for service flag types.
func TestServiceFlagStringer(t *testing.T) {
Expand Down Expand Up @@ -59,3 +63,19 @@ func TestBitcoinNetStringer(t *testing.T) {
}
}
}

func TestHasFlag(t *testing.T) {
tests := []struct {
in ServiceFlag
check ServiceFlag
want bool
}{
{0, SFNodeNetwork, false},
{SFNodeNetwork | SFNodeNetworkLimited | SFNodeWitness, SFNodeBloom, false},
{SFNodeNetwork | SFNodeNetworkLimited | SFNodeWitness, SFNodeNetworkLimited, true},
}

for _, test := range tests {
require.Equal(t, test.want, test.in.HasFlag(test.check))
}
}

0 comments on commit 55ac06b

Please sign in to comment.