Skip to content

feat: expose detailed try_finalize_psbt outcomes#433

Open
reez wants to merge 5 commits into
bitcoindevkit:masterfrom
reez:issue-73
Open

feat: expose detailed try_finalize_psbt outcomes#433
reez wants to merge 5 commits into
bitcoindevkit:masterfrom
reez:issue-73

Conversation

@reez

@reez reez commented Apr 7, 2026

Copy link
Copy Markdown

Description

First step for #73, following ValuedMammal's suggestion.

This PR keeps the scope to PSBT finalization only:

  • add try_finalize_psbt which returns FinalizePsbtResult
  • report per input outcomes via FinalizePsbtInputResult

Notes to the reviewers

This is now additive rather than breaking: Wallet::finalize_psbt still returns bool

Intentionally not included here:

  • changing Wallet::sign to return a richer result type
  • any broader redesign beyond the PSBT finalization API surface

Changelog notice

  • Add Wallet::try_finalize_psbt, which returns FinalizePsbtResult and exposes per-input finalization outcomes while preserving the existing Wallet::finalize_psbt API.

Checklists

All Submissions:

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature

@codecov

codecov Bot commented Apr 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.62921% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.15%. Comparing base (58fe631) to head (ec3a683).

Files with missing lines Patch % Lines
src/types.rs 82.35% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #433      +/-   ##
==========================================
+ Coverage   80.96%   81.15%   +0.19%     
==========================================
  Files          24       24              
  Lines        5489     5552      +63     
  Branches      247      247              
==========================================
+ Hits         4444     4506      +62     
- Misses        968      970       +2     
+ Partials       77       76       -1     
Flag Coverage Δ
rust 81.15% <96.62%> (+0.19%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@reez reez force-pushed the issue-73 branch 2 times, most recently from c65f534 to e046adc Compare April 7, 2026 20:16
@reez reez changed the title (draft) feat: expose detailed finalize_psbt outcomes (draft) feat: expose detailed try_finalize_psbt outcomes Apr 7, 2026
@reez

reez commented Apr 7, 2026

Copy link
Copy Markdown
Author

Updated per some good feedback from mammal

@reez reez marked this pull request as ready for review April 9, 2026 19:21
@reez reez changed the title (draft) feat: expose detailed try_finalize_psbt outcomes feat: expose detailed try_finalize_psbt outcomes Apr 9, 2026
@reez reez force-pushed the issue-73 branch 5 times, most recently from f3fb2a6 to 69966b6 Compare April 14, 2026 19:14
@ValuedMammal ValuedMammal added this to the Wallet 3.1.0 milestone Apr 14, 2026
@ValuedMammal ValuedMammal added the new feature New feature or request label Apr 14, 2026
@ValuedMammal ValuedMammal moved this to In Progress in BDK Wallet Apr 14, 2026

@ValuedMammal ValuedMammal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think After and Older are doing much good, and would prefer to leave them out of the new implementation if we plan to support try_finalize_psbt into the future.

@notmandatory

Copy link
Copy Markdown
Member

Concept ACK, glad to see this as a non-breaking change.

@reez

reez commented Jun 16, 2026

Copy link
Copy Markdown
Author

Added four commits as small follow-ups from review feedback from mammal: make finalization cleanup more explicit, preserve opaque PSBT/input metadata, stop the new try_finalize_psbt path from redacting output metadata, and clarify the internal timelock inputs without changing legacy finalize_psbt behavior.

Comment thread src/wallet/mod.rs Outdated
Comment thread src/wallet/mod.rs Outdated
Comment on lines +190 to +193
/// The input was already finalized before this call.
AlreadyFinalized,
/// The input was successfully finalized during this call.
Finalized,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

question: are we using this differently ? otherwise, a single Finalized would be enough imho.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I see where you're coming from for sure but I do think the distinctions intentional. Finalized would be this call was able to finalize the input, AlreadyFinalized would be the input already had final script/witness data before this call and we skipped it. is_finalized() treats both as success, but I thought preserving that difference was useful since this API is meant to explain what happened per input.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good, I think I see where you're going. Agree, it's probably useful to have that distinction if it'll be used for upstream users (e.g UX/UI).

Comment thread src/wallet/mod.rs Outdated
Comment thread src/wallet/mod.rs Outdated
Comment thread src/wallet/mod.rs

@oleonardolima oleonardolima left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

cACK 09d2cd0

Comment thread src/wallet/mod.rs
@Musab1258

Musab1258 commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

tACK 09d2cd0

The concept and approach make sense. I fetched the branch and ran the tests locally, and they all pass. The documentation also clearly specifies when to use the finalize_psbt and try_finalize_psbt methods.

Comment thread src/types.rs
}

/// Whether all inputs are finalized after this call.
pub fn is_finalized(&self) -> bool {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If outcomes is empty (e.g. a PSBT with no inputs), is_finalized() returns true, since .all() on an empty iterator is true. Is this the intended behavior or worth documenting/guarding against explicitly?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I think this is intended since is_finalized() is only answering whether any input failed finalization, so if there are no inputs there is nothing to fail. This also matches the old finalize_psbt behavior where finished started as true and only changed inside the input loop. But that's my take, open to further thoughts

Comment thread src/wallet/mod.rs
let mut finished = true;
let mut outcomes = BTreeMap::new();

for (n, input) in tx.input.iter().enumerate() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If psbt.inputs.len() < tx.input.len() but not 0, this loop will partially mutate earlier inputs before hitting the IndexOutOfBoundsError on a later one. Is it expected to have a partially-mutated PSBT on Err , or should length be validated up front before any mutation starts?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agree I think validating up front is cleaner here. 6afd006 adds a guard before the loop so a PSBT with missing input metadata returns IndexOutOfBoundsError before any inputs are mutated, plus a regression test for the partial mutation case.

Comment thread src/types.rs

/// The finalization status for a single PSBT input.
#[derive(Debug, PartialEq)]
pub enum FinalizeInputOutcome {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would it make sense to add a Display impl for FinalizeInputOutcome so callers don't have to match on the variants themselves to produce an outcome that can be logged in user interfaces?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Maybe, but I lean toward leaving this out for now. I was thinking of FinalizeInputOutcome as structured data that callers can match on and render however they want, especially for UI wording, while Debug is still available for basic logging. Happy to add Display if others think that belongs in the initial API though.

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

Labels

new feature New feature or request

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

5 participants