Describe the enhancement
bdk_esplora re-downloads the full transaction body for every tracked txid on every sync, even when the transaction was already fetched in a previous sync and only its confirmation status may have changed. bdk_electrum does not have this problem.
BdkElectrumClient (crates/electrum/src/bdk_electrum_client.rs:27) maintains a persistent tx_cache: Mutex<HashMap<Txid, Arc<Transaction>>>, along with a populate_tx_cache() method to seed it from an existing TxGraph. Already-known transactions are never re-fetched.
bdk_esplora has no equivalent. Both crates/esplora/src/async_ext.rs and crates/esplora/src/blocking_ext.rs only build a throwaway HashSet<Txid> (inserted_txs) local to each sync call — it's discarded once the function returns. There is no persistent cache at the client level, and no wrapper struct in lib.rs to hold one.
Every txid passed via request.iter_txids() / iter_outpoints() triggers a call to client.get_tx_info(&txid) in fetch_txs_with_txids, which downloads the entire transaction body, even though esplora_client already exposes a lightweight get_tx_status() (GET /tx/{txid}/status) that returns only the confirmation status. I confirmed get_tx_status is never called anywhere in bdk_esplora.
There is a TODO already acknowledging this gap:
async_ext.rs:495
blocking_ext.rs:454
// TODO: We should maintain a tx cache (like we do with Electrum).
Proposed fix
- Add a persistent transaction cache to
bdk_esplora, mirroring BdkElectrumClient's pattern — including a populate_tx_cache() method so users can seed it from an existing wallet/TxGraph on startup.
- For txids already present in the cache, use the lightweight
get_tx_status() call instead of get_tx_info() to check for status changes, rather than re-downloading the full transaction.
- Only call
get_tx_info() (full fetch) for genuinely new/unseen txids.
Use case
Wallets that sync on an interval (e.g. mobile wallets polling every few seconds/minutes) end up re-downloading the full transaction body for every tracked unconfirmed txid on every single sync, purely to check whether its status changed — wasted bandwidth and slower syncs, especially with many tracked/unconfirmed transactions.
Impact
Are you using BDK in a production project?
Which backend(s) are relevant (if any)?
Project or organization (optional)
Additional context
Confirmed via direct code inspection on master (commit 337e9d68). No cryptography involved, scope is contained to the bdk_esplora crate only.
Describe the enhancement
bdk_esplorare-downloads the full transaction body for every tracked txid on every sync, even when the transaction was already fetched in a previous sync and only its confirmation status may have changed.bdk_electrumdoes not have this problem.BdkElectrumClient(crates/electrum/src/bdk_electrum_client.rs:27) maintains a persistenttx_cache: Mutex<HashMap<Txid, Arc<Transaction>>>, along with apopulate_tx_cache()method to seed it from an existingTxGraph. Already-known transactions are never re-fetched.bdk_esplorahas no equivalent. Bothcrates/esplora/src/async_ext.rsandcrates/esplora/src/blocking_ext.rsonly build a throwawayHashSet<Txid>(inserted_txs) local to each sync call — it's discarded once the function returns. There is no persistent cache at the client level, and no wrapper struct inlib.rsto hold one.Every txid passed via
request.iter_txids()/iter_outpoints()triggers a call toclient.get_tx_info(&txid)infetch_txs_with_txids, which downloads the entire transaction body, even thoughesplora_clientalready exposes a lightweightget_tx_status()(GET /tx/{txid}/status) that returns only the confirmation status. I confirmedget_tx_statusis never called anywhere inbdk_esplora.There is a TODO already acknowledging this gap:
async_ext.rs:495blocking_ext.rs:454Proposed fix
bdk_esplora, mirroringBdkElectrumClient's pattern — including apopulate_tx_cache()method so users can seed it from an existing wallet/TxGraphon startup.get_tx_status()call instead ofget_tx_info()to check for status changes, rather than re-downloading the full transaction.get_tx_info()(full fetch) for genuinely new/unseen txids.Use case
Wallets that sync on an interval (e.g. mobile wallets polling every few seconds/minutes) end up re-downloading the full transaction body for every tracked unconfirmed txid on every single sync, purely to check whether its status changed — wasted bandwidth and slower syncs, especially with many tracked/unconfirmed transactions.
Impact
Are you using BDK in a production project?
Which backend(s) are relevant (if any)?
bdk_chain,bdk_core)____Project or organization (optional)
Additional context
Confirmed via direct code inspection on
master(commit337e9d68). No cryptography involved, scope is contained to thebdk_esploracrate only.