-
Notifications
You must be signed in to change notification settings - Fork 396
fix(bitcoind_rpc): properly handle reorgs in FilterIter
#1985
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
base: master
Are you sure you want to change the base?
Conversation
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.
Thanks for picking this up @LagginTimes
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.
It's missing a test for max reorg depth.
Co-authored-by: valued mammal <valuedmammal@protonmail.com>
The test for this is still WIP but I pushed out the changes that resolved the other open comments. |
Co-authored-by: valued mammal <valuedmammal@protonmail.com>
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.
ACK c2ae4da
/// Returns `None` if the remote height is less than the height of this [`FilterIter`]. | ||
pub fn get_tip(&mut self) -> Result<Option<BlockId>, Error> { |
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.
Maybe a little out of scope for this PR, but the documentation here is a little lacking.
get_tip
, as I understand, serves the following purposes:
- Initialize the
FilerIter
. Without calling it,FilterIter
returns nothing. - If it returns
None
, it means we are up to date with remote.
Is this the case?
If so, purpose 2.
is not satisfied because reorgs are not detected by get_tip
.
@ValuedMammal are you able to provide some clarity, thanks!
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.
get_tip
is used to set the start and stop height of a scan and is only necessary to call once per instance of FilterIter. During review I was going to mention that I think get_tip
should actually clear self.blocks
, because I didn't anticipate the user interleaving calls to get_tip
and next
.
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.
@ValuedMammal Thank you for the update.
The internal implementation of FilterIter
implies that it is a single-use structure (construct once, call .next
till end). However, the API design of it implies something different.
What do you think about changing the API to properly represent a "single-use" workflow? I.e. I would change the following:
- Remove or unexpose
add_spk{s}
. - Change constructor methods to also take in spks. Return
None
if there are no spks provided. - Make sure
get_tip
logic is run on the first call tonext
. - Rename
get_tip
toinit
which would return the target height.
(Separate PR of course)
Let me know what you think.
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.
I like this idea, and can make a follow up PR to implement this.
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.
Thanks for taking this forward.
I addressed my own review comments in commit 30e25d1 of evanlinjin:bdk @ filter_iter
. Let me know what you think. Check commit message for rationale.
* Remove `MAX_REORG_DEPTH` check and error variant. For the scenario where the `FilterIter` is of a different network than the receiver, the genesis block will be emitted, thus making the receiver error out. * Fix `Iterator::next` impl so that we only mutate internal state after we are certain that no more errors will be returned. * `Error::NoScripts` is no longer returned since I could not justify a rationale for it. * Refactor `Iterator::next` impl be cleaner.
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.
I'm not convinced that this represents an objective improvement over Musab's PR.
@ValuedMammal are you able to provide more context? I'm assuming you are referring to changes in 071fe40? Here is my justification why these changes are superior:
|
Replaces #1909.
Fixes #1848.
Description
This patch enhances
FilterIter
to robustly detect and handle chain reorgs. Reorgs are detected by checking if the block hash at the current height has changed, or if the block'sprev_blockhash
no longer matches the hash of the block at the previous height. This allows detection of reorgs that occur either at the current height or one block prior.When a reorg is detected, the iterator rewinds up to
MAX_REORG_DEPTH
blocks to locate the most recent common ancestor. It then resets its internal state and resumes scanning from the fork point on the new chain.This update also includes tests that simulate reorgs — including back-to-back reorgs at the same height — and verifies that
FilterIter
correctly switches to the new chain and yields accurate events.Changelog notice
FilterIter
to detect and handle reorgs at the current height or its parent.Checklists
All Submissions:
cargo +nightly fmt
andcargo clippy
before committingNew Features:
Bugfixes: