diff --git a/bitcoin/psbt.c b/bitcoin/psbt.c index c721dbb8a92b..8f2690019926 100644 --- a/bitcoin/psbt.c +++ b/bitcoin/psbt.c @@ -86,6 +86,22 @@ struct wally_psbt *new_psbt(const tal_t *ctx, const struct wally_tx *wtx) return psbt; } +struct wally_psbt *combine_psbt(const tal_t *ctx, + const struct wally_psbt *psbt0, + const struct wally_psbt *psbt1) +{ + struct wally_psbt *combined_psbt; + tal_wally_start(); + if (wally_psbt_clone_alloc(psbt0, 0, &combined_psbt) != WALLY_OK) + abort(); + if (wally_psbt_combine(combined_psbt, psbt1) != WALLY_OK) { + tal_wally_end_onto(ctx, combined_psbt, struct wally_psbt); + return tal_free(combined_psbt); + } + tal_wally_end_onto(ctx, combined_psbt, struct wally_psbt); + return combined_psbt; +} + bool psbt_is_finalized(const struct wally_psbt *psbt) { size_t is_finalized; diff --git a/bitcoin/psbt.h b/bitcoin/psbt.h index dc22b3bbe926..4c872c8cdad6 100644 --- a/bitcoin/psbt.h +++ b/bitcoin/psbt.h @@ -50,6 +50,17 @@ struct wally_psbt *new_psbt(const tal_t *ctx, */ struct wally_psbt *clone_psbt(const tal_t *ctx, struct wally_psbt *psbt); +/** + * combine_psbt - Combine two PSBT into a cloned copy + * + * @ctx - allocation context + * @psbt0 - one psbt + * @psbt1 - other psbt + */ +struct wally_psbt *combine_psbt(const tal_t *ctx, + const struct wally_psbt *psbt0, + const struct wally_psbt *psbt1); + /** * psbt_is_finalized - Check if tx is ready to be extracted * diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index 198bfb559344..5e687032fc6d 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -799,15 +799,28 @@ static struct command_result *json_signpsbt(struct command *cmd, "HSM gave bad sign_withdrawal_reply %s", tal_hex(tmpctx, msg)); - if (!psbt_set_version(signed_psbt, psbt_version)) { + /* Some signers (VLS) prune the input.utxo data as it's used + * because it is too large to store in the signer. We can + * restore this metadata by combining the signed psbt back + * into a clone of the original psbt. */ + struct wally_psbt *combined_psbt; + combined_psbt = combine_psbt(cmd, psbt, signed_psbt); + if (!combined_psbt) { + return command_fail(cmd, LIGHTNINGD, + "Unable to combine signed psbt: %s", + type_to_string(tmpctx, struct wally_psbt, + signed_psbt)); + } + + if (!psbt_set_version(combined_psbt, psbt_version)) { return command_fail(cmd, LIGHTNINGD, "Signed PSBT unable to have version set: %s", type_to_string(tmpctx, struct wally_psbt, - psbt)); + combined_psbt)); } response = json_stream_success(cmd); - json_add_psbt(response, "signed_psbt", signed_psbt); + json_add_psbt(response, "signed_psbt", combined_psbt); return command_success(cmd, response); }