Skip to content

Commit a6ea571

Browse files
client/core: check if wallet is synchronized for spend actions
1 parent f1de923 commit a6ea571

5 files changed

Lines changed: 55 additions & 19 deletions

File tree

client/core/bond.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -446,10 +446,10 @@ func (c *Core) postRequiredBonds(dc *dexConnection, cfg *dexBondCfg, state *dexA
446446
c.log.Errorf("failed to unlock bond asset wallet %v: %v", unbip(state.bondAssetID), err)
447447
return
448448
}
449-
if !wallet.synchronized() {
450-
c.log.Warnf("Wallet %v is not yet synchronized with the network. Cannot post new bonds yet.",
451-
unbip(state.bondAssetID))
452-
return // otherwise we might double spend if the wallet keys were used elsewhere
449+
err = wallet.checkPeersAndSyncStatus()
450+
if err != nil {
451+
c.log.Errorf("Cannot post new bonds yet. %v", err)
452+
return
453453
}
454454

455455
// For the max bonded limit, we'll normalize all bonds to the
@@ -1075,8 +1075,9 @@ func (c *Core) PostBond(form *PostBondForm) (*PostBondResult, error) {
10751075
if _, ok := wallet.Wallet.(asset.Bonder); !ok { // will fail in MakeBondTx, but assert early
10761076
return nil, fmt.Errorf("wallet %v is not an asset.Bonder", bondAssetSymbol)
10771077
}
1078-
if !wallet.synchronized() { // otherwise we might double spend if the wallet keys were used elsewhere
1079-
return nil, fmt.Errorf("wallet %v is not synchronized", unbip(bondAssetID))
1078+
err = wallet.checkPeersAndSyncStatus()
1079+
if err != nil {
1080+
return nil, err
10801081
}
10811082

10821083
// Check the app password.

client/core/core.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5324,6 +5324,10 @@ func (c *Core) Send(pw []byte, assetID uint32, value uint64, address string, sub
53245324
return nil, err
53255325
}
53265326

5327+
if err = wallet.checkPeersAndSyncStatus(); err != nil {
5328+
return nil, err
5329+
}
5330+
53275331
var coin asset.Coin
53285332
feeSuggestion := c.feeSuggestionAny(assetID)
53295333
if !subtract {
@@ -5379,6 +5383,11 @@ func (c *Core) ApproveToken(appPW []byte, assetID uint32, dexAddr string, onConf
53795383
return "", err
53805384
}
53815385

5386+
err = wallet.checkPeersAndSyncStatus()
5387+
if err != nil {
5388+
return "", err
5389+
}
5390+
53825391
dex, connected, err := c.dex(dexAddr)
53835392
if err != nil {
53845393
return "", err
@@ -5424,6 +5433,11 @@ func (c *Core) UnapproveToken(appPW []byte, assetID uint32, version uint32) (str
54245433
return "", err
54255434
}
54265435

5436+
err = wallet.checkPeersAndSyncStatus()
5437+
if err != nil {
5438+
return "", err
5439+
}
5440+
54275441
onConfirm := func() {
54285442
go c.notify(newTokenApprovalNote(wallet.state()))
54295443
}
@@ -10358,15 +10372,24 @@ func (c *Core) saveDisabledRateSources() {
1035810372
}
1035910373
}
1036010374

10361-
func (c *Core) shieldedWallet(assetID uint32) (asset.ShieldedWallet, error) {
10375+
func (c *Core) shieldedWallet(assetID uint32, forFundTransfer ...bool) (asset.ShieldedWallet, error) {
1036210376
w, found := c.wallet(assetID)
1036310377
if !found {
1036410378
return nil, fmt.Errorf("no %s wallet", unbip(assetID))
1036510379
}
10380+
1036610381
sw, is := w.Wallet.(asset.ShieldedWallet)
1036710382
if !is {
1036810383
return nil, fmt.Errorf("%s wallet is not a shielded wallet", unbip(assetID))
1036910384
}
10385+
10386+
// Check if this wallet can send funds at the moment.
10387+
if len(forFundTransfer) > 0 && forFundTransfer[0] {
10388+
if err := w.checkPeersAndSyncStatus(); err != nil {
10389+
return nil, err
10390+
}
10391+
}
10392+
1037010393
return sw, nil
1037110394
}
1037210395

@@ -10393,7 +10416,7 @@ func (c *Core) NewShieldedAddress(assetID uint32) (string, error) {
1039310416

1039410417
// ShieldFunds moves funds from the transparent account to the shielded account.
1039510418
func (c *Core) ShieldFunds(assetID uint32, amt uint64) ([]byte, error) {
10396-
sw, err := c.shieldedWallet(assetID)
10419+
sw, err := c.shieldedWallet(assetID, true)
1039710420
if err != nil {
1039810421
return nil, err
1039910422
}
@@ -10403,7 +10426,7 @@ func (c *Core) ShieldFunds(assetID uint32, amt uint64) ([]byte, error) {
1040310426
// UnshieldFunds moves funds from the shielded account to the transparent
1040410427
// account.
1040510428
func (c *Core) UnshieldFunds(assetID uint32, amt uint64) ([]byte, error) {
10406-
sw, err := c.shieldedWallet(assetID)
10429+
sw, err := c.shieldedWallet(assetID, true)
1040710430
if err != nil {
1040810431
return nil, err
1040910432
}
@@ -10419,7 +10442,7 @@ func (c *Core) SendShielded(appPW []byte, assetID uint32, toAddr string, amt uin
1041910442
return nil, fmt.Errorf("password error: %w", err)
1042010443
}
1042110444

10422-
sw, err := c.shieldedWallet(assetID)
10445+
sw, err := c.shieldedWallet(assetID, true)
1042310446
if err != nil {
1042410447
return nil, err
1042510448
}

client/core/core_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2779,6 +2779,13 @@ func TestSend(t *testing.T) {
27792779
if tWallet.sendFeeSuggestion != feeRate {
27802780
t.Fatalf("unexpected fee rate from FeeRater. wanted %d, got %d", feeRate, tWallet.sendFeeSuggestion)
27812781
}
2782+
2783+
// wallet is not synced
2784+
wallet.synced = false
2785+
_, err = tCore.Send(tPW, tUTXOAssetA.ID, 1e8, address, false)
2786+
if err == nil {
2787+
t.Fatalf("Expected error for a non-synchronized wallet")
2788+
}
27822789
}
27832790

27842791
func trade(t *testing.T, async bool) {

client/core/trade.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2903,12 +2903,8 @@ func (t *trackedTrade) confirmRedemption(match *matchTracker) (bool, error) {
29032903
// In some cases the wallet will need to send a new redeem transaction.
29042904
toWallet := t.wallets.toWallet
29052905

2906-
if toWallet.peerCount < 1 {
2907-
return false, fmt.Errorf("%s wallet has no peers", unbip(toWallet.AssetID))
2908-
}
2909-
2910-
if !toWallet.synchronized() {
2911-
return false, fmt.Errorf("%s still syncing", unbip(toWallet.AssetID))
2906+
if err := toWallet.checkPeersAndSyncStatus(); err != nil {
2907+
return false, err
29122908
}
29132909

29142910
didUnlock, err := toWallet.refreshUnlock()

client/core/wallet.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,20 @@ func (w *xcWallet) connected() bool {
365365
return w.hookedUp
366366
}
367367

368-
// synchronized is true if the wallet had been synchronized with the network.
369-
func (w *xcWallet) synchronized() bool {
368+
// checkPeersAndSyncStatus checks that the wallet is synced, and has peers
369+
// otherwise we might double spend if the wallet keys were used elsewhere. This
370+
// should be checked before attempting to send funds but does not replace any
371+
// other checks that may be required.
372+
func (w *xcWallet) checkPeersAndSyncStatus() error {
370373
w.mtx.RLock()
371374
defer w.mtx.RUnlock()
372-
return w.synced
375+
if w.peerCount < 1 {
376+
return fmt.Errorf("%s wallet has no connected peers", unbip(w.AssetID))
377+
}
378+
if !w.synced {
379+
return fmt.Errorf("%s wallet is not synchronized", unbip(w.AssetID))
380+
}
381+
return nil
373382
}
374383

375384
// Connect calls the dex.Connector's Connect method, sets the xcWallet.hookedUp

0 commit comments

Comments
 (0)