Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chain: Request block ntfns only after initial sync #2310

Merged
merged 1 commit into from
Dec 1, 2023

Conversation

matheusd
Copy link
Member

@matheusd matheusd commented Dec 1, 2023

Previously, request for notifications about connected blocks were sent to the underlying dcrd instance before the chain was fully synced. This could cause a race issue if the underlying dcrd instance was also performing an initial sync, causing blocks to be connected by the blockConnected handler before the active data filter was loaded, causing transactions to be missed and the wallet's balance to be wrong, requiring a rescan to be fixed.

This could happen, for example, if both the dcrd and dcrwallet processes were started at the same time or if dcrd took just enough time to connect to the network that the wallet was also initialized (for exemple, from within Decrediton).

This fixes the issue by refactoring the initial sync code to only request block notifications after the initial header sync has been completed by the wallet.

Note that, despite a large(ish) diff, this is mostly a code move PR.

One way to reproduce the above issue in simnet is the following:

  • Run dcrd's tmux script to setup a full simnet env
  • Create a new, empty wallet (wallet3)
  • Run, complete the initial sync and generate an address for wallet3
  • Shutdown the wallet
  • Send (but do not mine) 1 DCR from wallet1 to the previously generated wallet3 address
  • Apply the diff below to the current master, to increase the odds of the issue happening
  • Run wallet3 with the diff applied
  • Before the 5 second timeout added by the diff elapses, mine a block that includes the transaction generated above
  • The wallet will not see the transaction and will remain with a zero balance
diff --git a/chain/sync.go b/chain/sync.go
index 0881e218..583cdcb2 100644
--- a/chain/sync.go
+++ b/chain/sync.go
@@ -13,6 +13,7 @@ import (
 	"runtime/trace"
 	"sync"
 	"sync/atomic"
+	"time"
 
 	"decred.org/dcrwallet/v4/errors"
 	"decred.org/dcrwallet/v4/rpc/client/dcrd"
@@ -328,6 +329,12 @@ func (s *Syncer) Run(ctx context.Context) (err error) {
 		return err
 	}
 
+	log.Infof("XXXXXXXXXXXXXXX Gonna wait 5 seconds")
+	for i := 0; i < 5; i++ {
+		time.Sleep(time.Second)
+		log.Infof("XXXXXXXXXXXX %d", i+1)
+	}
+
 	cnet := s.wallet.ChainParams().Net
 	s.fetchHeadersStart()
 	for {

"parent %s not in main chain. Re-requesting "+
"missing headers.", header.BlockHash(),
header.Height, header.PrevBlock)
return s.getHeaders(ctx)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty much the only significant change on this PR.

Given we are moving the notifyblocks request after getHeaders returns during initial sync, there's a chance that we could miss blocks. So if the node sends a block for which we don't have its parent, we restart the getHeaders from scratch to fetch the missing blocks (including the one in this ntfn).

@jrick
Copy link
Member

jrick commented Dec 1, 2023

needs a rebase

Previously, request for notifications about connected blocks were sent
to the underlying dcrd instance before the chain was fully synced.  This
could cause a race issue if the underlying dcrd instance was also
performing an initial sync, causing blocks to be connected by the
blockConnected handler before the active data filter was loaded, causing
transactions to be missed and the wallet's balance to be wrong,
requiring a rescan to be fixed.

This could happen, for example, if both the dcrd and dcrwallet processes
were started at the same time or if dcrd took just enough time to
connect to the network that the wallet was also initialized (for
exemple, from within Decrediton).

This fixes the issue by refactoring the initial sync code to only
request block notifications after the initial header sync has been
completed by the wallet.
@jrick jrick merged commit 9873543 into decred:master Dec 1, 2023
2 checks passed
@matheusd matheusd deleted the rpc-balance-bug branch December 1, 2023 21:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants