Skip to content

feat: stream transactions and progress during sync#2242

Closed
ANAMASGARD wants to merge 1 commit into
bitcoindevkit:masterfrom
ANAMASGARD:feature/stream-sync-progress-2202
Closed

feat: stream transactions and progress during sync#2242
ANAMASGARD wants to merge 1 commit into
bitcoindevkit:masterfrom
ANAMASGARD:feature/stream-sync-progress-2202

Conversation

@ANAMASGARD

Copy link
Copy Markdown

Closes #2202

Description

Adds incremental sync progress and transaction streaming to Electrum and Esplora backends.

Wallets can register .on_event() on SyncRequest / FullScanRequest to receive:

  • PartialUpdate(TxUpdate) — newly discovered txs/metadata at fetch boundaries
  • AnchorsResolved(TxUpdate) — anchor-only delta after Electrum resolves confirmation proofs
  • ItemStarted / SpkStarted — progress events (.inspect() is sugar over these)

TxUpdate::drain_since() destructively moves data out of the working buffer at each emission boundary. When events consume everything, response.tx_update is naturally empty — applying it at the end is a safe no-op (no double-apply footgun).

Consumer contract:

let request = SyncRequest::builder()
    .spks(spks)
    .on_event(|event| match event {
        SyncRequestEvent::PartialUpdate(delta)
        | SyncRequestEvent::AnchorsResolved(delta) => graph.apply_update(delta),
        _ => { /* progress UI */ }
    })
    .build();

let response = client.sync(request, batch_size, true)?;
graph.apply_update(response.tx_update); // empty when events drained all data

Emission points:

  • Electrum: after each SPK batch; once after txid/outpoint passes; AnchorsResolved after batch_fetch_anchors
  • Esplora: after each parallel batch (blocking + async)

Existing sync/full_scan signatures are unchanged (additive API).

Notes to the reviewers

  • .inspect() now routes through .on_event() internally (single reporter path); progress-only users are unaffected unless they also call .on_event().
  • emit_partial_updates defaults to false — draining only happens when .on_event() is used.
  • Electrum confirmed txs in PartialUpdate intentionally lack anchors until AnchorsResolved; see sync_defers_anchors_until_resolved test.
  • Esplora async uses EmitPartial trait on the concrete request (not dyn across .await) to satisfy Send.

Changelog notice

  • Added SyncRequestEvent, FullScanRequestEvent, FullScanProgress, and TxUpdateCursor types.
  • Added SyncRequestBuilder::on_event() and FullScanRequestBuilder::on_event().
  • Added TxUpdate::drain_since() for incremental delta extraction.
  • Electrum and Esplora now emit PartialUpdate events during sync/full_scan when .on_event() is registered.

Checklists

All Submissions:

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR
Screenshot From 2026-07-11 14-54-26 --- image --- image --- image

---

## What each test proves for #2202

| Test | Proves |
|---|---|
| `drain_since_*` | Delta extraction is correct; partials reconstruct full update |
| `final_response_empty_after_full_drain` | No double-apply when streaming |
| `sync_on_event_fires_item_started` | `.on_event()` builder works |
| `sync_streams_partial_updates` (electrum + esplora) | `PartialUpdate` fires **before** sync returns; final `tx_update` empty |
| `sync_defers_anchors_until_resolved` | Electrum anchor semantics correct |

Add .on_event() API with PartialUpdate and AnchorsResolved events,
TxUpdate::drain_since() for safe incremental application, and wire
emission into Electrum and Esplora backends. Addresses bitcoindevkit#2202.
@thunderbiscuit

Copy link
Copy Markdown
Member

This PR is addressing an issue that is now closed. The feature is already (albeit in a different form) available today.

@ANAMASGARD your approach with PRs on the BDK repos is in my opinion somewhat misguided at the moment. Your PRs are coming in at a staggering rate, across all repos and languages. As a maintainer, to me this reads like someone who is just sending Claude into a GitHub org, scanning for open and easy issues, and just prompting AI sub-agents into one-shotting a bunch of our issues without thought or care for deep understanding. For context: bitcoindevkit/bdk-dart#116, bitcoindevkit/bdk-dart#115, bitcoindevkit/bdk-dart#116, bitcoindevkit/bdk-dart#114, bitcoindevkit/bdk-dart#113, bitcoindevkit/book-of-bdk#156, bitcoindevkit/bdk-jvm#69, bitcoindevkit/bdk_wallet#513, bitcoindevkit/bdk_wallet#512, #2241, #2238, #2242.

We are always happy to see new contributors, but if I may suggest something that would increase your chance of success, it'd be to spend time on a single repo/language and take time to learn it well. Interact on the issues, and get some PRs in slow and steady. Good luck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Stream transactions and progress in syncing

2 participants