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
valued mammal [Thu, 5 Jun 2025 17:17:21 +0000 (13:17 -0400)]
fix(esplora): `chain_update` errors if no point of connection
Before, the `chain_update` function would hit a panic 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`.
志宇 [Wed, 25 Jun 2025 23:34:50 +0000 (23:34 +0000)]
test(electrum): Improve benchmark
* Actually use different spks
* Do not benchmark applying updates (only fetching/contructing)
* Have two benches: One with cache, one without.
* Remove `black_box`.
Automated update to Github CI workflow `cont_integration.yml` by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action
* [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
Users with large wallet and/or complex descriptors may experience slow startup of `KeychainTxOutIndex`. This PR addresses this problem by providing the option to persist derived spks so that they no longer need to be re-derived on startup.
The `IndexedTxGraph` API has been changed for better ergonomics.
Compared to #1960, this is a more longterm solution that does not depend on multi-threading logic.
### Changelog notice
```md
Changed
- `KeychainTxOutIndex::new` to take in an additional parameter `persist_spks` to control whether derived spks are cached and persisted across restarts. The default of `persist_spks` is false.
- `KeychainTxOutIndex` methods (`lookahead_to_target, `next_unused_spk`, `reveal_next_spk`) now return changesets as they may derive spks to be persisted.
- The `InsertDescriptorError` type now wraps descriptors in `Box` to reduce enum size.
Added
- `spk_cache` field to `indexer::keychain_txout::ChangeSet` which persists derived spks.
- `IndexedTxGraph::from_changeset` - allows constructing from `indexed_tx_graph::ChangeSet` and only indexing when ready.
- `IndexedTxGraph::reindex` method.
Fixed
- `KeychainTxOutIndex::reveal_to_target` so that it actually returns `None` if the `keychain` does not exist.
```
### 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
Adds missing persistence for `first_seen`, which was not included in #1950.
### Changelog notice
- Adds `first_seen` column to the `bdk_txs` table via schema v3 migration.
- Updates `from_sqlite()` and `persist_to_sqlite()` to handle `first_seen`.
- Updates the v0-to-v3 migration test to verify compatibility with older schemas.
### 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:
* [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