-
Notifications
You must be signed in to change notification settings - Fork 321
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
The TxGraph::missing_heights
implementation is problematic.
#1354
Comments
Tests written can be based on #1171 |
I do not know what the root cause for the forever unconfirmed one, but I think I can make the test first, and then fix the issue after the test. |
First I'll respond inline
Thanks for figuring this out. Let me restate the key observation. Imagine a chain with tip Then, because the person may be using
I think this is extremely unlikely to be the source of any real world observed bug. Reorgs simply don't happen often enough. it's also easy to verify this theory -- take a look at the tx anchors when the bug occurs. Does it have two?
The method does what it says it's just not a very useful method. You even made this observation in #1126 but I NACK'd it because I thought this method could have a use outside of typical syns.c I didn't think we were actually still using this method anywhere but it looks like it is used in the wallet examples somehow. These should be changed to the BTW I think it is always the wrong idea to have methods that require the user to specify a "max_reorg_depth". Our algorithms should be able to logically tolerate any re-org depth without exception.
I don't think so. Is the point of the test to make sure @yanganto don't waste your time writing a test here yet. |
@LLFourn thank you for the response. I think we can still write tests with the |
Yes. I am objecting to these tests being integration tests that actually make esplora calls. You can simulate re-orgs without running esplora. We have a issue of understanding the implications of our design. I think it's wasteful to try and tackle those with integration tests which are hard to maintain and will quickly go stale. Gaining understanding about design is a painful process because it exposes our flaws and may cause us to lose confidence along the way. But you have to try and resist the urge to call for integration tests to address bugs in our understanding -- this can only make the situation worse. If we can't understand it, it's probably too complicated. I think #1194 is the right approach because it redesigns the process that doesn't require this call at all so the user can't even make this mistake. In theory this is possible because in eslplora/electrum you can always assume the "missing heights" is the heights of all the transactions after what we call the "point of agreement". To demonstrate that the problem is lack of understanding here -- I think we're wonrg. I've changed my mind: there is nothing problematic about the
We will always fetch the new block hash if I think the only work to do here is to delete |
I'll work on getting rid of |
I think that As an example, let's say the caller is syncing with Esplora. Another problem is that Because relying on a returned changeset to find missing checkpoints is problematic, I think the safest solution would be to determine missing heights from the wallet's |
After chatting with @LLFourn a couple of days ago, I am convinced by his idea to remove the need to lock the wallet multiple times. @LLFourn suggested that since we are already passing a linked list of checkpoints to the chain source, we can use that to determine missing heights instead of locking |
96a9aa6 feat(chain): refactor `merge_chains` (志宇) 2f22987 chore(chain): fix comment (志宇) daf588f feat(chain): optimize `merge_chains` (志宇) 77d3595 feat(chain)!: rm `local_chain::Update` (志宇) 1269b06 test(chain): fix incorrect test case (志宇) 72fe65b feat(esplora)!: simplify chain update logic (志宇) eded1a7 feat(chain): introduce `CheckPoint::insert` (志宇) 519cd75 test(esplora): move esplora tests into src files (志宇) a6e613e test(esplora): add `test_finalize_chain_update` (志宇) 494d253 feat(testenv): add `genesis_hash` method (志宇) 886d72e chore(chain)!: rm `missing_heights` and `missing_heights_from` methods (志宇) bd62aa0 feat(esplora)!: remove `EsploraExt::update_local_chain` (志宇) 1e99793 feat(testenv): add `make_checkpoint_tip` (志宇) Pull request description: Fixes #1354 ### Description Built on top of both #1369 and #1373, we simplify the `EsploraExt` API by removing the `update_local_chain` method and having `full_scan` and `sync` update the local chain in the same call. The `full_scan` and `sync` methods now takes in an additional input (`local_tip`) which provides us with the view of the `LocalChain` before the update. These methods now return structs `FullScanUpdate` and `SyncUpdate`. The examples are updated to use this new API. `TxGraph::missing_heights` and `tx_graph::ChangeSet::missing_heights_from` are no longer needed, therefore they are removed. Additionally, we used this opportunity to simplify the logic which updates `LocalChain`. We got rid of the `local_chain::Update` struct (which contained the update `CheckPoint` tip and a `bool` which signaled whether we want to introduce blocks below point of agreement). It turns out we can use something like `CheckPoint::insert` so the chain source can craft an update based on the old tip. This way, we can make better use of `merge_chains`' optimization that compares the `Arc` pointers of the local and update chain (before we were crafting the update chain NOT based on top of the previous local chain). With this, we no longer need the `Update::introduce_older_block` field since the logic will naturally break when we reach a matching `Arc` pointer. ### Notes to the reviewers * Obtaining the `LocalChain`'s update now happens within `EsploraExt::full_scan` and `EsploraExt::sync`. Creating the `LocalChain` update is now split into two methods (`fetch_latest_blocks` and `chain_update`) that are called before and after fetching transactions and anchors. * We need to duplicate code for `bdk_esplora`. One for blocking and one for async. ### Changelog notice * Changed `EsploraExt` API so that sync only requires one round of fetching data. The `local_chain_update` method is removed and the `local_tip` parameter is added to the `full_scan` and `sync` methods. * Removed `TxGraph::missing_heights` and `tx_graph::ChangeSet::missing_heights_from` methods. * Introduced `CheckPoint::insert` which allows convenient checkpoint-insertion. This is intended for use by chain-sources when crafting an update. * Refactored `merge_chains` to also return the resultant `CheckPoint` tip. * Optimized the update `LocalChain` logic - use the update `CheckPoint` as the new `CheckPoint` tip when possible. ### Checklists #### All Submissions: * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing #### New Features: * [x] I've added tests for the new feature * [x] I've added docs for the new feature ACKs for top commit: LLFourn: ACK 96a9aa6 Tree-SHA512: 3d4f2eab08a1fe94eb578c594126e99679f72e231680b2edd4bfb018ba1d998ca123b07acb2d19c644d5887fc36b8e42badba91cd09853df421ded04de45bf69
The logic of
missing_heights
is explained clearly in this comment:However, if a transaction is confirmed in a block that is about to turn stale (get reorged out), we
still want to fetch the new block hash. I suspect this is where our "transaction is never confirmed"
bug comes from.
My proposed solution:
Change the exception to:
And we change the signature of the method to be:
With some nice documentation for
max_reorg_depth
.An alternative solution:
Remove the stated "exception". We can continue to consider a height "missing" when there is a
floating anchor at that height (anchor that does not point to a block in the best chain).
The downside of this approach is that there are situations where certain heights will always be
considered "missing". I think this is somewhat acceptable as reorgs are rare and this situation only
happens due to reorgs.
Because of the behavior change, if we do this solution, we should rename the method to
floating_anchor_heights
.How to reproduce with
bdk_esplora
:The following should be written as a test.
bdk_esplora
),h' >= h
.bdk_esplora
).Going forward:
The test should be written first while we wait for the discussion on which solution to do matures.
The text was updated successfully, but these errors were encountered: