Skip to content

Commit e4acd44

Browse files
committed
chain: Wait for dcrd to sync before starting RPC sync
This prevents the wallet from syncing from blockConnected messages when it is connected to a dcrd instance that is not yet as synced as the one the wallet has used in the past. This improves performance by batching the sync work in the initial getHeaders stage and prevents wallet misuse by ensuring the underlying dcrd is also synced to recent blocks. Note that the the case of a new wallet (with recorded tip height 0) connected to a network isolated dcrd instance (header and block height both 0) is explicitly allowed to proceed without waiting. This handles the use-cases of airgapped and empty simnet wallets.
1 parent 25b8ae6 commit e4acd44

File tree

1 file changed

+43
-0
lines changed

1 file changed

+43
-0
lines changed

chain/sync.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"runtime/trace"
1515
"sync"
1616
"sync/atomic"
17+
"time"
1718

1819
"decred.org/dcrwallet/v4/errors"
1920
"decred.org/dcrwallet/v4/rpc/client/dcrd"
@@ -460,6 +461,43 @@ func normalizeAddress(addr string, defaultPort string) (hostport string, err err
460461
return addr, nil
461462
}
462463

464+
// waitRPCSync waits until the underlying node is synced up to (at least) the
465+
// passed height and that is has all blockchain data up to its target header
466+
// height.
467+
func (s *Syncer) waitRPCSync(ctx context.Context, minHeight int64) error {
468+
for {
469+
info, err := s.rpc.GetBlockchainInfo(ctx)
470+
if err != nil {
471+
return err
472+
}
473+
474+
if info.Headers > minHeight {
475+
minHeight = info.Headers
476+
}
477+
if info.Blocks >= minHeight && !info.InitialBlockDownload {
478+
// dcrd is synced.
479+
return nil
480+
}
481+
482+
log.Infof("Waiting dcrd instance to catch up to minimum block "+
483+
"height %d (%d blocks, %d headers, IBS=%v)",
484+
minHeight, info.Blocks, info.Headers, info.InitialBlockDownload)
485+
486+
// Determine when to make the next check. When there are less
487+
// than 100 blocks to go, use a lower check interval.
488+
nextDelay := 10 * time.Second
489+
if minHeight-info.Blocks < 100 {
490+
nextDelay = time.Second
491+
}
492+
493+
select {
494+
case <-time.After(nextDelay):
495+
case <-ctx.Done():
496+
return ctx.Err()
497+
}
498+
}
499+
}
500+
463501
// hashStop is a zero value stop hash for fetching all possible data using
464502
// locators.
465503
var hashStop chainhash.Hash
@@ -570,6 +608,11 @@ func (s *Syncer) Run(ctx context.Context) (err error) {
570608
log.Infof("Transactions synced through block %v height %d", &tipHash, tipHeight)
571609
}
572610

611+
err = s.waitRPCSync(ctx, int64(tipHeight))
612+
if err != nil {
613+
return err
614+
}
615+
573616
if s.wallet.VotingEnabled() {
574617
err = s.rpc.Call(ctx, "notifywinningtickets", nil)
575618
if err != nil {

0 commit comments

Comments
 (0)