`BdkElectrumClient::populate_with_txids` queries each transaction's confirmation status by calling `script_get_history` on the script of one of its outputs. It currently picks the first output unconditionally. This breaks for transactions which first output is an `OP_RETURN`, because Electrum servers don't index `OP_RETURN` scripts and will return an empty history. This is a real-world scenario: protocols like RGB place an `OP_RETURN` commitment as the first output of every transaction.
### Notes to the reviewers
The fix selects the first output which script is not `OP_RETURN` or a `OP_FALSE OP_RETURN`. If a transaction has only `OP_RETURN`/`OP_FALSE OP_RETURN` outputs, we fall back to the script of any input's previous output to query history. The only case still skipped is a coinbase with all unindexed outputs, since coinbases have no parent to fall back on.
### Changelog notice
```
Fixed:
- `BdkElectrumClient::sync` now correctly retrieves confirmation status for transactions which first output is an `OP_RETURN` or `OP_FALSE OP_RETURN`
```
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
When a reorg drops the agreement point below `start_height`, the emitter would skip directly to `start_height`, producing a checkpoint that could not connect with the caller's local chain (`CannotConnectError`).
This affects callers that create a new `Emitter` on each sync with `start_height = tip_height` — a common pattern.
**Fix:** Override `start_height` to the agreement height when a reorg is detected (agreement point below both `start_height` and `last_cp`), so the emitter revisits the invalidated block heights.
The key change is in `poll()` in `crates/bitcoind_rpc/src/lib.rs`: when `AgreementFound` is handled and the agreement point is below both `start_height` and `last_cp.height()`, we lower `start_height` to the agreement height. This ensures the emitter emits the invalidated blocks instead of skipping over them.
### Changelog notice
```md
Fixed:
- `Emitter` producing un-connectable checkpoints when `start_height` is above the agreement point after a reorg.
```
### 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
* [x] I've added tests to reproduce the issue which are now passing
* [x] I'm linking the issue being fixed by this PR
Fixes #2057. `full_scan` now always covers the revealed range before applying the stop_gap
### Notes to the reviewers
Replaces #2181. That PR unified full_scan and sync into one path; per @evanlinjin's feedback we're keeping them separate and doing the minimal fix here instead
### Changelog notice
Fixed: full_scan now always scans the full revealed range before applying stop_gap past last_revealed.
### 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
* [x] I've added tests to reproduce the issue which are now passing
* [x] I'm linking the issue being fixed by this PR
An Electrum server could return an arbitrary transaction when `fetch_tx()` requests a specific txid. The returned transaction was cached and used without verifying that its computed txid matches the requested one.
Add a verification check that `tx.compute_txid() == txid` after fetching from the server, returning an error on mismatch. Include a unit test with a mock Electrum client that exercises both the mismatch rejection and the matching-txid happy path.
Elias Rohrer [Thu, 23 Apr 2026 16:54:52 +0000 (18:54 +0200)]
fix(electrum): verify txid of server-returned transactions
An Electrum server could return an arbitrary transaction when
`fetch_tx()` requests a specific txid. The returned transaction was
cached and used without verifying that its computed txid matches the
requested one.
Add a verification check that `tx.compute_txid() == txid` after
fetching from the server, returning an error on mismatch.
fix(bitcoind_rpc): emit invalidated heights when start_height is above agreement point
When a reorg drops the agreement point below `start_height`, the emitter
would skip directly to `start_height`, producing a checkpoint that could
not connect with the caller's local chain (`CannotConnectError`).
Fix: override `start_height` to the agreement height when a reorg is
detected (agreement point below both `start_height` and `last_cp`), so
the emitter revisits the invalidated block heights.
The start and end bound calculations used unchecked addition which
overflows when given `u32::MAX`, causing the iterator to silently produce
wrong results (e.g., an empty iterator for `0..=u32::MAX` in release
mode). Use `saturating_add` to handle the boundary correctly.
### 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
* [x] I've added tests to reproduce the issue which are now passing
* [ ] I'm linking the issue being fixed by this PR
Elias Rohrer [Wed, 8 Apr 2026 09:42:39 +0000 (11:42 +0200)]
fix(chain): prevent integer overflow in `SpkIterator::new_with_range`
The start and end bound calculations used unchecked addition which
overflows when given `u32::MAX`, causing the iterator to silently produce
wrong results (e.g., an empty iterator for `0..=u32::MAX` in release
mode). Use `saturating_add` to handle the boundary correctly.
Co-Authored-By: HAL 9000 Signed-off-by: Elias Rohrer <dev@tnull.de>
Closes #2021
Related to #2076
Replaces #2024
Replaces #2091
### Description
This PR adds `prev_blockhash` awareness to `CheckPoint`, enabling proper chain validation when merging checkpoint chains that store block headers or similar data with previous block hash information.
### Notes to the reviewers
This PR replaces some prior attempts:
* #2024 - where we made the `CheckPoint::data` optional - however this resulted in internal complexity and an API with annoying edge cases. The tests from this PR were still useful.
* #2091 - This second attempt had some good ideas, but was distracted from the goal of #2021. I mostly reused the `CheckPoint::insert` implementation of that PR.
### Changelog notice
```md
Added:
- `ToBlockHash::prev_blockhash()` - optional method to expose previous block hash
- `CheckPointEntry` - new type for iterating with `prev_blockhash` awareness, yielding "placeholder" entries for heights inferred from `prev_blockhash`
- `ApplyBlockError` - this is a new error type with two variants; `MissingGenesis` and `PrevBlockhashMismatch`. The second variant is a new error case introduced by `prev_blockhash` awareness.
Changed:
- `CheckPoint::push` - now errors when `prev_blockhash` conflicts with current tip (contiguous heights)
- `CheckPoint::insert` - now evicts/displaces checkpoints on `prev_blockhash` conflict
- `merge_chains` - now validates `prev_blockhash` consistency when merging
- `LocalChain<D>` generic parameter - relaxed constraint to `D: Clone` instead of `D: Copy`.
Fixed:
- `merge_chains` no longer replaces the genesis block.
```
### 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
docs: address review feedback on `prev_blockhash` validation
- Clarify `CheckPoint::insert` eviction semantics when `data.prev_blockhash`
conflicts with the checkpoint at `height - 1`.
- Explain placeholder handling in `merge_chains` conflict branch where
`u.data()` may legitimately insert `None`.
- Preserve mismatch height in `merge_chains`' fallback so release-mode
callers get a useful `try_include_height` instead of `0`.
- Reframe the "update displaces invalid block" test comment to make the
best-effort recovery intent explicit.
- Derive `PartialEq` on `CheckPointEntry` and fix a broken intra-doc link.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
docs(core): address review feedback on docs and tests
Address suggestions by @nymius:
- Add `Returns` and `Errors` doc sections to `CheckPoint::from_blocks`
- Add test assertions for chain integrity after failed push and chain
length after successful push
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
志宇 [Wed, 18 Feb 2026 17:33:29 +0000 (17:33 +0000)]
fix(chain)!: make genesis immutable in `merge_chains`
Prevent `merge_chains` from replacing the genesis block when original
and update disagree on the genesis hash. This aligns with
`CheckPoint::insert` which already panics on genesis replacement.
Also update the "fix blockhash before agreement point" test to operate
at a non-genesis height and add a new test for conflicting genesis.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
docs(core): Add module-level docs for `checkpoint_entry`
Explain the purpose of `CheckPointEntry` and its two variants:
- `Occupied`: real checkpoint at this height
- `Placeholder`: implied by `prev_blockhash` from checkpoint above
Also fix typo: "atleast" → "at least"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(chain)!: Add `ApplyBlockError` for `prev_blockhash` validation
Introduce `ApplyBlockError` enum with two variants:
- `MissingGenesis`: genesis block is missing or would be altered
- `PrevBlockhashMismatch`: block's `prev_blockhash` doesn't match expected
This replaces `MissingGenesisError` in several `LocalChain` methods:
- `from_blocks`
- `from_changeset`
- `apply_changeset`
Also adds test cases for `merge_chains` with `prev_blockhash` scenarios:
- Update displaces invalid block below point of agreement
- Update fills gap with matching `prev_blockhash`
- Cascading eviction through multiple blocks
🤖 Generated with [Claude Code](https://claude.com/claude-code)
test(core): add tests for CheckPoint::push and insert methods
Add comprehensive tests for CheckPoint::push error cases:
- Push fails when height is not greater than current
- Push fails when prev_blockhash conflicts with self
- Push succeeds when prev_blockhash matches
Include tests for CheckPoint::insert conflict handling:
- Insert with conflicting prev_blockhash
- Insert purges conflicting tail
- Insert between conflicting checkpoints
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: valued mammal <valuedmammal@protonmail.com>
test(chain): make `TestLocalChain` generic and add `prev_blockhash` test
Make `TestLocalChain` and `ExpectedResult` generic over checkpoint data
type `D`, allowing the same test infrastructure to work with both
`BlockHash` and `TestBlock` types.
Add `merge_chains_with_prev_blockhash` test to verify that `prev_blockhash`
correctly invalidates conflicting blocks and connects disjoint chains.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Automated update to Github CI workflow `cont_integration.yml` by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 8.0.0 to 8.1.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/peter-evans/create-pull-request/releases">peter-evans/create-pull-request's releases</a>.</em></p>
<blockquote>
<h2>Create Pull Request v8.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>README.md: bump given GitHub actions to their latest versions by <a href="https://github.com/deining"><code>@deining</code></a> in <a href="https://redirect.github.com/peter-evans/create-pull-request/pull/4265">peter-evans/create-pull-request#4265</a></li>
<li>build(deps): bump the github-actions group with 2 updates by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/peter-evans/create-pull-request/pull/4273">peter-evans/create-pull-request#4273</a></li>
<li>build(deps-dev): bump the npm group with 2 updates by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/peter-evans/create-pull-request/pull/4274">peter-evans/create-pull-request#4274</a></li>
<li>build(deps-dev): bump undici from 6.22.0 to 6.23.0 by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/peter-evans/create-pull-request/pull/4284">peter-evans/create-pull-request#4284</a></li>
<li>Update distribution by <a href="https://github.com/actions-bot"><code>@actions-bot</code></a> in <a href="https://redirect.github.com/peter-evans/create-pull-request/pull/4289">peter-evans/create-pull-request#4289</a></li>
<li>fix: Handle remote prune failures gracefully on self-hosted runners by <a href="https://github.com/peter-evans"><code>@peter-evans</code></a> in <a href="https://redirect.github.com/peter-evans/create-pull-request/pull/4295">peter-evans/create-pull-request#4295</a></li>
<li>feat: add <code>@octokit/plugin-retry</code> to handle retriable server errors by <a href="https://github.com/peter-evans"><code>@peter-evans</code></a> in <a href="https://redirect.github.com/peter-evans/create-pull-request/pull/4298">peter-evans/create-pull-request#4298</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/deining"><code>@deining</code></a> made their first contribution in <a href="https://redirect.github.com/peter-evans/create-pull-request/pull/4265">peter-evans/create-pull-request#4265</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/peter-evans/create-pull-request/compare/v8.0.0...v8.1.0">https://github.com/peter-evans/create-pull-request/compare/v8.0.0...v8.1.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/peter-evans/create-pull-request/commit/c0f553fe549906ede9cf27b5156039d195d2ece0"><code>c0f553f</code></a> feat: add <code>@octokit/plugin-retry</code> to handle retriable server errors (<a href="https://redirect.github.com/peter-evans/create-pull-request/issues/4298">#4298</a>)</li>
<li><a href="https://github.com/peter-evans/create-pull-request/commit/70001242bfa9ec7844891e620fdda69a2a2a06c7"><code>7000124</code></a> fix: Handle remote prune failures gracefully (<a href="https://redirect.github.com/peter-evans/create-pull-request/issues/4295">#4295</a>)</li>
<li><a href="https://github.com/peter-evans/create-pull-request/commit/34aa40e9cf0bb8b5be745a552003fdeb25e4dd3a"><code>34aa40e</code></a> build: update distribution (<a href="https://redirect.github.com/peter-evans/create-pull-request/issues/4289">#4289</a>)</li>
<li><a href="https://github.com/peter-evans/create-pull-request/commit/641099ddca097df58c3369dd5e1f33322b223029"><code>641099d</code></a> build(deps-dev): bump undici from 6.22.0 to 6.23.0 (<a href="https://redirect.github.com/peter-evans/create-pull-request/issues/4284">#4284</a>)</li>
<li><a href="https://github.com/peter-evans/create-pull-request/commit/2271f1ddcf09437ed8f019733eb5cfba58ac76f0"><code>2271f1d</code></a> build(deps-dev): bump the npm group with 2 updates (<a href="https://redirect.github.com/peter-evans/create-pull-request/issues/4274">#4274</a>)</li>
<li><a href="https://github.com/peter-evans/create-pull-request/commit/437c31a11dd02128dd37633ad8d3832853477e7a"><code>437c31a</code></a> build(deps): bump the github-actions group with 2 updates (<a href="https://redirect.github.com/peter-evans/create-pull-request/issues/4273">#4273</a>)</li>
<li><a href="https://github.com/peter-evans/create-pull-request/commit/0979079bc20c05bbbb590a56c21c4e2b1d1f1bbe"><code>0979079</code></a> docs: update readme</li>
<li><a href="https://github.com/peter-evans/create-pull-request/commit/5b751cdf403b4f0314c656b2618939e4c8bdf824"><code>5b751cd</code></a> README.md: bump given GitHub actions to their latest versions (<a href="https://redirect.github.com/peter-evans/create-pull-request/issues/4265">#4265</a>)</li>
<li>See full diff in <a href="https://github.com/peter-evans/create-pull-request/compare/98357b18bf14b5342f975ff684046ec3b2a07725...c0f553fe549906ede9cf27b5156039d195d2ece0">compare view</a></li>
</ul>
</details>
<br />
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>v7 What's new</h2>
<h3>Direct Uploads</h3>
<p>Adds support for uploading single files directly (unzipped). Callers can set the new <code>archive</code> parameter to <code>false</code> to skip zipping the file during upload. Right now, we only support single files. The action will fail if the glob passed resolves to multiple files. The <code>name</code> parameter is also ignored with this setting. Instead, the name of the artifact will be the name of the uploaded file.</p>
<h3>ESM</h3>
<p>To support new versions of the <code>@actions/*</code> packages, we've upgraded the package to ESM.</p>
<h2>What's Changed</h2>
<ul>
<li>Add proxy integration test by <a href="https://github.com/Link"><code>@Link</code></a>- in <a href="https://redirect.github.com/actions/upload-artifact/pull/754">actions/upload-artifact#754</a></li>
<li>Upgrade the module to ESM and bump dependencies by <a href="https://github.com/danwkennedy"><code>@danwkennedy</code></a> in <a href="https://redirect.github.com/actions/upload-artifact/pull/762">actions/upload-artifact#762</a></li>
<li>Support direct file uploads by <a href="https://github.com/danwkennedy"><code>@danwkennedy</code></a> in <a href="https://redirect.github.com/actions/upload-artifact/pull/764">actions/upload-artifact#764</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Link"><code>@Link</code></a>- made their first contribution in <a href="https://redirect.github.com/actions/upload-artifact/pull/754">actions/upload-artifact#754</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/actions/upload-artifact/compare/v6...v7.0.0">https://github.com/actions/upload-artifact/compare/v6...v7.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/actions/upload-artifact/commit/bbbca2ddaa5d8feaa63e36b76fdaad77386f024f"><code>bbbca2d</code></a> Support direct file uploads (<a href="https://redirect.github.com/actions/upload-artifact/issues/764">#764</a>)</li>
<li><a href="https://github.com/actions/upload-artifact/commit/589182c5a4cec8920b8c1bce3e2fab1c97a02296"><code>589182c</code></a> Upgrade the module to ESM and bump dependencies (<a href="https://redirect.github.com/actions/upload-artifact/issues/762">#762</a>)</li>
<li><a href="https://github.com/actions/upload-artifact/commit/47309c993abb98030a35d55ef7ff34b7fa1074b5"><code>47309c9</code></a> Merge pull request <a href="https://redirect.github.com/actions/upload-artifact/issues/754">#754</a> from actions/Link-/add-proxy-integration-tests</li>
<li><a href="https://github.com/actions/upload-artifact/commit/02a8460834e70dab0ce194c64360c59dc1475ef0"><code>02a8460</code></a> Add proxy integration test</li>
<li>See full diff in <a href="https://github.com/actions/upload-artifact/compare/v6...v7">compare view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
This PR adds new CI job `check-docs` to validate that documentation builds for all workspace packages, also adds a new justfile recipe `just doc`.
It also fixes the existing errors in `bdk_chain` and `bdk_core`.
### Changelog notice
```
### Added
- ci: add new `check-docs` job.
### Changed
- fix(docs): in `keychain_txout.rs` and `spk_client.rs`
```
### 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
#### 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
Previously `fetch_txs_with_outpoints` collected spend txids into a Vec, so the same txid could be pushed multiple times when one transaction spent several input outpoints. This caused redundant `get_tx_info` calls to Esplora for the same transaction, wasting network and CPU without changing the resulting `TxUpdate`.
Use `HashSet<Txid>` for `missing_txs` in both async and blocking `fetch_txs_with_outpoints,` so each txid is only requested once while keeping the observable behaviour of `SyncResponse` / `TxUpdate` unchanged.
### Changelog notice
```
### Changed
- Use `HashSet` instead of `Vec` to track `missing_txs` in bdk_esplora, it deduplicates txids.
```
### 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:
* [ ] 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
Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2 to 3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/actions/create-github-app-token/releases">actions/create-github-app-token's releases</a>.</em></p>
<blockquote>
<h2>v3.0.0</h2>
<h1><a href="https://github.com/actions/create-github-app-token/compare/v2.2.2...v3.0.0">3.0.0</a> (2026-03-14)</h1>
<ul>
<li>feat!: node 24 support (<a href="https://redirect.github.com/actions/create-github-app-token/issues/275">#275</a>) (<a href="https://github.com/actions/create-github-app-token/commit/2e564a0bb8e7cc2b907b2401a2afe177882d4325">2e564a0</a>)</li>
<li>fix!: require <code>NODE_USE_ENV_PROXY</code> for proxy support (<a href="https://redirect.github.com/actions/create-github-app-token/issues/342">#342</a>) (<a href="https://github.com/actions/create-github-app-token/commit/4451bcbc139f8124b0bf04f968ea2586b17df458">4451bcb</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>remove custom proxy handling (<a href="https://redirect.github.com/actions/create-github-app-token/issues/143">#143</a>) (<a href="https://github.com/actions/create-github-app-token/commit/dce0ab05f36f30b22fd14289fd36655c618e4e8e">dce0ab0</a>)</li>
</ul>
<h3>BREAKING CHANGES</h3>
<ul>
<li>Custom proxy handling has been removed. If you use HTTP_PROXY or HTTPS_PROXY, you must now also set NODE_USE_ENV_PROXY=1 on the action step.</li>
<li>Requires <a href="https://github.com/actions/runner/releases/tag/v2.327.1">Actions Runner v2.327.1</a> or later if you are using a self-hosted runner.</li>
</ul>
<h2>v3.0.0-beta.6</h2>
<h1><a href="https://github.com/actions/create-github-app-token/compare/v3.0.0-beta.5...v3.0.0-beta.6">3.0.0-beta.6</a> (2026-03-13)</h1>
<h3>Bug Fixes</h3>
<ul>
<li><strong>deps:</strong> bump <code>@actions/core</code> from 1.11.1 to 3.0.0 (<a href="https://redirect.github.com/actions/create-github-app-token/issues/337">#337</a>) (<a href="https://github.com/actions/create-github-app-token/commit/b04413352d4644ac2131b9a90c074f5e93ca18a1">b044133</a>)</li>
<li><strong>deps:</strong> bump minimatch from 9.0.5 to 9.0.9 (<a href="https://redirect.github.com/actions/create-github-app-token/issues/335">#335</a>) (<a href="https://github.com/actions/create-github-app-token/commit/5cbc65624c9ddc4589492bda7c8b146223e8c3e4">5cbc656</a>)</li>
<li><strong>deps:</strong> bump the production-dependencies group with 4 updates (<a href="https://redirect.github.com/actions/create-github-app-token/issues/336">#336</a>) (<a href="https://github.com/actions/create-github-app-token/commit/6bda5bc1410576b9a0879ce6076d53345485bba9">6bda5bc</a>)</li>
<li><strong>deps:</strong> bump undici from 7.16.0 to 7.18.2 (<a href="https://redirect.github.com/actions/create-github-app-token/issues/323">#323</a>) (<a href="https://github.com/actions/create-github-app-token/commit/b4f638f48ee0dcdbb0bc646c48e4cb2a2de847fe">b4f638f</a>)</li>
</ul>
<h2>v3.0.0-beta.5</h2>
<h1><a href="https://github.com/actions/create-github-app-token/compare/v3.0.0-beta.4...v3.0.0-beta.5">3.0.0-beta.5</a> (2026-03-13)</h1>
<ul>
<li>fix!: require <code>NODE_USE_ENV_PROXY</code> for proxy support (<a href="https://redirect.github.com/actions/create-github-app-token/issues/342">#342</a>) (<a href="https://github.com/actions/create-github-app-token/commit/d53a1cdfde844c958786293adcaf739ecb8b5eb9">d53a1cd</a>)</li>
</ul>
<h3>BREAKING CHANGES</h3>
<ul>
<li>Custom proxy handling has been removed. If you use HTTP_PROXY or HTTPS_PROXY, you must now also set NODE_USE_ENV_PROXY=1 on the action step.</li>
</ul>
<h2>v3.0.0-beta.4</h2>
<h1><a href="https://github.com/actions/create-github-app-token/compare/v3.0.0-beta.3...v3.0.0-beta.4">3.0.0-beta.4</a> (2026-03-13)</h1>
<h3>Bug Fixes</h3>
<ul>
<li><strong>deps:</strong> bump <code>@octokit/auth-app</code> from 7.2.1 to 8.0.1 (<a href="https://redirect.github.com/actions/create-github-app-token/issues/257">#257</a>) (<a href="https://github.com/actions/create-github-app-token/commit/bef1eaf1c0ac2b148ee2a0a74c65fbe6db0631f1">bef1eaf</a>)</li>
<li><strong>deps:</strong> bump <code>@octokit/request</code> from 9.2.3 to 10.0.2 (<a href="https://redirect.github.com/actions/create-github-app-token/issues/256">#256</a>) (<a href="https://github.com/actions/create-github-app-token/commit/5d7307be63501c0070c634b0ae8fec74e8208130">5d7307b</a>)</li>
<li><strong>deps:</strong> bump glob from 10.4.5 to 10.5.0 (<a href="https://redirect.github.com/actions/create-github-app-token/issues/305">#305</a>) (<a href="https://github.com/actions/create-github-app-token/commit/5480f4325a18c025ee16d7e081413854624e9edc">5480f43</a>)</li>
<li><strong>deps:</strong> bump p-retry from 6.2.1 to 7.1.0 (<a href="https://redirect.github.com/actions/create-github-app-token/issues/294">#294</a>) (<a href="https://github.com/actions/create-github-app-token/commit/dce3be8b284f45e65caed11a610e2bef738d15b4">dce3be8</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/actions/create-github-app-token/commit/f8d387b68d61c58ab83c6c016672934102569859"><code>f8d387b</code></a> build(release): 3.0.0 [skip ci]</li>
<li><a href="https://github.com/actions/create-github-app-token/commit/d2129bd463d4feb8723edeea9437baa7db58e41e"><code>d2129bd</code></a> style: remove extra blank line in release workflow</li>
<li><a href="https://github.com/actions/create-github-app-token/commit/77b94efc3e5f99a45abdd163fe04a4ebb95e98d6"><code>77b94ef</code></a> build: refresh generated artifacts</li>
<li><a href="https://github.com/actions/create-github-app-token/commit/3ab4c6689898955f913a485593b36b197c6dbbdc"><code>3ab4c66</code></a> chore: move undici to devDependencies</li>
<li><a href="https://github.com/actions/create-github-app-token/commit/739cf66feb937a443e4b6b7626bedd98f9fef6df"><code>739cf66</code></a> docs: update README action versions</li>
<li><a href="https://github.com/actions/create-github-app-token/commit/db40289976a36527816d4f6f45765fdee71f134b"><code>db40289</code></a> build(deps): bump actions versions in test.yml</li>
<li><a href="https://github.com/actions/create-github-app-token/commit/496a7ac4eb472eeac44d67818d1ce7f5e9e5fc97"><code>496a7ac</code></a> test: migrate from AVA to Node.js native test runner (<a href="https://redirect.github.com/actions/create-github-app-token/issues/346">#346</a>)</li>
<li><a href="https://github.com/actions/create-github-app-token/commit/3870dc3051e3f1fc3a2faa17bcbb00f31fe1dd6c"><code>3870dc3</code></a> Rename end-to-end proxy job in test workflow</li>
<li><a href="https://github.com/actions/create-github-app-token/commit/4451bcbc139f8124b0bf04f968ea2586b17df458"><code>4451bcb</code></a> fix!: require <code>NODE_USE_ENV_PROXY</code> for proxy support (<a href="https://redirect.github.com/actions/create-github-app-token/issues/342">#342</a>)</li>
<li><a href="https://github.com/actions/create-github-app-token/commit/dce0ab05f36f30b22fd14289fd36655c618e4e8e"><code>dce0ab0</code></a> fix: remove custom proxy handling (<a href="https://redirect.github.com/actions/create-github-app-token/issues/143">#143</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/actions/create-github-app-token/compare/v2...v3">compare view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Bumps [Swatinem/rust-cache](https://github.com/swatinem/rust-cache) from 2.8.2 to 2.9.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/swatinem/rust-cache/releases">Swatinem/rust-cache's releases</a>.</em></p>
<blockquote>
<h2>v2.9.1</h2>
<p>Fix regression in hash calculation</p>
<p><strong>Full Changelog</strong>: <a href="https://github.com/Swatinem/rust-cache/compare/v2.9.0...v2.9.1">https://github.com/Swatinem/rust-cache/compare/v2.9.0...v2.9.1</a></p>
<h2>v2.9.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add support for running rust-cache commands from within a Nix shell by <a href="https://github.com/marc0246"><code>@marc0246</code></a> in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/290">Swatinem/rust-cache#290</a></li>
<li>Bump taiki-e/install-action from 2.62.57 to 2.62.60 in the actions group by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/291">Swatinem/rust-cache#291</a></li>
<li>Bump the actions group across 1 directory with 5 updates by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/296">Swatinem/rust-cache#296</a></li>
<li>Bump the prd-major group with 3 updates by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/294">Swatinem/rust-cache#294</a></li>
<li>Bump <code>@types/node</code> from 24.10.1 to 25.0.2 in the dev-major group by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/295">Swatinem/rust-cache#295</a></li>
<li>Consider all installed toolchains in cache key by <a href="https://github.com/tamird"><code>@tamird</code></a> in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/293">Swatinem/rust-cache#293</a></li>
<li>Compare case-insenitively for full cache key match by <a href="https://github.com/kbriggs"><code>@kbriggs</code></a> in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/303">Swatinem/rust-cache#303</a></li>
<li>Migrate to <code>node24</code> runner by <a href="https://github.com/rhysd"><code>@rhysd</code></a> in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/314">Swatinem/rust-cache#314</a></li>
<li>Bump the actions group across 1 directory with 7 updates by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/312">Swatinem/rust-cache#312</a></li>
<li>Bump the prd-minor group across 1 directory with 2 updates by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/307">Swatinem/rust-cache#307</a></li>
<li>Bump <code>@types/node</code> from 25.0.2 to 25.2.2 in the dev-minor group by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/309">Swatinem/rust-cache#309</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/marc0246"><code>@marc0246</code></a> made their first contribution in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/290">Swatinem/rust-cache#290</a></li>
<li><a href="https://github.com/tamird"><code>@tamird</code></a> made their first contribution in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/293">Swatinem/rust-cache#293</a></li>
<li><a href="https://github.com/kbriggs"><code>@kbriggs</code></a> made their first contribution in <a href="https://redirect.github.com/Swatinem/rust-cache/pull/303">Swatinem/rust-cache#303</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/Swatinem/rust-cache/compare/v2.8.2...v2.9.0">https://github.com/Swatinem/rust-cache/compare/v2.8.2...v2.9.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md">Swatinem/rust-cache's changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>2.9.1</h2>
<ul>
<li>Fix regression in hash calculation</li>
</ul>
<h2>2.9.0</h2>
<ul>
<li>Update to <code>node24</code></li>
<li>Support running from within a <code>nix</code> shell</li>
<li>Consider all installed toolchains for cache key</li>
<li>Use case-insensitive comparison to determine exact cache hit</li>
</ul>
<h2>2.8.2</h2>
<ul>
<li>Don't overwrite env for cargo-metadata call</li>
</ul>
<h2>2.8.1</h2>
<ul>
<li>Set empty <code>CARGO_ENCODED_RUSTFLAGS</code> when retrieving metadata</li>
<li>Various dependency updates</li>
</ul>
<h2>2.8.0</h2>
<ul>
<li>Add support for <code>warpbuild</code> cache provider</li>
<li>Add new <code>cache-workspace-crates</code> feature</li>
</ul>
<h2>2.7.8</h2>
<ul>
<li>Include CPU arch in the cache key</li>
</ul>
<h2>2.7.7</h2>
<ul>
<li>Also cache <code>cargo install</code> metadata</li>
</ul>
<h2>2.7.6</h2>
<ul>
<li>Allow opting out of caching $CARGO_HOME/bin</li>
<li>Add runner OS in cache key</li>
<li>Adds an option to do lookup-only of the cache</li>
</ul>
<h2>2.7.5</h2>
<ul>
<li>Support Cargo.lock format cargo-lock v4</li>
<li>Only run macOsWorkaround() on macOS</li>
</ul>
<h2>2.7.3</h2>
<ul>
<li>Work around upstream problem that causes cache saving to hang for minutes.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/Swatinem/rust-cache/commit/c19371144df3bb44fab255c43d04cbc2ab54d1c4"><code>c193711</code></a> 2.9.1</li>
<li><a href="https://github.com/Swatinem/rust-cache/commit/781e8d91ab29deb65464798965e49853f963b561"><code>781e8d9</code></a> try reverting pipeline change</li>
<li><a href="https://github.com/Swatinem/rust-cache/commit/3d1fa4654a5786f5537b1d31acd0f35e56de9924"><code>3d1fa46</code></a> add changelog</li>
<li><a href="https://github.com/Swatinem/rust-cache/commit/c676846f29d98ff6b0106d3608c7ffd4048af17b"><code>c676846</code></a> 2.9.0</li>
<li><a href="https://github.com/Swatinem/rust-cache/commit/bf71d02c11df9d5253618f39943e9dd59f7fd5a9"><code>bf71d02</code></a> bump dependencies and rebuild</li>
<li><a href="https://github.com/Swatinem/rust-cache/commit/8a02ed5e290d8afc7e587930243f3016b3223f50"><code>8a02ed5</code></a> Bump <code>@types/node</code> from 25.0.2 to 25.2.2 in the dev-minor group (<a href="https://redirect.github.com/swatinem/rust-cache/issues/309">#309</a>)</li>
<li><a href="https://github.com/Swatinem/rust-cache/commit/390157d4874246aff722dd7f77e641fcae197678"><code>390157d</code></a> Bump the prd-minor group across 1 directory with 2 updates (<a href="https://redirect.github.com/swatinem/rust-cache/issues/307">#307</a>)</li>
<li><a href="https://github.com/Swatinem/rust-cache/commit/68500c182e89a3f56d9b1de095d7e62f0ea5b8bf"><code>68500c1</code></a> Bump the actions group across 1 directory with 7 updates (<a href="https://redirect.github.com/swatinem/rust-cache/issues/312">#312</a>)</li>
<li><a href="https://github.com/Swatinem/rust-cache/commit/1a8384176d7ed15c323a201c65073983cdb5a5be"><code>1a83841</code></a> Migrate to <code>node24</code> runner (<a href="https://redirect.github.com/swatinem/rust-cache/issues/314">#314</a>)</li>
<li><a href="https://github.com/Swatinem/rust-cache/commit/11da8522bc3856a8fbc565f1d1530989c793d67d"><code>11da852</code></a> Compare case-insenitively for full cache key match (<a href="https://redirect.github.com/swatinem/rust-cache/issues/303">#303</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/swatinem/rust-cache/compare/779680da715d629ac1d338a641029a2f4372abb5...c19371144df3bb44fab255c43d04cbc2ab54d1c4">compare view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
This introduces clear temporal context **documentation** to the `TxUpdate` struct, explicitly stating that entries must have either `anchors` or `seen_ats` to be considered canonical and contribute to wallet balances.
It also explicitly documents the `seen_ats` HashSet signature to prevent usage errors when writing custom chain sources.
This fulfills the recommendation outlined in the Wizardsardine BDK Audit Report (Q4 2024).
### Description
This primarily affects developers building **custom chain sources** — anyone constructing `Update` structs outside of `bdk_electrum`/`bdk_esplora`/`bdk_bitcoind_rpc`.
As the ecosystem grows (streaming Electrum, Nostr relay sync, compact block filters, custom backends), more developers will encounter this undocumented contract.
### What I Changed
*1. Doc comment on `TxUpdate` struct*
* **`anchors` or `seen_ats`** are stored in the graph but do not affect the balance.
* **`seen_ats` collection type**: `TxUpdate::seen_ats` is a `BTreeSet<(Txid, u64)>`, requiring `.insert((txid, timestamp))`.
*2. Doc comment on `Wallet::apply_update()`*
* **TxGraph `apply_update`**: transactions without temporal context note.
* **IndexedTxGraph `apply_update`**: transactions without temporal context note.
### Impact
This is just a documentation fix - no code changes, no breaking changes.
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
This introduces clear temporal context documentation to the `TxUpdate`
struct, explicitly stating that entries must have either `anchors` or
`seen_ats` to be considered canonical and contribute to wallet balances.
This fulfills the recommendation outlined in the Wizardsardine
BDK Audit Report (Q4 2024).
Signed-off-by: Rafael Turon <3598269+rafaelturon@users.noreply.github.com>
The blanket `Anchor` impl for `&A` was missing the `confirmation_height_upper_bound` method, causing it to fall back to the default implementation instead of delegating to the inner type.
### Changelog notice
```md
Fixed:
- The `Anchor::confirmation_height_upper_bound` impl was missing for `&A`, causing it to fallback to the default impl.
```
### 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~~
志宇 [Sat, 14 Feb 2026 00:21:20 +0000 (00:21 +0000)]
fix(chain): forward `confirmation_height_upper_bound` in `Anchor` impl for `&A`
The blanket `Anchor` impl for `&A` was missing the
`confirmation_height_upper_bound` method, causing it to fall back to
the default implementation instead of delegating to the inner type.
I didn't realize #2053 didn't actually compile when I merged it. This PR fixes this by bumping `esplora_client` to `0.12.3` so that the `.get_block_infos` method is always available.
### Changelog
```md
Fixed:
- Bump `esplora_client` to `0.12.3` so that the `.get_block_infos` method is always available.
```
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
Add `mine_block` to `bdk_testenv::Env` with custom timestamp and coinbase address. This allows us to test timelocked transactions.
### Changelog notice
```md
Added
- `mine_block` method to `bdk_testenv::Env` with custom `MineParams`. Blocks can be mined with no transactions, contain custom timestamp and custom coinbase address.
- `min_time_for_next_block` and `get_block_template` helper methods.
```
### 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
志宇 [Sat, 24 Jan 2026 10:20:23 +0000 (10:20 +0000)]
feat(testenv): add `mine_block` with custom timestamp and coinbase address
Refactor block mining in `TestEnv` to use `getblocktemplate` RPC properly:
- Add `MineParams` struct to configure mining (empty blocks, custom
timestamp, custom coinbase address)
- Add `mine_block()` method that builds blocks from the template with
proper BIP34 coinbase scriptSig, witness commitment, and merkle root
- Add `min_time_for_next_block()` and `get_block_template()` helpers
- Refactor `mine_empty_block()` to use the new `mine_block()` API
- Include mempool transactions when `empty: false`
<!-- You can erase any parts of this template not applicable to your Pull Request. -->
### Description
This PR addresses a panic path in stop gap scan loop. Removes `expect` used to compute gap boundary and instead tracks `consecutive_unused` with `gap_limit = stop_gap.max(1)` to decide when to stop scanning.
Spurred by trying to address https://github.com/bitcoindevkit/bdk_wallet/issues/30 for Esplora
### Notes to the reviewers
Open to any and all feedback on this.
Behavior is unchanged for typical cases, it just avoids a panic in the control flow.
### Changelog notice
```
### Fix:
- Avoid a panic in the Esplora stop‑gap scan loop by tracking consecutive unused scripts to compute the gap boundary.
```
### 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:
* [ ] 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
The `get_blocks` method from `esplora-client` has been deprecated on the latest release `v0.12.3`. I'm updating it to use newly added one: `get_blocks_infos` in order to fix the deprecation warning.
### Changelog notice
```
### Changed
- fix(bdk_esplora): use `get_block_infos` instead of deprecated `get_blocks`
```
### 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
Automated update to Github CI workflow `cont_integration.yml` by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action
Implement spent_txouts and created_txouts methods on SpkTxOutIndex and KeychainTxOutIndex. These methods return SpentTxOut and CreatedTxOut structs allowing callers to access complete transaction output information including script pubkeys and values.
### Notes to the reviewers
This info is useful to users who use the new WalletEvent data in bitcoindevkit/bdk_wallet#319. In particular to determine the addresses and amounts for TxOuts that are sent/spent or have been received in a newly seen or confirmed transaction. See: [bdk_wallet#319 comment](https://github.com/bitcoindevkit/bdk_wallet/pull/319#issuecomment-3630027488)
If/when this PR is merged I'll make a corresponding one to `bdk_wallet::Wallet`.
### Changelog notice
Added
* New spent_txouts and created_txouts methods on SpkTxOutIndex and KeychainTxOutIndex.
* New SpentTxOut and CreatedTxOut structs returned by spent_txouts and created_txouts functions.
### 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
Add CODEOWNERS file with both primary and secondary maintainers for repo files with overrides for specific sub-crates. See: https://github.com/bitcoindevkit#stable
fixes #1926
### Notes to the reviewers
This will trigger a review request for above maintainers for any file changes in the repo.
Fixes https://github.com/bitcoindevkit/bdk/issues/1933, remove the usage of `Debug` on `Display` implemetations mentioned in https://github.com/bitcoindevkit/bdk/pull/1881#issuecomment-2718412512
### Changelog notice
- Replaced `Debug` usage with `Display` messages for `InsertDescriptorError`, `CalculateFeeError` and `StoreError`.
- `InvalidMagicBytes` now displays expected and actual bytes in hexadecimal instead of using `Debug`.
- Added a new `short_descriptor` function to shorten descriptors for concise error output.
- Added detailed `SyncRequest` `Display` for Esplora and Electrum examples.
### Checklists
#### All Submissions:
* [x] I have signed all my commits
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
* [x] I ran `just check`, `just fmt` and `just test` before committing
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
</details>
> **Note**
> Automatic rebases have been disabled on this pull request as it has been open for over 30 days.
Steve Myers [Thu, 29 Jan 2026 02:27:15 +0000 (20:27 -0600)]
feat(chain): add spent_txouts and created_txouts methods to SPK and keychain indexes
Implement sent_txouts and created_txouts methods on SpkTxOutIndex and
KeychainTxOutIndex. These methods return new SpentTxOut and CreatedTxOut
structs allowing callers to access complete transaction information
including script pubkeys, values, and spk index.
Steve Myers [Thu, 11 Dec 2025 17:26:25 +0000 (11:26 -0600)]
feat(chain): add input/output indices to sent_and_received_txouts
Return tuple of (index, TxOut) in sent_and_received_txouts methods to
identify which input/output positions the TxOuts correspond to in the
original transaction.
Steve Myers [Wed, 10 Dec 2025 21:42:45 +0000 (15:42 -0600)]
feat(chain): add sent_and_received_txouts method to SPK and keychain indexes
Implement sent_and_received_txouts methods on SpkTxOutIndex and
KeychainTxOutIndex. These methods return actual TxOut structs allowing callers
to access complete transaction output information including script pubkeys
and values.
The PR upgrades `miniscript` to it's latest `v13.0.0`, it's a breaking change so it's only meant to being merged in master, can't be backported to `release/chain-0.23.x`.
- upgrades `miniscript` version to `13.0.0`.
- fixes the usage of `psbt.sign` in `example_cli.
BREAKING_CHANGE: `bdk_chain` does re-exports the `miniscript` API, therefore bumping it's version is considered a breaking change.
### Notes to the reviewers
### Changelog notice
```
### Changed
- deps(bdk_chain): upgrades `miniscript` version to `13.0.0`.
- chore(example_cli): fixes the usage of `psbt.sign` in `example_cli.
```
### 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
Leonardo Lima [Mon, 26 Jan 2026 20:52:39 +0000 (17:52 -0300)]
deps(bdk_chain)!: bump `miniscript` to `13.0.0`
- upgrades `miniscript` version to `13.0.0`.
- fixes the usage of `psbt.sign` in `example_cli.
- `miniscript/no-std` has been removed in `13.0.0`, so it's not needed
anymore to use it in CI.
BREAKING_CHANGE: `bdk_chain` does re-exports the `miniscript` API,
therefore bumping it's version is considered a breaking change.
Upgrades the `electrsd` version from `0.28.0` to `0.36.1`, migrating from old `bitcoind` to `corepc-node` and using the `corepc-node_28_2` feature.
Updates the `bitcoind` client type for `TestEnv`, and its internal methods. Also, updates: bdk_bitcoind_rpc, bdk_esplora, bdk_electrum usage of `bdk_testenv` and `TestEnv`.
### Notes to the reviewers
As we are upgrading to the latest `electrsd`, we can drop for now the pinning for `home` in the MSRV step.
### Changelog notice
```
### Added
- deps(bdk_testenv): introduces `bitcoin and it's `bitcoin/rand-std` feature under `bdk_testenv/std`.
- test(bdk_bitcoind_rpc): introcuce `ClientExt` trait to use custom testing RPC client with current `bitcoincore-rpc` one.
### Changed
- deps(bdk_testenv)!: bump `electrsd` to `0.36.1`.
- deps(bdk_testenv): updates `electrsd` feature to `corepc-node_28_2`.
- test(bdk_bitcoind_rpc): update all tests to use new `ClientExt` trait when building the `Emitter`.
- test(bdk_chain): update all tests to use new `bdk_testenv`, `electrsd` and `corepc-node` APIs.
- test(bdk_esplora, bdk_electrum): update all tests to use new `bdk_testenv`, `electrsd` and `corepc-node` APIs.
- build(testenv): feature gate `mine_empty_blocks`, `reorg_empty_blocks` behind `std` feature.
```
### 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
Feature-gate TestEnv methods `mine_empty_blocks`, `reorg_empty_blocks`
behind `std` feature, as they depend on `rand` which is only
available when `std` feature is enabled.
valued mammal [Sat, 22 Nov 2025 00:36:58 +0000 (19:36 -0500)]
test(bdk_bitcoind_rpc): update it's tests to use `ClientExt`
- introduces `ClientExt` trait to `bdk_bitcoind_rpc` common tests
module.
- update all `bdk_bitcoind_rpc` tests to build the `Emitter` using the
`ClientExt` trait, which allows it to use the old
`bitcoincore-rpc::RpcApi` with the corepc-node background.
Leonardo Lima [Fri, 21 Mar 2025 15:03:36 +0000 (12:03 -0300)]
deps(bdk_testenv): bump `electrsd` to `0.36.1`
- upgrades the `electrsd` to latest `0.36.1`.
- updates the `electrsd` features to use `corepc-node_28_2`, it's the
previously named `bitcoind`.
- introduce `bitcoin` as a dependency, in order to use the
`bitcoind/rand-std` feature, which is now toggled by
`bdk_testenv/std`.
- remove the MSRV pinned `home` dependency, it's not currently required.
This PR adds the ability to calculate median-time-past (MTP) for `CheckPoint` structures, implementing the functionality described in #2036.
## Notes to the reviewers
`CheckPoint::median_time_past` calculates the MTP value by looking at the previous 11 blocks (including the current block).
### Why `ToBlockTime` is a separate trait from `ToBlockHash`
`ToBlockTime` is intentionally kept as a separate trait with a non-optional return type (`fn to_blocktime(&self) -> u32`).
For operations like MTP calculation, block times are either fully available or the calculation is meaningless — there's no useful "partial" or "best-effort" result. By using a separate trait, we get compile-time guarantees: methods like `median_time_past()` use `where D: ToBlockTime` bounds, making it explicit which checkpoint data types support time-based operations. Types without block time data (e.g., `BlockHash`, `BlockId`) simply don't implement the trait.
#### How this differs from `prev_blockhash`
In contrast, `prev_blockhash() -> Option<BlockHash>` is a method on `ToBlockHash` rather than a separate trait. The `Option` return serves a different purpose — it allows graceful degradation. A `CheckPoint<BlockId>` chain is still useful even without hash linkage validation; callers can simply skip verification when `None` is returned. Additionally, `None` at genesis is semantically meaningful (it marks the chain root), not an error condition.
For MTP, there's no equivalent "skip if unavailable" — you either have all 11 timestamps or the calculation fails. This binary requirement is better expressed as a trait bound than runtime `Option` handling.
## Changelog notice
### Added
- Introduced `ToBlockTime` trait for types that can return a block time.
- Added `median_time_past()` method to `CheckPoint` for calculating MTP according to BIP113
## 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
feat(core): add median-time-past calculation to CheckPoint
Add MTP calculation methods for CheckPoint following Bitcoin's BIP113:
- `median_time_past()`: calculates MTP for current block using 11 blocks
starting from the current block
- Returns None when required blocks are missing
`serde_json` requires either `std` or `alloc` feature enabled. We just enable `alloc` as we don't need the features that `std` provides.
### Notes to the reviewers
`alloc` is just a subset of `std`. `json_serde` has `from_reader()` & `to_writer()` methods if `std` is enabled. We aren't using those methods so just having `alloc` is fine.
I'm also not sure why an explicit `alloc` cargo feature flag is needed in `serde_json`. They can just have an internal prelude based on whether the `std` feature is enabled.
### Checklists
#### All Submissions:
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
This PR fixes incorrect ordering of `ChainPosition` that affected how wallet transactions are displayed. Previously, unconfirmed transactions that were never seen in the mempool would incorrectly appear before transactions with mempool timestamps due to the derived `Ord` implementation treating `None` as less than `Some(_)`.
### Problem
The derived `Ord` implementation for `ChainPosition::Unconfirmed` caused incorrect transaction ordering:
- `Unconfirmed { first_seen: None, last_seen: None }` (never in mempool)
- Would appear **before** `Unconfirmed { first_seen: Some(10), last_seen: Some(10) }` (seen in mempool)
This resulted in a confusing wallet display where transactions never broadcast would appear before pending mempool transactions.
### Solution
Implemented manual `Ord` and `PartialOrd` traits for `ChainPosition` with the correct ordering:
1. **Confirmed transactions** (earliest first by block height)
2. **Unconfirmed transactions seen in mempool** (ordered by `first_seen`)
3. **Unconfirmed transactions never seen** (these come last)
Additional ordering rules:
- At the same confirmation height, transitive confirmations come before direct confirmations (as they may actually be confirmed earlier)
- Tie-breaking uses transaction IDs for deterministic ordering
## Changelog notice
### Fixed
- Fixed `ChainPosition` ordering so unconfirmed transactions never seen in mempool appear last instead of first
### Changed
- `ChainPosition`, `CanonicalTx`, and `FullTxOut` now require `A: Ord` for their `Ord` implementations
- Simplified `FullTxOut` ordering to only use essential fields (chain_position, outpoint, spent_by)
## 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
* [x] I've added tests to reproduce the issue which are now passing
* [ ] I'm linking the issue being fixed by this PR