Leonardo Lima [Thu, 2 Oct 2025 04:42:28 +0000 (14:42 +1000)]
chore(msrv): bump MSRV to `1.85.0`
- update all references to previous 1.63.0 MSRV.
- update the rust-version to 1.85.0.
- update the CI to not exclude bdk_electrum anymore.
- update the ci/pin-msrv.sh to 1.85.0.
<!-- You can erase any parts of this template not applicable to your Pull Request. -->
### Description
<!-- Describe the purpose of this PR, what's being adding and/or fixed -->
### Notes to the reviewers
<!-- In this section you can include notes directed to the reviewers, like explaining why some parts
of the PR were done in a specific way -->
### Changelog notice
<!-- Notice the release manager should include in the release tag message changelog -->
<!-- See https://keepachangelog.com/en/1.0.0/ for examples -->
### Checklists
#### All Submissions:
* [ ] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
#### 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
Replace `ScriptBuf` with `&Script` in `SpkTxOutIndex::index_of_spk` and `KeychainTxOutIndex::index_of_spk` methods, to avoid the need of cloning the `ScriptBuf` for a SPK index lookup.
### Changelog notice
Breaking changes:
- Change `SpkTxOutIndex::index_of_spk` and `KeychainTxOutIndex::index_of_spk` args from `ScriptBuf` to `&Script`.
### Checklists
#### All Submissions:
* [X] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
#### New Features:
* [ ] I've added tests for the new feature
* [ ] I've added docs for the new feature
#### Bugfixes:
* [X] 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
It's an initial attempt to solve the timeout failures we have been facing on CI when running electrum tests. It it's not solved at all, at least it now adds the total time elapsed so we can know how long it's taking in CI.
The PR updates the `chained_mempool_txs` test to use 6 seconds as timeout, instead of 5, it was the only spot using 5 instead of 6. Also updates the error message to show the total time elapsed, can help debug the CI if the timeout error persists.
### Notes to the reviewers
### Changelog notice
```
### Changed
- Update the `chained_mempool_txs` to use 6 seconds as timeout.
- Update the error message to show the time elapsed.
```
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
Leonardo Lima [Thu, 2 Oct 2025 04:18:47 +0000 (14:18 +1000)]
fix(ci,test): update `chained_mempool_txs` to use 6 secs timeout
- update the chained_mempool_txs test to use 6 seconds as timeout,
instead of 5, it was the only spot using 5 instead of 6.
- update the error message to show the total time elapsed, can help
debug the CI if the timeout error persists.
refactor(chain): replace `ScriptBuf` with `AsRef<Script>` in SPK index methods
Replace `ScriptBuf` with `AsRef<Script>` in `SpkTxOutIndex::index_of_spk` and `KeychainTxOutIndex::index_of_spk` methods, to avoid the need of cloning the `ScriptBuf` for a SPK index lookup.
`CanonicalView` allows us to canonicalize upfront, reducing our API surface and improving performance by reducing canonicalizations we need to do.
This is also the first step to achieving many of our goals.
* Event notifications.
* Intent tracker.
* Getting rid of `CanonicalUnspents` structure in `bdk_tx`.
### Changelog notice
```md
Added
- Introduce `CanonicalView` which allows us to canonicalize once upfront.
- Added `TxGraph::canonical_view` which constructs a `CanonicalView`.
Changed
- `TxGraph` methods which require canonicalization now have `CanonicalView` equivalents.
Removed
- `TxGraph` methods which take in a fallible `ChainOracle` implementations are now removed.
```
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
#### New Features:
* [x] I've added tests for the new feature
* [x] I've added docs for the new feature
It looks like that the retry approach introduced on #2032 does not really work, as the github workflow syntax does not have those fields.
I've opened this PR to revert the changes, and make sure that CI is working again. Though I still think we can implement a manual retry logic on our side, probably using gh cli inside of the CI job.
### Notes to the reviewers
It needs to be merged in order to coverage CI to work properly again.
### Changelog notice
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
test(chain): Add comprehensive tests for min_confirmations parameter
Add test file `tests/test_canonical_view.rs` with three comprehensive test cases:
1. `test_min_confirmations_parameter`: Tests basic min_confirmations functionality
- Verifies min_confirmations = 0 and 1 behave identically
- Tests edge case where transaction has exactly required confirmations
- Tests case where transaction has insufficient confirmations
2. `test_min_confirmations_with_untrusted_tx`: Tests trust predicate interaction
- Verifies insufficient confirmations + untrusted predicate = untrusted_pending
- Ensures trust predicate is respected when confirmations are insufficient
3. `test_min_confirmations_multiple_transactions`: Tests complex scenarios
- Multiple transactions with different confirmation counts
- Verifies correct categorization based on min_confirmations threshold
- Tests both min_confirmations = 5 and min_confirmations = 10 scenarios
These tests validate that the min_confirmations parameter correctly controls
when transactions are treated as confirmed vs trusted/untrusted pending.
🤖 Generated with [Claude Code](https://claude.ai/code)
feat(chain): Add min_confirmations parameter to CanonicalView::balance
Add min_confirmations parameter to control confirmation depth requirements:
- min_confirmations = 0: Include all confirmed transactions (same as 1)
- min_confirmations = 1: Standard behavior - require at least 1 confirmation
- min_confirmations = 6: High security - require at least 6 confirmations
Transactions with fewer than min_confirmations are treated as trusted/untrusted
pending based on the trust_predicate. This restores the minimum confirmation
functionality that was available in the old TxGraph::balance doctest but with
a more intuitive API since CanonicalView has the tip internally.
🤖 Generated with [Claude Code](https://claude.ai/code)
feat(chain)!: Introduce `CanonicalView` and migrate API
- Add `CanonicalView` structure with canonical transaction methods
- Move methods from `TxGraph` to `CanonicalView` (txs, filter_outpoints, balance, etc.)
- Add canonical view methods to `IndexedTxGraph`
- Update all tests and examples to use new API
- Optimize examples to reuse canonical view instances
🤖 Generated with [Claude Code](https://claude.ai/code)
All `last_evicted` field to `TxNode` and remove `TxGraph::get_last_evicted` method.
### Notes to the reviewers
`get_last_evicted` was added as adding fields to `TxNode` is a breaking change. However, we are going to break `bdk_chain` in the next release so a breaking change now is okay.
### Changelog notice
```md
Added:
- `last_evicted` field is added to `TxNode`.
Removed:
- `TxGraph::get_last_evicted` method is removed.
```
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
#### New Features:
~* [ ] I've added tests for the new feature~
* [x] I've added docs for the new feature
This PR is a step towards header checkpointing for `bdk_electrum`. The goal is to be able to store whole headers in `CheckPoint` so they do not have to be re-downloaded. Storing headers this way would be a prerequisite for caching of merkle proofs and for median time passed.
### Notes to the reviewers
### Changelog notice
* `CheckPoint` takes in a generic.
* `LocalChain` and `ChangeSet` take in generics.
* `spk_client` types can take in generics.
### 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
Leonardo Lima [Wed, 10 Sep 2025 01:23:32 +0000 (11:23 +1000)]
chore(release): bump `bdk-chain` to `0.23.2`
- bump `bdk_core` to `0.6.2`
- bump `bitcoind_rpc` to `0.22.0`
- bump `file_store` to `0.22.0`.
- bump `bdk_electrum` to `0.23.2`
- update all the required `CHANGELOG.md`
Previously `FilterIter` did not detect or handle reorgs between `next` calls, meaning that if a reorg occurred, we might process blocks from a stale fork potentially resulting in an invalid wallet state. This PR aims to fix that by adding logic to explicitly check for and respond to a reorg on every call to `next`.
### Notes to the reviewers
The old implementation required storing block IDs of scanned blocks before creating a checkpoint update, but because the interface was split across different methods, it introduced a timing risk between method calls which, when we consider the possibility of reorgs, made the implementation somewhat brittle.
To address this, we make sure that 1) Finding the start block and 2) Updating the internal checkpoint are directly tied to the logic of `next`. Since the checkpoint in practice is derived from a clone of the local chain, this ensures that the checkpoint returned by `next` can always find a connection point with the receiver. Additionally we now emit a checkpoint at every height to ensure that any "must-include" heights are not missing.
For example usage see `examples/filter_iter.rs`
fixes #1848
### Changelog notice
Fixed
- `FilterIter` now handles reorgs to ensure consistency of the header chain.
Changed
- `Event` is now a struct instead of enum
Added
- `FilterIter::new` constructor that takes as input a reference to the RPC client, checkpoint, and a list of SPKs.
- `Error::ReorgDepthExceeded` variant
- `Error::TryFromInt` variant
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
#### New Features:
* [x] I've added tests for the new feature
* [x] I've added docs for the new feature
#### Bugfixes:
* [x] This pull request breaks the existing API
* [x] I've added tests to reproduce the issue which are now passing
* [x] I'm linking the issue being fixed by this PR
This PR adds a new doctest demonstrating how to simulate a minimum confirmation threshold for confirmed balance calculations by adjusting the `chain_tip` height passed to `TxGraph::balance`.
### Changelog notice
- Added a doctest illustrating how to filter confirmed balance results by simulating a minimum confirmation threshold via `chain_tip` height.
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
#### New Features:
* [x] I've added tests for the new feature
* [x] 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
* [x] I'm linking the issue being fixed by this PR
The API now consists of the methods `new` and `next`.
The local checkpoint and SPK inventory are provided to
the constructor. `next` is now responsible for locating
the point of agreement.
The next filter to fetch is determined by the `next_block_hash`
field of `GetBlockHeaderResult`. If the next header has negative
confirmations due to a reorg, we rewind the internal state until
we find a header still in the best chain.
`Event` is changed to a simple struct containing `cp` and optional
`block`. The checkpoint is updated on each iteration whether
or not it corresponds to a matching block. We use
`CheckPoint::insert` which will also purge evicted blocks
if needed.
Change implementation of `find_base` to use `get_block_header_info`
which helps to reduce the number of RPC calls.
Removed `EventInner`.
Add test `event_checkpoint_connects_to_local_chain` to check
the expected events after a reorg, and check that intermediate
updates can be applied to the local chain.
Fixes an issue in `batch_fetch_anchors()` in `bdk_electrum` where, if a stale block header was detected and a fresh header was fetched, the confirmation anchor inserted into `anchor_cache` still used the hash from the original stale header instead of the new one.
### Changelog notice
- `batch_fetch_anchors()` no longer uses a potentially stale hash as the anchor.
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
#### 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
This PR addresses #1982
It introduces functionality to populate the anchor cache, improving how BDK handles stateful or performance-critical anchor data.
### Changes
- Add `populate_anchor_cache` method to `BdkElectrumClient `in `bdk-core`
- Improves sync speed by caching anchor transactions in advance
- Enables pre-caching of anchor transactions to reduce redundant network calls
Follow-up work will extend this functionality to `bdk-wallet`.
This PR updates the GitHub issue templates `bug_report.md` and `enhancement_request.md` to improve triage and prioritization. Specifically, it adds structured fields for:
* Production impact (e.g., blocking usage vs. nice-to-have)
* Backend in use (Electrum, Esplora, RPC, etc.)
* Project or organization (optional, helps identify high-priority users)
The goal is to make it easier for maintainers to gauge the urgency and relevance of issues, especially for production users or high-impact integrations.
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
* Why something is no longer part of the best history.
* Whether it is possible that something can reappear in the best history.
In order to do this, we need to track conflicts of spk-relevant transactions.
For example, an incoming transaction may be evicted from the mempool due to insufficient fees or cancelled (a conflicting transaction is confirmed). The caller may want to handle these two possibilities differently:
* **Transaction has insufficient fees** - the caller may want to CPFP the transaction.
* **Transaction is cancelled/replaced** - The user may want to forget about this transaction once the conflict reaches x confirmations.
The `IntentTracker` will make use of these relevant-conflicts to help determine the course of action.
#### Side note about chain sources
For some chain sources, obtaining relevant-conflicts is extremely costly or downright impossible (i.e. Electrum, BIP-158 filters).
`bdk_bitcoind_rpc::Emitter` is still the most robust chain source to use.
### Changelog notice
```md
Changed:
- Behavior of `IndexedTxGraph` methods (`apply_block_relevant`, `batch_insert_relevant` and `batch_insert_relevant_unconfirmed`) to also consider conflicts of spk-relevant transactions as relevant.
```
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
#### New Features:
* [x] I've added tests for the new feature
* [x] I've added docs for the new feature
<!-- You can erase any parts of this template not applicable to your Pull Request. -->
### Description
Fixes #1991. As the linked issue mentions `Box`ing helps reduce memory overhead and [limits the size of enums with `StoreErrorWithDump` as variant](https://github.com/bitcoindevkit/bdk_wallet/pull/277#discussion_r2196831262).
Breaking: The enum `StoreErrorWithDump` and the functions `load`,`dump` and `load_or_create` have been changed.
### Changelog Notice
```
Changed
- `changeset` field of `StoreErrorWithDump` is now of type `Option<Box<C>>`
```
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
refactor!: `Box` changeset in `StoreErrorWithDump`
As mentioned in the corresponding issue, `Box`ing helps reduce memory
overhead while passing the enum around and also to limit the size of
enums with `StoreErrorWithDump` as a variant.
Breaking: The enum `StoreErrorWithDump` has been changed.
fixes #1987
depends on https://github.com/bitcoindevkit/rust-electrum-client/pull/170
### Description
- update `batch_fetch_anchors` to use `batch_transaction_get_merkle` method instead of manually creating the batch call.
### Changelog notice
```md
### Changes
- Use new `batch_transaction_get_merkle` method instead of batch raw calls
```
### 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 +nightly fmt` and `cargo clippy` before committing
Leonardo Lima [Fri, 4 Jul 2025 18:46:03 +0000 (15:46 -0300)]
chore(bdk-electrum): use new `batch_transaction_get_merkle` API
- removes the now unused `serde_json` dependency from `bdk_electrum`.
- update `batch_fetch_anchors` to use `batch_transaction_get_merkle`
method instead of manually creating the batch call.
feat(chain): Txs that conflict with relevant txs are also relevant
Change behavior of {insert|apply}-if-relevant methods of `IndexedTxGraph`
to also consider txs that conflict with relevant txs as relevant.
Rationale:
It is useful to determine why something is evicted from the mempool.
For example, an incoming transaction may be evicted from the mempool due
to insufficient fees or a conflicting transaction is confirmed.
* Insufficient fees - the user may want to CPFP the tx.
* Conflicting tx is confirmed - the sender probably purposefully
cancelled the tx. The user may want to forget about this tx once it
reaches x confirmations.
The `IntentTracker` will make use of these relevant-conflicts.
A note about chain sources:
For some chain sources, obtaining relevant-conflicts is extremely
costly or downright impossible (i.e. Electrum, BIP-158 filters).
`bdk_bitcoind_rpc::Emitter` is still the most robust chain source to use.
Automated update to Github CI workflow `cont_integration.yml` by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action
As explained in #1984 , I discovered some misreportings in the coverage information given by grcov.
Fixes #1984
### Notes to the reviewers
The discussion about the tool to use is open, but I'm adding this PR to showcase how a change from `grcov` to `cargo-llvm-cov` would look like and the improvements in reporting this change will bring. [Look the report in `coveralls`](https://coveralls.io/github/nymius/bdk?branch=ci/replace-grcov-by-cargo-llvm-cov) to get a better perspective of them.
### 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 +nightly fmt` and `cargo clippy` before committing
There is a bug in `bdk_bitcoind_rpc` where some new mempool transactions will not be emitted at all.
This problem exists because the avoid-re-emission logic depends on rounded-to-nearest-second timestamps.
The fix is to just emit all mempool transactions but wrap them in `Arc`s so that emission becomes cheap.
**Background:** I tried using `bdk_bitcoind_rpc` as the chain-source to write an example to showcase the [`IntentTracker`](https://github.com/bitcoindevkit/bdk_wallet/pull/257). However, `bdk_bitcoind_rpc` failed to emit some mempool transactions.
### Notes to the reviewers
The test added in c22c68f fails without these fixes.
Some tests are removed as they are no longer relevant.
### Changelog notice
```md
Fixed:
- Some mempool transactions not being emitted at all. The fix is to replace the avoid-re-emission-logic with one which emits all mempool transactions.
```
### 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 +nightly fmt` and `cargo clippy` before committing
#### Bugfixes:
* [x] This pull request breaks the existing API
* [x] I've added tests to reproduce the issue which are now passing
~* [ ] I'm linking the issue being fixed by this PR~
Ideally, this would be included as a field in `TxNode`, however that would be a breaking change.
### Changelog notice
```md
Added
- `TxGraph::get_last_evicted`
```
### 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 +nightly fmt` and `cargo clippy` before committing
#### New Features:
~* [ ] I've added tests for the new feature~
* [x] I've added docs for the new feature
This PR eliminates all `unwrap()` and `expect()` calls from `bdk_electrum_client`, replacing them with proper error handling. Given that all public methods already return `Result`, we now propagate error messages instead of panicking.
### Changelog notice
* Removed all `unwrap()`s and `expect()`s from `bdk_electrum_client.rs`.
### 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 +nightly fmt` and `cargo clippy` before committing
This patch improves readability and maintains logical consistency with the use of `spk_cache` throughout the `keychain_txout` module.
While it might offer a performance benefit, the results are mostly comparable with the current benchmarks as far as I can tell. At least there's no indication that it would negatively impact performance.
fixes #1975
### Changelog notice
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
The logic in `CanonicalIter` includes transactions anchored to blocks outside the best chain, since they may still appear in the mempool.
However, coinbase transactions can never be unconfirmed—a case the previous logic failed to exclude.
### Notes to the reviewers
Sorry for my previous oversight on this.
### Changelog notice
```md
Fixed:
- During canonicalization, exclude coinbase transactions when considering txs that are anchored in stale blocks.
```
### 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 +nightly fmt` and `cargo clippy` before committing
#### Bugfixes:
~* [ ] This pull request breaks the existing API~
* [x] I've added tests to reproduce the issue which are now passing
* [ ] I'm linking the issue being fixed by this PR
# Run all tests for all crates with all features enabled
test:
@just _test-bitcoind_rpc
@just _test-chain
@just _test-core
@just _test-electrum
@just _test-esplora
@just _test-file_store
@just _test-testenv
_test-bitcoind_rpc:
cargo test -p bdk_bitcoind_rpc --all-features
_test-chain:
cargo test -p bdk_chain --all-features
_test-core:
cargo test -p bdk_core --all-features
_test-electrum:
cargo test -p bdk_electrum --all-features
_test-esplora:
cargo test -p bdk_esplora --all-features
_test-file_store:
cargo test -p bdk_file_store --all-features
_test-testenv:
cargo test -p bdk_testenv --all-features
# Run pre-push suite: format, check, and test
pre-push: fmt check test
```
`check` will verify if `HEAD` was signed and echo that warning if not. It does not check all commits, but I think that checking only the last is a pretty good heuristic (who signs the last commit only?).
Before pushing, one only needs to run `just p`.
### 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 `just p` before pushing
feat(bitcoind_rpc)!: Use `getrawmempool` without verbose
This is the more performant method. The downside is that mempool txids
are not returned to the seen-in-mempool timestamps so the caller either
needs to provide this, or we need to rely on std to get the current
timestamp.
* `Emitter::mempool` method now requires the `std` feature. A non-std
version of this is added: `Emitter::mempool_at` which takes in a
`sync_time` parameter.
Additional changes:
* `NO_EXPECTED_MEMPOOL_TXIDS` is renamed to `NO_EXPECTED_MEMPOOL_TXS`.
* Updated documentation.
* Fix imports so that `bdk_bitcoind_rpc` compiles without `std`.
Instead of having an avoid-reemission logic based on timestamps returned
by bitcoind RPC, we wrap all transactions in `Arc` and always emit the
entire mempool. This makes emission cheap while avoiding the flawed
avoid-reemission logic.
Before, the `chain_update` function might have panicked if the local checkpoint was not on the same network as the remote server. Now if we have iterated all of the blocks of the local CP and do not find a point of agreement, then we return early with a `esplora_client::Error::HeaderHashNotFound`.
cc bitcoindevkit/bdk_wallet#30
### Notes to the reviewers
### Changelog notice
### 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 +nightly fmt` and `cargo clippy` before committing
#### 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
* [x] I've added tests to reproduce the issue which are now passing
* [x] I'm linking the issue being fixed by this PR
- Add benchmark `reindex_tx_graph`. Run with `cargo bench -p bdk_chain --bench indexer`.
- Add unit test to `keychain_txout` module to test behavior of spk-cache.
- Fixup a few doc comments.
### 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 +nightly fmt` and `cargo clippy` before committing
<!-- You can erase any parts of this template not applicable to your Pull Request. -->
### Description
This PR covers a wide range on tests for excluded bounds and the `SpkTxOutIndex::outputs_in_range`. This PR fixes bitcoindevkit/bdk_wallet#58
<!-- Describe the purpose of this PR, what's being adding and/or fixed -->
### Notes to the reviewers
<!-- In this section you can include notes directed to the reviewers, like explaining why some parts
of the PR were done in a specific way -->
### Changelog notice
<!-- Notice the release manager should include in the release tag message changelog -->
<!-- See https://keepachangelog.com/en/1.0.0/ for examples -->
### 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:
* [ ] 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
* [x] I'm linking the issue being fixed by this PR
Replaces #1908, originally authored by @Keerthi421.
Fixes #1891.
### Description
This PR optimizes `sync`/`full_scan` performance by batching and caching key RPC calls to slash network round-trips and eliminate redundant work.
Key improvements:
* Gather all `blockchain.transaction.get_merkle` calls into a single `batch_call` request.
* Use `batch_script_get_history` instead of many individual `script_get_history` calls.
* Use `batch_block_header` to fetch all needed block headers in one call rather than repeatedly calling `block_header`.
* Introduce a cache of transaction anchors to skip re-validating already confirmed transactions.
#### Anchor Caching Performance Improvements
Results suggest a significant speed up with a warmed up cache. Tested on local Electrum server with:
```
$ cargo bench -p bdk_electrum --bench test_sync
```
Results before this PR (https://github.com/LagginTimes/bdk/tree/1957-master-branch):
```
sync_with_electrum time: [1.3702 s 1.3732 s 1.3852 s]
```
Results after this PR:
```
sync_with_electrum time: [851.31 ms 853.26 ms 856.23 ms]
```
#### Batch Call Performance Improvements
No persisted data was carried over between runs, so each test started with cold caches and measured only raw batching performance. Tested with`example_electrum` out of https://github.com/LagginTimes/bdk/tree/example_electrum_timing with the following parameters:
Results after this PR (using this PR's [`bdk_electrum_client.rs`](https://github.com/bitcoindevkit/bdk/blob/70495e2010541acbb5d62f9b5692de20924ac53f/crates/electrum/src/bdk_electrum_client.rs)):
```
FULL_SCAN TIME: 2.594050112s
```
### Changelog notice
* Add transaction anchor cache to prevent redundant network calls.
* Batch Merkle proof, script history, and header requests.
### 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
#### Bugfixes:
* [ ] This pull request breaks the existing API
* [x] I've added tests to reproduce the issue which are now passing
* [x] I'm linking the issue being fixed by this PR