Skip to content

Commit ca8ba06

Browse files
txprepare: fix withdraw returning unsigned transaction
The withdraw command was returning an unsigned raw transaction in its 'tx' response field. This happened because signpsbt_done() used psbt_txid() to extract utx->tx, which internally calls wally_psbt_extract() with WALLY_PSBT_EXTRACT_NON_FINAL — stripping all signature and witness data. The broadcast itself succeeded because sendpsbt internally finalizes the PSBT via psbt_final_tx(), but the 'tx' field returned to the user had empty scriptSigs and no witness data. Fix by finalizing the signed PSBT in signpsbt_done() and extracting the fully signed transaction via psbt_final_tx(). The txid verification still uses psbt_txid() (which is correct for txid computation since txids exclude witness data). Fixes: #8701 Changelog-Fixed: withdraw now returns a fully signed transaction in the `tx` response field. Signed-off-by: Vincenzo Palazzo <vincenzopalazzo@member.fsf.org> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 089d3af commit ca8ba06

File tree

1 file changed

+17
-5
lines changed

1 file changed

+17
-5
lines changed

plugins/txprepare.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,28 @@ static struct command_result *signpsbt_done(struct command *cmd,
156156
/* Replace with signed tx. */
157157
tal_free(utx->tx);
158158

159-
/* The txid from the final should match our expectation. */
160-
psbt_txid(utx, utx->psbt, &txid, &utx->tx);
159+
/* The txid from the signed PSBT should match our expectation. */
160+
psbt_txid(NULL, utx->psbt, &txid, NULL);
161161
if (!bitcoin_txid_eq(&txid, &utx->txid)) {
162162
return command_fail(cmd, LIGHTNINGD,
163163
"Signed tx changed txid? Had '%s' now '%s'",
164-
tal_hex(tmpctx,
165-
linearize_wtx(tmpctx, utx->tx)),
166-
fmt_wally_psbt(tmpctx, utx->psbt));
164+
fmt_bitcoin_txid(tmpctx, &utx->txid),
165+
fmt_bitcoin_txid(tmpctx, &txid));
167166
}
168167

168+
/* Finalize the signed PSBT and extract the fully signed tx,
169+
* so that utx->tx contains witness data for the response. */
170+
if (!psbt_finalize(utx->psbt))
171+
return command_fail(cmd, LIGHTNINGD,
172+
"Signed PSBT not finalizeable: %s",
173+
fmt_wally_psbt(tmpctx, utx->psbt));
174+
175+
utx->tx = psbt_final_tx(utx, utx->psbt);
176+
if (!utx->tx)
177+
return command_fail(cmd, LIGHTNINGD,
178+
"Could not extract final tx: %s",
179+
fmt_wally_psbt(tmpctx, utx->psbt));
180+
169181
req = jsonrpc_request_start(cmd, "sendpsbt",
170182
sendpsbt_done, forward_error,
171183
utx);

0 commit comments

Comments
 (0)