-
Notifications
You must be signed in to change notification settings - Fork 36.9k
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
wallet: ignore chainStateFlushed notifications while attaching chain #24984
Conversation
Fixed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With current implementation we don't save the rescan progress and on the next load we will have to start from scratch. Is it possible to save the last processed blocked at shutdown?
a384b55
to
2052e3a
Compare
Yes, that's true. I think it should be possible to call |
Concept ACK
Right, I'm concerned about unexpected behavior. I don't think optimality is important in this case. |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
The wallet already tracks last processed block, why can't we just write that form |
Not sure I understand this right - do you mean why locators are used in general instead of single block hashes? I think that's because we want to be flexible and not dependent on a specific block: There may be a reorg so a given block is no longer part of the chain when the wallet is loaded, or maybe the the wallet called the chainStateFlushed handler manually without the actual chainstate being flushed, and then an unclean shutdown happens so that the wallet would be ahead of the chain at next startup. In any case, any block must be converted to a locator anyway to be stored in Also note that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK 2052e3a. This is a straightforward fix for the bug described in #24487 where a wallet could skip scanning blocks if is shut down in the middle of a sync and a chainStateFlushed notification was received during the sync. It would be nice to write a test for this but probably would be tricky to write.
S3RK raises a great point in #24984 (review) that the wallet doesn't save the scan position during syncs, so if it is interrupted, parts of the scan could be repeated unnecessarily next time the wallet is loaded. This issue would be good to fix, and I created #25010 to track it, but I think it's basically a separate issue with a separate fix. This PR makes that issue more likely to happen, but in the cases it does this, current behavior of skipping unscanned blocks is worse than new behavior of rescanning already-scanned blocks, so in every case this PR should be a strict improvement over the status quo.
ACK 2052e3a |
Agree that "this PR should be a strict improvement over the status quo". The only thing that still slightly worries me is two |
Yes, I'd like that too. the problem is how to deal with the racing condition, timing the shutdown to be during the sync and not after. I played around a bit with bpftrace / uprobes after an idea by @jnewbery (e.g. hook into a function such as
Yes, we currently rely on this to be the case. We aren't only concerned about accidental signals during the sync but also after it, caused by the interrupting signal: In case of a shutdown by SIGINT, Shutdown() in Init will create a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review ACK 2052e3a
If I understand correctly, the problem is that at the end of CWallet::AttachChain()
, CWallet::chainStateFlushed(...)
is called passing the chain tip as parameter, even if abort or shutdown is requested during the wallet scan (CWallet::ScanForWalletTransactions
).
I think this solution achieves the goal of preventing the wallet from being in an inconsistent state by forcing it to write the tip only after the scan completes.
Ideally there would be a functional test for this, but I don't see how to simulate this on regtest.
…hile attaching chain 2052e3a wallet: ignore chainStateFlushed notifications while attaching chain (Martin Zumsande) Pull request description: Fixes bitcoin#24487 When a rescan is performed during `CWallet::AttachChain()` (e.g. when loading an old wallet) but this is interrupted by a shutdown signal, the wallet will currently stop the rescan, receive a `chainStateFlushed` signal, set the saved best block to the tip and shut down. At next startup, the rescan is not continued or repeated because of this. But some blocks have never been scanned by the wallet, which could lead to an incorrect balance. Fix this by ignoring `chainStateFlushed` notifications until the chain is attached. Since `CWallet::chainStateFlushed` is being manually called by `AttachChain()` anyway after finishing with the rescan, it is not a problem if intermediate notifications are ignored. Manual rescans started / aborted by the `rescanblockchain` / `abortrescan` RPCs are not affected by this. I didn't choose alternative ways of fixing this issue that would delay the validationinterface registration or change anything else about the handling of `blockConnected` signals for the reasons mentioned in [this existing comment](https://github.com/bitcoin/bitcoin/blob/master/src/wallet/wallet.cpp#L2937-L2944). ACKs for top commit: achow101: ACK 2052e3a ryanofsky: Code review ACK 2052e3a. This is a straightforward fix for the bug described in bitcoin#24487 where a wallet could skip scanning blocks if is shut down in the middle of a sync and a chainStateFlushed notification was received during the sync. It would be nice to write a test for this but probably would be tricky to write. w0xlt: Code Review ACK bitcoin@2052e3a Tree-SHA512: a6186173d72b26bd4adbf2315e11af365004a723ea5565a0f7b868584dc47c321a6572eafaeb2420bd21eed1c7ad92b47e6218c5eb72313a3c6bee58364e2247
…ing for signals ba10b90 Wallet: Ensure m_attaching_chain is set before registering for signals (Luke Dashjr) Pull request description: Avoids a race where chainStateFlushed could be called before rescanning began, yet rescan gets interrupted or fails Followup for #24984 avoiding a race between registering and setting the flag. ACKs for top commit: mzumsande: Code Review ACK ba10b90 achow101: ACK ba10b90 Tree-SHA512: 1d2fa2db189d3e87f2d0863cf2ab62166094436483f0da16760b1083a4743bf08e476a3277e0d36564213d65dd6f0a1fc16a4bf68d3338c991a14d1de9fc0fee
Github-Pull: bitcoin#24984 Rebased-From: 2052e3a
…egistering for signals ba10b90 Wallet: Ensure m_attaching_chain is set before registering for signals (Luke Dashjr) Pull request description: Avoids a race where chainStateFlushed could be called before rescanning began, yet rescan gets interrupted or fails Followup for bitcoin#24984 avoiding a race between registering and setting the flag. ACKs for top commit: mzumsande: Code Review ACK ba10b90 achow101: ACK ba10b90 Tree-SHA512: 1d2fa2db189d3e87f2d0863cf2ab62166094436483f0da16760b1083a4743bf08e476a3277e0d36564213d65dd6f0a1fc16a4bf68d3338c991a14d1de9fc0fee
Fixes #24487
When a rescan is performed during
CWallet::AttachChain()
(e.g. when loading an old wallet) but this is interrupted by a shutdown signal, the wallet will currently stop the rescan, receive achainStateFlushed
signal, set the saved best block to the tip and shut down. At next startup, the rescan is not continued or repeated because of this. But some blocks have never been scanned by the wallet, which could lead to an incorrect balance.Fix this by ignoring
chainStateFlushed
notifications until the chain is attached. SinceCWallet::chainStateFlushed
is being manually called byAttachChain()
anyway after finishing with the rescan, it is not a problem if intermediate notifications are ignored.Manual rescans started / aborted by the
rescanblockchain
/abortrescan
RPCs are not affected by this.I didn't choose alternative ways of fixing this issue that would delay the validationinterface registration or change anything else about the handling of
blockConnected
signals for the reasons mentioned in this existing comment.