Skip to content

Commit

Permalink
multi: refactor sync status (#2895)
Browse files Browse the repository at this point in the history
* refactor sync status

Use a more details structure for sync status. Add a sync
notification to replace wallet state notifications where only
the sync status has changed. Lower default account and address
gap limits for Decred and make address gap limit configurable.
Add information about address and tx syncing, for after headers
and filters have synced.

* supress unreported block warning during initial sync

* translations
  • Loading branch information
buck54321 authored Aug 5, 2024
1 parent 5701cfc commit 12aeb7c
Show file tree
Hide file tree
Showing 39 changed files with 455 additions and 308 deletions.
44 changes: 17 additions & 27 deletions client/asset/btc/btc.go
Original file line number Diff line number Diff line change
Expand Up @@ -1727,32 +1727,20 @@ func (r *GetBlockchainInfoResult) Syncing() bool {
}

// SyncStatus is information about the blockchain sync status.
func (btc *baseWallet) SyncStatus() (bool, float32, error) {
func (btc *baseWallet) SyncStatus() (*asset.SyncStatus, error) {
ss, err := btc.node.syncStatus()
if err != nil {
return false, 0, err
}

if ss.Target == 0 { // do not say progress = 1
return false, 0, nil
return nil, err
}
if ss.Syncing {
ogTip := atomic.LoadInt64(&btc.tipAtConnect)
totalToSync := ss.Target - int32(ogTip)
var progress float32 = 1
if totalToSync > 0 {
progress = 1 - (float32(ss.Target-ss.Height) / float32(totalToSync))
ss.StartingBlocks = uint64(atomic.LoadInt64(&btc.tipAtConnect))
if ss.Synced {
numPeers, err := btc.node.peerCount()
if err != nil {
return nil, err
}
return false, progress, nil
}

// It looks like we are ready based on syncStatus, but that may just be
// comparing wallet height to known chain height. Now check peers.
numPeers, err := btc.node.peerCount()
if err != nil {
return false, 0, err
ss.Synced = numPeers > 0
}
return numPeers > 0, 1, nil
return ss, nil
}

// OwnsDepositAddress indicates if the provided address can be used
Expand Down Expand Up @@ -4706,15 +4694,17 @@ func (btc *intermediaryWallet) watchBlocks(ctx context.Context) {
syncStatus, err := btc.node.syncStatus()
if err != nil {
btc.log.Errorf("Error retrieving sync status before queuing polled block: %v", err)
} else if syncStatus.Syncing {
} else if !syncStatus.Synced {
blockAllowance *= 10
}
queuedBlock = &polledBlock{
BlockVector: newTip,
queue: time.AfterFunc(blockAllowance, func() {
btc.log.Warnf("Reporting a block found in polling that the wallet apparently "+
"never reported: %d %s. If you see this message repeatedly, it may indicate "+
"an issue with the wallet.", newTip.Height, newTip.Hash)
if ss, _ := btc.SyncStatus(); ss != nil && ss.Synced {
btc.log.Warnf("Reporting a block found in polling that the wallet apparently "+
"never reported: %d %s. If you see this message repeatedly, it may indicate "+
"an issue with the wallet.", newTip.Height, newTip.Hash)
}
btc.reportNewTip(ctx, newTip)
}),
}
Expand Down Expand Up @@ -5929,12 +5919,12 @@ func (btc *intermediaryWallet) syncTxHistory(tip uint64) {
return
}

synced, _, err := btc.SyncStatus()
ss, err := btc.SyncStatus()
if err != nil {
btc.log.Errorf("Error getting sync status: %v", err)
return
}
if !synced {
if !ss.Synced {
return
}

Expand Down
16 changes: 8 additions & 8 deletions client/asset/btc/btc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4277,14 +4277,14 @@ func testSyncStatus(t *testing.T, segwit bool, walletType string) {
node.birthdayTime = msgBlock.Header.Timestamp.Add(-time.Minute) // SPV, wallet birthday is passed
node.mainchain[100] = blkHash // SPV, actually has to reach target

synced, progress, err := wallet.SyncStatus()
ss, err := wallet.SyncStatus()
if err != nil {
t.Fatalf("SyncStatus error (synced expected): %v", err)
}
if !synced {
if !ss.Synced {
t.Fatalf("synced = false")
}
if progress < 1 {
if ss.BlockProgress() < 1 {
t.Fatalf("progress not complete when loading last block")
}

Expand All @@ -4293,7 +4293,7 @@ func testSyncStatus(t *testing.T, segwit bool, walletType string) {
node.getBestBlockHashErr = tErr // spv BestBlock()
node.blockchainMtx.Unlock()
delete(node.mainchain, 100) // force spv to BestBlock() with no wallet block
_, _, err = wallet.SyncStatus()
_, err = wallet.SyncStatus()
if err == nil {
t.Fatalf("SyncStatus error not propagated")
}
Expand All @@ -4308,15 +4308,15 @@ func testSyncStatus(t *testing.T, segwit bool, walletType string) {
Blocks: 150,
}
node.addRawTx(150, makeRawTx([]dex.Bytes{randBytes(1)}, []*wire.TxIn{dummyInput()})) // spv needs this for BestBlock
synced, progress, err = wallet.SyncStatus()
ss, err = wallet.SyncStatus()
if err != nil {
t.Fatalf("SyncStatus error (half-synced): %v", err)
}
if synced {
if ss.Synced {
t.Fatalf("synced = true for 50 blocks to go")
}
if progress > 0.500001 || progress < 0.4999999 {
t.Fatalf("progress out of range. Expected 0.5, got %.2f", progress)
if ss.BlockProgress() > 0.500001 || ss.BlockProgress() < 0.4999999 {
t.Fatalf("progress out of range. Expected 0.5, got %.2f", ss.BlockProgress())
}
}

Expand Down
8 changes: 4 additions & 4 deletions client/asset/btc/electrum.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,13 +367,13 @@ func (btc *ExchangeWalletElectrum) watchBlocks(ctx context.Context) {
// only comparing heights instead of hashes, which means we might
// not notice a reorg to a block at the same height, which is
// unimportant because of how electrum searches for transactions.
stat, err := btc.node.syncStatus()
ss, err := btc.node.syncStatus()
if err != nil {
btc.log.Errorf("failed to get sync status: %w", err)
continue
}

sameTip := currentTip.Height == int64(stat.Height)
sameTip := currentTip.Height == int64(ss.Blocks)
if sameTip {
// Could have actually been a reorg to different block at same
// height. We'll report a new tip block on the next block.
Expand Down Expand Up @@ -419,12 +419,12 @@ func (btc *ExchangeWalletElectrum) syncTxHistory(tip uint64) {
return
}

synced, _, err := btc.SyncStatus()
ss, err := btc.SyncStatus()
if err != nil {
btc.log.Errorf("Error getting sync status: %v", err)
return
}
if !synced {
if !ss.Synced {
return
}

Expand Down
10 changes: 5 additions & 5 deletions client/asset/btc/electrum_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -964,15 +964,15 @@ func (ew *electrumWallet) ownsAddress(addr btcutil.Address) (bool, error) {
}

// part of the btc.Wallet interface
func (ew *electrumWallet) syncStatus() (*SyncStatus, error) {
func (ew *electrumWallet) syncStatus() (*asset.SyncStatus, error) {
info, err := ew.wallet.GetInfo(ew.ctx)
if err != nil {
return nil, err
}
return &SyncStatus{
Target: int32(info.ServerHeight),
Height: int32(info.SyncHeight),
Syncing: !info.Connected || info.SyncHeight < info.ServerHeight,
return &asset.SyncStatus{
Synced: info.Connected && info.SyncHeight >= info.ServerHeight,
TargetHeight: uint64(info.ServerHeight),
Blocks: uint64(info.SyncHeight),
}, nil
}

Expand Down
6 changes: 3 additions & 3 deletions client/asset/btc/livetest/regnet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ func TestWallet(t *testing.T) {
time.Sleep(time.Second * 3)

for {
synced, progress, err := w.SyncStatus()
ss, err := w.SyncStatus()
if err != nil {
return fmt.Errorf("SyncStatus error: %w", err)
}
if synced {
if ss.Synced {
break
}
fmt.Printf("%s sync progress %.1f \n", name, progress*100)
fmt.Printf("%s sync progress %.1f \n", name, ss.BlockProgress()*100)
time.Sleep(time.Second)
}

Expand Down
11 changes: 6 additions & 5 deletions client/asset/btc/rpcclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -982,15 +982,16 @@ func (wc *rpcClient) ownsAddress(addr btcutil.Address) (bool, error) {
}

// syncStatus is information about the blockchain sync status.
func (wc *rpcClient) syncStatus() (*SyncStatus, error) {
func (wc *rpcClient) syncStatus() (*asset.SyncStatus, error) {
chainInfo, err := wc.getBlockchainInfo()
if err != nil {
return nil, fmt.Errorf("getblockchaininfo error: %w", err)
}
return &SyncStatus{
Target: int32(chainInfo.Headers),
Height: int32(chainInfo.Blocks),
Syncing: chainInfo.Syncing(),
synced := !chainInfo.Syncing()
return &asset.SyncStatus{
Synced: synced,
TargetHeight: uint64(chainInfo.Headers),
Blocks: uint64(chainInfo.Blocks),
}, nil
}

Expand Down
23 changes: 14 additions & 9 deletions client/asset/btc/spv_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ func (w *spvWallet) syncHeight() int32 {
// the chain service sync stage that comes before the wallet has performed any
// address recovery/rescan, and switch to the wallet's sync height when it
// reports non-zero height.
func (w *spvWallet) syncStatus() (*SyncStatus, error) {
func (w *spvWallet) syncStatus() (*asset.SyncStatus, error) {
// Chain service headers (block and filter) height.
chainBlk, err := w.cl.BestBlock()
if err != nil {
Expand All @@ -422,6 +422,10 @@ func (w *spvWallet) syncStatus() (*SyncStatus, error) {
target = atomic.LoadInt32(&w.syncTarget)
}

if target == 0 {
return new(asset.SyncStatus), nil
}

var synced bool
var blk *BlockVector
// Wallet address manager sync height.
Expand All @@ -434,10 +438,11 @@ func (w *spvWallet) syncStatus() (*SyncStatus, error) {
if walletBlock.Height == 0 {
// The wallet is about to start its sync, so just return the last
// chain service height prior to wallet birthday until it begins.
return &SyncStatus{
Target: target,
Height: atomic.LoadInt32(&w.lastPrenatalHeight),
Syncing: true,
h := atomic.LoadInt32(&w.lastPrenatalHeight)
return &asset.SyncStatus{
Synced: false,
TargetHeight: uint64(target),
Blocks: uint64(h),
}, nil
}
blk = &BlockVector{
Expand All @@ -459,10 +464,10 @@ func (w *spvWallet) syncStatus() (*SyncStatus, error) {
w.tipChan <- blk
}

return &SyncStatus{
Target: target,
Height: int32(blk.Height),
Syncing: !synced,
return &asset.SyncStatus{
Synced: synced,
TargetHeight: uint64(target),
Blocks: uint64(blk.Height),
}, nil
}

Expand Down
7 changes: 0 additions & 7 deletions client/asset/btc/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,3 @@ func (r *SwapReceipt) String() string {
func (r *SwapReceipt) SignedRefund() dex.Bytes {
return r.SignedRefundBytes
}

// SyncStatus is the current synchronization state of the node.
type SyncStatus struct {
Target int32 `json:"target"`
Height int32 `json:"height"`
Syncing bool `json:"syncing"`
}
2 changes: 1 addition & 1 deletion client/asset/btc/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type Wallet interface {
walletUnlock(pw []byte) error
walletLock() error
locked() bool
syncStatus() (*SyncStatus, error)
syncStatus() (*asset.SyncStatus, error)
peerCount() (uint32, error)
swapConfirmations(txHash *chainhash.Hash, vout uint32, contract []byte, startTime time.Time) (confs uint32, spent bool, err error)
getBestBlockHeader() (*BlockHeader, error)
Expand Down
1 change: 1 addition & 0 deletions client/asset/dcr/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type walletConfig struct {
RedeemConfTarget uint64 `ini:"redeemconftarget"`
ActivelyUsed bool `ini:"special_activelyUsed"` //injected by core
ApiFeeFallback bool `ini:"apifeefallback"`
GapLimit uint32 `ini:"gaplimit"`
}

type rpcConfig struct {
Expand Down
Loading

0 comments on commit 12aeb7c

Please sign in to comment.