Return wallet events when applying updates and blocks (3.0 milestone)#319
Return wallet events when applying updates and blocks (3.0 milestone)#319notmandatory wants to merge 8 commits intobitcoindevkit:masterfrom
Conversation
There was a problem hiding this comment.
Hey @notmandatory thanks for your work on this! I left some comments related to code quality. As always, nits are non-blocking.
| .collect::<BTreeMap<Txid, (Arc<Transaction>, ChainPosition<ConfirmationBlockTime>)>>(); | ||
|
|
||
| // apply update | ||
| self.apply_update(update)?; |
There was a problem hiding this comment.
Any reason not to apply the update and use the resulting changeset to produce a summary of what changed in the Wallet?
There was a problem hiding this comment.
The resulting Wallet::ChangeSet only contains the new blocks, tx, and anchors found after applying the sync update but don't show how this new data changes the canonical status of existing tx.
There was a problem hiding this comment.
I added this as an "Option 4" to the ADR 0003.
There was a problem hiding this comment.
We make a logical assumption that the information in the events matches the data that is persisted via the ChangeSet, so my thinking is that an adequate test for this feature should include checking that the events do in fact agree with the newly staged changes. I may look into adding a test for it.
| if chain_tip1 != chain_tip2 { | ||
| events.push(WalletEvent::ChainTipChanged { | ||
| old_tip: chain_tip1, | ||
| new_tip: chain_tip2, | ||
| }); | ||
| } |
There was a problem hiding this comment.
I think it would be helpful to know which blocks were connected and/or disconnected.
There was a problem hiding this comment.
Do you mean a list of connected/disconnected block ids? I didn't add any other info here because @tnull didn't need it for LDK's use case. Do you have some use or user in mind for this extra info?
There was a problem hiding this comment.
Yeah I mean the block IDs. It's just a more complete way of describing how the chain tip changed.
There was a problem hiding this comment.
@ValuedMammal are you thinking of something like adding connected and disconnected fields to this variant:
/// The latest chain tip known to the wallet changed.
ChainTipChanged {
/// Previous chain tip.
old_tip: BlockId,
/// New chain tip.
new_tip: BlockId,
/// Newly connected blocks.
connected: Vec<BlockId>,
/// Newly disconnected blocks.
disconnected: Vec<BlockId>,
},I'm still not clear on how this info would be used by a wallet user since it's more of an internal detail.
wallet/src/wallet/event.rs
Outdated
| }); | ||
| } | ||
|
|
||
| wallet_txs2.iter().for_each(|(txid2, (tx2, cp2))| { |
There was a problem hiding this comment.
nit: Please use a for loop for this.
There was a problem hiding this comment.
I don't mind using a for loop, but just curious what the benefit is, is it just easier to read?
There was a problem hiding this comment.
Claude says the main reasons to use for instead of for_each are:
- early termination, ie. can call break in a for loop
- using mutable variable inside the for loop
- readability
We don't need 1 or 2 in this code and 3 is debatable so I'm going to stick with the for_each unless anyone has another reason to use for. The performance should be identical.
Pull Request Test Coverage Report for Build 18893642494Details
💛 - Coveralls |
21eaa1f to
488b373
Compare
|
Addressed initial comments from @ValuedMammal and rebased on Next steps:
|
488b373 to
2891853
Compare
|
I will cherry-pick and incorporate commits from #336 for |
8d580ed to
6c5c755
Compare
|
Finished cherry-picking from #336 and rebased on |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #319 +/- ##
==========================================
+ Coverage 86.30% 86.81% +0.50%
==========================================
Files 24 25 +1
Lines 8346 8464 +118
==========================================
+ Hits 7203 7348 +145
+ Misses 1143 1116 -27
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
a868aa8 to
66cedb4
Compare
|
Refactored to return events from original apply_update, apply_block* functions, removed *_events functions, see 66cedb4. |
|
Added one more commit with some docs improvements and refactored out helper method based on suggestions from Claude LLM 🤖. |
5f276a6 to
45b3cd0
Compare
|
I haven't added an example for getting affected UTXOs/addresses from a Transaction related WalletEvents. This is a bit out of scope for this PR and should get it's own PR, either to add an example or add a helper function to Wallet to do it. |
My thinking is to provide a new helper method |
|
In 95e681a: If this is a fixup commit I guess it can be squashed into the previous one. |
On second thought isn't this precisely what the user is asking for in issue #6, suggesting we should have something like |
|
I couldn't track down the original comment, but may be worth having a |
There was a problem hiding this comment.
Thanks for working on this!
Since this is a 3.0 milestone, we will have CanonicalView available. I would store the latest CanonicalView as a field in Wallet and update it every time an update is applied.
Events can be obtained by diff-ing the new view against the old view.
impl CanonicalView {
/// Not implemented.
pub fn diff(other: &Self) -> Diff { todo!() }
}If apply_update returns the old view, we can do this:
let old_view = wallet.apply_update(update)?;
let diff = old_view.diff(wallet.view() /* current view */);Then diff can be treated as "events".
Here are some benefits to this:
- This feature will be available for callers that don't use
bdk_wallet. - You aren't forced to do the event processing (it's opt-in).
- Only canonicalize once (after applying update).
In other words, I propose implementing this in bdk_chain as a method on CanonicalView. Let me know what you think.
| Users have asked for a concise list of events that reflect if or how new blockchain data has changed the | ||
| blockchain tip and the status of transactions relevant to the wallet's bitcoin balance. This information should also | ||
| be useful for on-chain apps who want to notify users of wallet changes after syncing. |
There was a problem hiding this comment.
I think it's useful to include the specific types of events that the users want emitted. This way, we can make a better judgement on how exactly we should implement it.
Edit: I see you have the event types listed in option 2, maybe it's best to include it in this section here?
Hmm, do I understand correctly that you propose to revert the API changes from #310, i.e., no longer expose |
# Conflicts: # src/wallet/event.rs
WalletEvent is a enum of user facing events that are generated when a sync update is applied to a wallet using the Wallet::apply_update_events function.
per suggestions from ValuedMammal: 1. re-export WalletEvent type 2. add comments to wallet_events function 3. rename ambiguous variable names in wallet_events from cp to pos 4. remove signing from wallet_event tests 5. change wallet_events function assert_eq to debug_asset_eq 6. update ADR 0003 decision outcome and add option 4 re: creating events only from Update
Previously, we added a new `Wallet::apply_update_events` method that returned `WalletEvent`s. Unfortunately, no corresponding APIs were added for the `apply_block` counterparts. Here we fix this omission.
Co-authored-by: Steve Myers <github@notmandatory.org>
Also did minor cleanup of apply_update_events tests.
45b3cd0 to
54b7a3c
Compare
|
Rebased this one on latest |
No. Essentially moving However, I did suggest some API changes - one benefit of my suggestion is you can choose exactly where and when you diff. // Look you can apply multiple things and then diff later!
let old_view = wallet.apply_update(update1)?;
let _ = wallet.apply_update(update2)?;
// Look, we switch to a block-based chain source in the middle.
let _ = wallet.apply_block(&block, height)?;
// We diff now! Capturing the changes made by update1 + update2 + block.
let diff = old_view.diff(wallet.view() /* current view */);Maybe we don't even need let old_view = wallet.view();
wallet.apply_update(update1)?;
wallet.apply_update(update2)?;
wallet.apply_block(&block, height)?;
let diff = old_view.diff(wallet.view());I would argue this is probably even cleaner. If the |
Makes sense!
Not sure about the |
I like the concept of giving Wallet users more control of when events are created and making the functionality available to My main concern is that this is making the wallet API and steps to get events more complicated for the simple/common case where a users only wanting events after applying an update or block. But I'll start taking a look at how to create my current events from two One solution could be to keep the current |
54b7a3c to
50dc489
Compare
|
I've rolled back this PR to only cherry-pick the commits from #310 and #336. Now all this PR does is add from
After
|
Hmm, if you're gonna keep the |
Description
Cherry-pick of commits from #310 and #336.
Notes to the reviewers
See #319 (comment) for proposed follow-up work.
Changelog notice
No changes from
release/2.xbranch.Checklists
All Submissions:
just pbefore pushingNew Features: