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

Add event-based API to Client #69

Merged
merged 1 commit into from
Oct 25, 2024

Conversation

rustaceanrob
Copy link
Collaborator

@rustaceanrob rustaceanrob commented Oct 14, 2024

Ahead of the bindings chat I thought a little more about an event-based API as opposed to the callback style we currently have. In this draft I only have a few Event types, but there would be a handful more. I still don't quite know if this would be a developer experience improvement. Just looking for an opinion on this rough draft.

@rustaceanrob rustaceanrob force-pushed the event-10-14 branch 9 times, most recently from 3ed5c60 to 8b85319 Compare October 15, 2024 16:43
@rustaceanrob rustaceanrob changed the title WIP: event API Add event-based API to Client Oct 15, 2024
@rustaceanrob
Copy link
Collaborator Author

rustaceanrob commented Oct 15, 2024

Updated and ready for review. My notes:

  • Add the callbacks and events features and put the respective APIs behind feature flags. Both are enabled by default, so we may let the best API win
  • Added an Event type that will return wallet updates, as well as node information.
  • Log events may be filtered out with the LogLevel enum
  • Updated documentation
  • Updated examples
  • Integration tests to follow in another PR

@rustaceanrob rustaceanrob marked this pull request as ready for review October 15, 2024 16:47
@ValuedMammal
Copy link
Collaborator

Concept ACK. I'm still in the process of reviewing

Comment on lines +29 to +30
callbacks = []
events = []
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do these need to be feature flags or is it fine to have update and next_event available for Client out of the box?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

My intention was that developers should be able to choose the API surface as they please. I don't think there would be any downside to mixing the two calls, but it would be strange to do so.

Cargo.toml Show resolved Hide resolved
src/lib.rs Show resolved Hide resolved
examples/events.rs Outdated Show resolved Hide resolved
Copy link
Collaborator

@ValuedMammal ValuedMammal left a comment

Choose a reason for hiding this comment

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

ACK 09ad97d

Comment on lines +516 to +523
/// ## Note
///
/// No action is required from the developer, as these events are already
/// handled within the [`Client`]. This event is to inform the user of
/// such an event.
BlocksDisconnected(Vec<DisconnectedHeader>),
Copy link
Collaborator

Choose a reason for hiding this comment

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

To be clear, is the idea for this to be an event the caller will act on if we had something like bitcoindevkit/bdk#1655 ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's actually more cosmetic. In the event a user is expecting their transaction has confirmed when it actually got reorged, I was thinking the developer should let them know. But we still maintain LocalChain event with the Event architecture, so it handled internally and conveyed by the FullScanResult.

My intention with that PR is more for ldk-node, where one Block or BlocksDisconnected event from kyoto might be handled by many structures, one being the Wallet. In that case, I am thinking they can just use kyoto directly, and that PR would enable some good synergy between Wallet and kyoto

Copy link
Member

@thunderbiscuit thunderbiscuit left a comment

Choose a reason for hiding this comment

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

Looks good!

One more "meta" question I'd have is around the capture/drop of all events by the user-side code. There is currently (as far as I can tell) no way to retrieve events that have been emitted. If you missed one it's gone. ldk-node keeps them all in a queue and forces you to acknowledge receipt of the event before feeding you the next one, but honestly that feels pretty heavy-handed in the Kyoto case.

I was looking at all the event types and I don't think there are events that would create critical issues if you missed them, but I'm not 100% sure yet; just something to think about/confirm. The two that need confirming are Synced and BlockDisconnected. If you miss a Synced event, will you pick up the missing state on your next block/sync emitted event?

src/lib.rs Show resolved Hide resolved
recent_history.into_iter().for_each(|(height, header)| {
chain_changeset.insert(height, Some(header.block_hash()));
});
self.chain
Copy link
Member

Choose a reason for hiding this comment

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

So the result of the sync is applied to the local chain here, but also passed to the user code so they can apply it too?

Copy link
Collaborator Author

@rustaceanrob rustaceanrob Oct 24, 2024

Choose a reason for hiding this comment

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

Yeah, we maintain a copy of a LocalChain to apply updates, but it is only used to build wallet updates. That is why I opened this PR, so the Wallet may directly handle events from kyoto if we determine that is easier to work with

@thunderbiscuit
Copy link
Member

I'm not 100% sure of my reading of this yet but is it the case that the events-based approach here is basically sending back more "info-type" events letting the user know what happened internally, but the actual domain logic lives in bdk_kyoto (applying updates to the wallet, disconnecting blocks?). If that's the case it's a slight departure from the bdk_electrum and bdk_esplora clients, which simply return types you must use to update your wallet yourself.

I can see there is logic applied to the localchain in the events, but also the example applies the update to the wallet. Just wanting to build a good mental model for this for myself.

@rustaceanrob
Copy link
Collaborator Author

If that's the case it's a slight departure from the bdk_electrum and bdk_esplora clients, which simply return types you must use to update your wallet yourself.

This isn't much of an option for use unless we want to serialize blocks. I think it makes more sense to curate the events, so, if there are changes to the wallet, they are just aggregated together with a FullScanResponse.

If you missed one it's gone.

I am not sure what is meant by miss. The next event will always be held until next_event is called, the events build up in a queue if next_event is not called in a timely manner, but they are not missed. What I can empathize with is having a Wallet fail while calling persist, in which case maybe we could maintain a queue of FullScanResponse within client and the user can request them at any time (this is not even a feature of electrum or esplora to my knowledge). As an aside, the only relevant event that can actually mutate the wallet is ScanResponse. Everything else is for user info

@rustaceanrob rustaceanrob merged commit ce480e0 into bitcoindevkit:master Oct 25, 2024
2 checks passed
@rustaceanrob rustaceanrob deleted the event-10-14 branch October 25, 2024 12:16
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.

3 participants