Skip to content

fix!: return errors from wallet address methods - #1114

Open
Arowolokehinde wants to merge 1 commit into
bitcoindevkit:masterfrom
Arowolokehinde:fix-peek-address-panic
Open

Arowolokehinde wants to merge 1 commit into
bitcoindevkit:masterfrom
Arowolokehinde:fix-peek-address-panic

Conversation

@Arowolokehinde

@Arowolokehinde Arowolokehinde commented Sep 6, 2026

Copy link
Copy Markdown

Description

Fixes #1105

Wallet::peek_address reached two upstream expect calls in bdk_wallet that panic: derivation
indexes in the BIP32 hardened range, and descriptors with no address form, i.e.
bare descriptors such as pk(...) and top-level multi(...).

Per the discussion on the issue, the same must have address form panic is
reachable from reveal_next_address, next_unused_address, reveal_addresses_to
and list_unused_addresses, so all five address methods now return
Result<_, AddressError>.

The guard runs before delegating to bdk_wallet, which panics rather than
returning an error, so there is nothing to map_err. It also means the three
mutating methods no longer stage a derivation index change before failing.

Notes to the reviewers

AddressError is shared across all five, though only peek_address can return
IndexOutOfBounds.

list_unused_addresses is a behaviour change rather than a panic fix: it
previously returned an empty list on a bare descriptor wallet, because nothing
can be revealed on one. It now returns an error, for consistency with the other
four.

Swift needs try at three call sites. Kotlin and Python are source-compatible.

Changelog

changelog: breaking

Documentation

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing
  • I've added exactly one changelog:* label
  • I've linked the relevant upstream docs or specs above

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

Five `Wallet` methods reached upstream `expect` calls that panic instead
of returning an error.

`peek_address` panicked for derivation indexes in the BIP32 hardened
range, and for descriptors with no address form. The same `must have
address form` panic is reachable from `reveal_next_address`,
`next_unused_address`, `reveal_addresses_to` and
`list_unused_addresses`, so all five now return
`Result<_, AddressError>`.

The checks run before delegating to `bdk_wallet`, which panics rather
than returning an error, so there is no `Err` to map. This also stops
the three mutating methods from staging a derivation index change
before failing. The `has_wildcard` guard preserves the upstream
behaviour of clamping the index to 0 for non-wildcard descriptors.

`list_unused_addresses` previously returned an empty list rather than
panicking on a bare descriptor wallet, since nothing can be revealed on
one. It now returns `BareDescriptorAddr`, for consistency with the
other four methods.

The signatures become fallible, a breaking change for Swift callers.
Kotlin and Python remain source-compatible.

@Ugarba202 Ugarba202 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an excellent catch and a very necessary fix! 💯 Mobile developers definitely prefer handling a thrown error over a complete app-crashing native panic.
I pulled the branch locally and ran through some checks:

  • Test Suite Verification: Ran the standard cargo test suite, and all 77 unit tests passed.
  • New Test Coverage: The new tests you added (like test_peek_address_bare_descriptor_returns_error and test_peek_address_above_max_index_returns_error) perfectly cover the new guard logic.
  • API Break Acknowledgment: Adding the AddressError return type to all five address methods is absolutely the right call to maintain consistency, even if it forces a try block in Swift. It's much better to have API-breaking safety than unpredictable panics.
    The guards you placed before delegating to bdk_wallet are clean and effective. Thanks for making the mobile bindings more robust!

@j-kon

j-kon commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

ACK c9aa633.

I checked the bounds handling, bare-descriptor guard, and the behavior of the other four address-returning methods against the upstream bdk_wallet implementation.

The wildcard check in peek_address looks correct, especially preserving the existing behavior where non-wildcard descriptors ignore the supplied index. Guarding the address form before calling the mutating upstream methods also avoids staging derivation changes before returning the error.

The Rust regression coverage looks good across the max index, out-of-range index, non-wildcard descriptors, and bare descriptors.

Non-blocking: since the main goal here is turning native panics into binding-visible errors, it would be nice to have one Kotlin or Swift regression test that actually catches the generated AddressError, for example verifying the out-of-range index field. The existing Rust coverage already proves the wrapper behavior, so I wouldn't block this PR on it.

Otherwise this looks good to me.

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

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

fix!: return errors from Wallet.peek_address

4 participants