dlc: build a valid script signature for P2SH-wrapped funding inputs - #195
Merged
Merged
Conversation
redeem_script_to_script_sig wrapped the redeem script in a fresh witness program, so a 22-byte P2SH-P2WPKH redeem script hit the V0 length check and panicked inside WitnessProgram::new. Any funding input with a redeem script, including one sent by a counterparty, crashed the accepting side during fee weighting, and no P2SH input could ever fund a contract. The script signature is now a single push of the redeem script, as P2SH requires, and the helper returns an error instead of panicking on an oversized script. The manager clears script signatures before building its funding PSBT, which Psbt::from_unsigned_tx demands, and restores the redeem script push on extraction so the wrapped input remains spendable.
Two stateless tests build each party from a bdk_wallet Bip49 template, so every funding input, payout, and change script is P2SH-P2WPKH. One test hands the funding PSBT to each wallet and lets BDK sign and finalize its own input from the witness UTXO alone; the other signs through the sh(wpkh()) descriptor path, which was documented as supported but had no test. PartySetup gains a payout_spk so a party can pay out to a script other than its native P2WPKH key. The BIP49 party spends a non-null dummy outpoint because BDK rejects a coinbase as an unconfirmed transaction.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the Bitcoin Red Team finding FND-004, "P2SH-P2WPKH funding inputs produce an invalid funding transaction in the stateless contract API", with a corrected root cause. The report blamed the witness-only copy in
apply_funding_signatures; the final transaction is in fact rebuilt fromcreate_dlc_transactions, which sets the script signature. The real defect sits one step earlier:redeem_script_to_script_sigwrapped the redeem script in a fresh witness program, so a 22-byte P2SH-P2WPKH redeem script failed the V0 length check and panicked insideWitnessProgram::new. Any funding input with a redeem script, including one sent by a counterparty, crashed the accepting side during fee weighting, and no P2SH input could ever fund a contract.Changes
redeem_script_to_script_signow returns a single push of the redeem script, which is what spending a P2SH output requires, and returns an error instead of panicking on an oversized script.get_unsigned_tx_inputs_and_serial_idspropagates that error.Psbt::from_unsigned_txdemands, and restores the redeem script push on every wrapped input before extraction, so the manager path can fund from a P2SH-P2WPKH input too. Before this the manager returned "Tried to create PSBT from signed tx" for any such input.build_funding_psbtalready strips and the finalizer already restores the push, and the final transaction is rebuilt with the correct script signature.Testing
ddk-dlcunit tests: an empty redeem script yields an empty script signature; 22-byte P2SH-P2WPKH and 34-byte P2SH-P2WSH redeem scripts are pushed whole.p2sh_p2wpkh_funding_inputs_carry_the_redeem_script_push: a full offer, accept, sign, and finalize cycle where the offerer funds from a wrapped output. The funding transaction's wrapped input carries the redeem script push and a two-element witness, native inputs stay empty. The harness's funding transaction check now understands wrapped inputs.cargo test -p ddk-dlc(22), the stateless suite (33), and the regtestenum_single_oracle_testpass.cargo check --all-features --testsandcargo +1.89.0 clippy -- -D warningsare clean.