bitcoindevkit / bitcoindevkit/bdk-tx
Make output-metadata redaction opt-in and split into two composable functions
- Dominant language
- Rust
- Stars
- 13
- Forks
- 17
- Avg merge
- 17h 22m
- Merged PRs (30d)
- 1
Description
`Finalizer::finalize` currently strips `bip32_derivation`, `tap_key_origins`, and `tap_internal_key` from every output when the PSBT is fully finalized (`finalizer.rs:139-146`). Two issues:
1. **Not spec-compliant by default.** BIP-174's finalizer role is defined over inputs only; output `PSBT_OUT_*` fields are normally retained until extraction. Bitcoin Core never touches outputs on finalize. Doing it silently diverges from both, and destroys metadata a downstream consumer may legitimately need (verifying change ownership, re-deriving addresses, registering change on a watch-only).
2. **Incomplete for policy privacy.** The current set removes wallet-linkage (key origins) but leaves `redeem_script` / `witness_script` / `tap_tree`, which expose an output's spending policy (multisig structure, full taproot tree). `tap_internal_key` sits between the two categories — it's a raw key, not a `KeySource` — so the split below assigns it to the key-origin function deliberately rather than leaving it ambiguous.
## Proposal
- Make `finalize` pure BIP-174 (inputs only; outputs untouched). Redaction becomes explicit opt-in.
- Add two standalone, composable functions (no `Finalizer`/plan dependency):
- `redact_output_key_origins` → clears `bip32_derivation`, `tap_key_origins`, `tap_internal_key` *(unlink output from wallet/xpub)*
- `redact_output_scripts` → clears `redeem_script`, `witness_script`, `tap_tree` *(hide spending policy)*
- Leave `proprietary` / `unknown` untouched (opaque, often load-bearing; mirrors input handling at `finalizer.rs:107-109`).
## Reasoning
- Two threat models, two field sets — callers pick what they need; calling both gives the full strip.
- Separate functions over a `finalize` parameter: redaction doesn't depend on the finalizer's plans, so coupling it to `finalize` is artificial. Distinct names make each function's leak-surface obvious.
- Opt-in default keeps us spec-compliant and Core-aligned; privacy is an explicit, deliberate step.
## Acceptance criteria
- [ ] `finalize` no longer modifies outputs.
- [ ] `redact_output_key_origins` and `redact_output_scripts` added.
- [ ] Doc comment at `finalizer.rs:20-22` updated; the "cleared after finalize" test (`finalizer.rs:300-304`) moved to exercise the new functions; preserve-by-default tests retained.
Contributor guide
Research direction
Start by reading finalizer.rs:139-146 and the doc comment at :20-22, then inspect the test at :300-304 and the existing output-field handling. Done means finalize leaves outputs unchanged, the two opt-in redaction functions cover their specified fields, and preserve-by-default behavior remains tested.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- blockchain
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 66/100