Skip to content

Commit 7830dd6

Browse files
committed
[release-v2.0] Attempt cxns to >=3 mixing-capable peers
Similar to dcrd, we want SPV wallets to maintain a minimum number of peers that support the mixing protocol version. This will be especially important after dcrwallet is updated to a mixclient branch that submits PR messages over the entire duration before the epoch occurs, as any errors for failed message sends due to not having a single mixing-capable peer connected would be delayed far into the future. Backport of 62c10d5.
1 parent fee6056 commit 7830dd6

File tree

1 file changed

+43
-5
lines changed

1 file changed

+43
-5
lines changed

spv/sync.go

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ import (
3434
// they do not provide each of these services.
3535
const reqSvcs = wire.SFNodeNetwork
3636

37+
const (
38+
targetPeerCount = 8
39+
40+
// Require a subset of all connected outbounded peers to meet some
41+
// minimum protocol version.
42+
minVersion = wire.MixVersion
43+
minVersionTarget = 3
44+
)
45+
3746
// Syncer implements wallet synchronization services by over the Decred wire
3847
// protocol using Simplified Payment Verification (SPV) with compact filters.
3948
type Syncer struct {
@@ -451,9 +460,12 @@ func (s *Syncer) peerCandidate(svcs wire.ServiceFlag) (*addrmgr.NetAddress, erro
451460
return nil, errors.New("no addresses")
452461
}
453462

463+
var errBreaksMinVersionTarget = errors.New("peer uses too low version to satisify " +
464+
"minimum target version count")
465+
454466
// connectAndRunPeer connects to and runs the syncing process with the specified
455467
// peer. It blocks until the peer disconnects and logs any errors.
456-
func (s *Syncer) connectAndRunPeer(ctx context.Context, raddr string) {
468+
func (s *Syncer) connectAndRunPeer(ctx context.Context, raddr string, persistent bool) {
457469
// Attempt connection to peer.
458470
rp, err := s.lp.ConnectOutbound(ctx, raddr, reqSvcs)
459471
if err != nil {
@@ -467,18 +479,24 @@ func (s *Syncer) connectAndRunPeer(ctx context.Context, raddr string) {
467479
}
468480
return
469481
}
470-
log.Infof("New peer %v %v %v", raddr, rp.UA(), rp.Services())
471482

472483
// Track peer as running as opposed to attempting connection.
473484
s.remotesMu.Lock()
474485
delete(s.connectingRemotes, raddr)
486+
if !persistent && s.breaksMinVersionTarget(rp) {
487+
s.remotesMu.Unlock()
488+
log.Debugf("Disconnecting %v: %v", raddr, errBreaksMinVersionTarget)
489+
rp.Disconnect(errBreaksMinVersionTarget)
490+
return
491+
}
475492
s.remotes[raddr] = rp
476493
n := len(s.remotes)
477494
if s.remoteAvailable != nil {
478495
close(s.remoteAvailable)
479496
s.remoteAvailable = nil
480497
}
481498
s.remotesMu.Unlock()
499+
log.Infof("New peer %v %v version=%d %v", raddr, rp.UA(), rp.Pver(), rp.Services())
482500
s.peerConnected(n, raddr)
483501

484502
// Alert disconnection once this peer is done.
@@ -514,9 +532,29 @@ func (s *Syncer) connectAndRunPeer(ctx context.Context, raddr string) {
514532
}
515533
}
516534

535+
func (s *Syncer) breaksMinVersionTarget(rp *p2p.RemotePeer) bool {
536+
if rp.Pver() >= minVersion {
537+
return false
538+
}
539+
n := len(s.remotes)
540+
if n < targetPeerCount-minVersionTarget {
541+
return false
542+
}
543+
var meetsMin int
544+
for _, rp := range s.remotes {
545+
if rp.Pver() >= minVersion {
546+
meetsMin++
547+
if meetsMin == minVersionTarget {
548+
return false
549+
}
550+
}
551+
}
552+
return true
553+
}
554+
517555
func (s *Syncer) connectToPersistent(ctx context.Context, raddr string) error {
518556
for {
519-
s.connectAndRunPeer(ctx, raddr)
557+
s.connectAndRunPeer(ctx, raddr, true)
520558

521559
// Retry persistent peer after 5 seconds.
522560
select {
@@ -531,7 +569,7 @@ func (s *Syncer) connectToCandidates(ctx context.Context) error {
531569
var wg sync.WaitGroup
532570
defer wg.Wait()
533571

534-
sem := make(chan struct{}, 8)
572+
sem := make(chan struct{}, targetPeerCount)
535573
for {
536574
if ctx.Err() != nil {
537575
return ctx.Err()
@@ -555,7 +593,7 @@ func (s *Syncer) connectToCandidates(ctx context.Context) error {
555593
wg.Add(1)
556594
go func() {
557595
raddr := na.String()
558-
s.connectAndRunPeer(ctx, raddr)
596+
s.connectAndRunPeer(ctx, raddr, false)
559597
wg.Done()
560598
<-sem
561599
}()

0 commit comments

Comments
 (0)