bitcoindevkit / bitcoindevkit/bdk_wallet
`build_fee_bump` panics on legacy foreign input when previous tx is not in the tx graph
- Dominant language
- Rust
- Stars
- 59
- Forks
- 105
- Avg merge
- 10d 9h
- Merged PRs (30d)
- 1
Description
**Describe the bug**
`Wallet::build_fee_bump` reconstructs the original transaction's inputs as `WeightedUtxo`s. For inputs the wallet does not own, it builds a `Utxo::Foreign` whose `psbt_input` gets:
- `witness_utxo` only if the prevout script has a witness version, and
- `non_witness_utxo` only if the full previous transaction is in the tx graph.
If the foreign input is legacy (e.g. p2pkh) and the wallet only knows the prevout via `insert_txout` (which is what the `add_foreign_utxo` docs suggest for fee calculation), both fields end up `None`. `build_fee_bump` itself succeeds, but `TxBuilder::finish` then panics in `Utxo::txout` (`src/types.rs`, `expect("Foreign UTXOs should have one of witness_utxo, non_witness_utxo set")`).
Related: #474 discusses the panic in `Utxo::txout` itself; this issue is about `build_fee_bump` constructing such a value internally.
This issue was found by AI.
**To Reproduce**
```rust
let (mut wallet1, _) = get_funded_wallet_wpkh();
let (wallet2, _) = get_funded_wallet_single("pkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)");
let utxo = wallet2.list_unspent().next().unwrap();
let prev_tx = wallet2.get_tx(utxo.outpoint.txid).unwrap().tx_node.tx.as_ref().clone();
let weight = wallet2.public_descriptor(KeychainKind::External).max_weight_to_satisfy().unwrap();
let addr = wallet1.next_unused_address(KeychainKind::External);
let mut builder = wallet1.build_tx();
builder
.add_recipient(addr.script_pubkey(), Amount::from_sat(60_000))
.add_foreign_utxo(
utxo.outpoint,
psbt::Input { non_witness_utxo: Some(prev_tx), ..Default::default() },
weight,
)
.unwrap();
let tx = builder.finish().unwrap().extract_tx().unwrap();
let txid = tx.compute_txid();
// wallet learns the prevout but not the full previous transaction
wallet1.insert_txout(utxo.outpoint, utxo.txout);
insert_tx(&mut wallet1, tx);
let mut builder = wallet1.build_fee_bump(txid).unwrap();
builder.fee_rate(FeeRate::from_sat_per_vb_unchecked(5));
builder.finish(); // panics at src/types.rs:132
```
**Expected behavior**
`build_fee_bump` / `finish` should return an error for inputs it cannot reconstruct enough information for, rather than panic.
**Build environment**
- BDK tag/commit: `6fc68462` (master)
**Which backend(s) are relevant (if any)?**
- [x] None / not backend-related (e.g. `bdk_chain`, `bdk_core`)
**Is this blocking production use?**
- [x] No
Contributor guide
Research direction
Start in src/types.rs at Utxo::txout, then trace Wallet::build_fee_bump through TxBuilder::finish using the reproduction in the issue. Done means the legacy foreign-input case returns an error from build_fee_bump or finish instead of panicking when only the prevout is known.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- blockchain
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100