sendpsbt: update channel psbts if this is a channel PSBT.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
@@ -32300,7 +32300,7 @@
|
|||||||
"rpc": "sendpsbt",
|
"rpc": "sendpsbt",
|
||||||
"title": "Command to finalize, extract and send a partially signed bitcoin transaction (PSBT).",
|
"title": "Command to finalize, extract and send a partially signed bitcoin transaction (PSBT).",
|
||||||
"description": [
|
"description": [
|
||||||
"The **sendpsbt** is a low-level RPC command which sends a fully-signed PSBT."
|
"The **sendpsbt** is a low-level RPC command which sends a fully-signed PSBT. If the PSBT is the same one promised by a channel (via fundchannel_complete) it will also be associated with that channel and re-transmitted if necessary on restart."
|
||||||
],
|
],
|
||||||
"request": {
|
"request": {
|
||||||
"required": [
|
"required": [
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"rpc": "sendpsbt",
|
"rpc": "sendpsbt",
|
||||||
"title": "Command to finalize, extract and send a partially signed bitcoin transaction (PSBT).",
|
"title": "Command to finalize, extract and send a partially signed bitcoin transaction (PSBT).",
|
||||||
"description": [
|
"description": [
|
||||||
"The **sendpsbt** is a low-level RPC command which sends a fully-signed PSBT."
|
"The **sendpsbt** is a low-level RPC command which sends a fully-signed PSBT. If the PSBT is the same one promised by a channel (via fundchannel_complete) it will also be associated with that channel and re-transmitted if necessary on restart."
|
||||||
],
|
],
|
||||||
"request": {
|
"request": {
|
||||||
"required": [
|
"required": [
|
||||||
|
|||||||
@@ -2405,6 +2405,11 @@ static struct command_result *single_splice_signed(struct command *cmd,
|
|||||||
SPLICE_INPUT_ERROR,
|
SPLICE_INPUT_ERROR,
|
||||||
"Splice failed to convert to v2");
|
"Splice failed to convert to v2");
|
||||||
|
|
||||||
|
/* Update "funding" psbt now */
|
||||||
|
tal_free(channel->funding_psbt);
|
||||||
|
channel->funding_psbt = clone_psbt(channel, psbt);
|
||||||
|
wallet_channel_save(cmd->ld->wallet, channel);
|
||||||
|
|
||||||
msg = towire_channeld_splice_signed(tmpctx, psbt, sign_first);
|
msg = towire_channeld_splice_signed(tmpctx, psbt, sign_first);
|
||||||
subd_send_msg(channel->owner, take(msg));
|
subd_send_msg(channel->owner, take(msg));
|
||||||
if (success)
|
if (success)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <bitcoin/script.h>
|
#include <bitcoin/script.h>
|
||||||
|
#include <ccan/mem/mem.h>
|
||||||
#include <common/addr.h>
|
#include <common/addr.h>
|
||||||
#include <common/base64.h>
|
#include <common/base64.h>
|
||||||
#include <common/bech32.h>
|
#include <common/bech32.h>
|
||||||
@@ -1065,6 +1066,85 @@ static const struct json_command dev_finalizepsbt_command = {
|
|||||||
};
|
};
|
||||||
AUTODATA(json_command, &dev_finalizepsbt_command);
|
AUTODATA(json_command, &dev_finalizepsbt_command);
|
||||||
|
|
||||||
|
/* Yuck. */
|
||||||
|
static const u8 *psbt_input_txid(const struct wally_psbt *psbt, size_t index)
|
||||||
|
{
|
||||||
|
if (psbt->version == WALLY_PSBT_VERSION_0)
|
||||||
|
return psbt->tx->inputs[index].txhash;
|
||||||
|
return psbt->inputs[index].txhash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 psbt_input_index(const struct wally_psbt *psbt, size_t index)
|
||||||
|
{
|
||||||
|
if (psbt->version == WALLY_PSBT_VERSION_0)
|
||||||
|
return psbt->tx->inputs[index].index;
|
||||||
|
return psbt->inputs[index].index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 psbt_input_sequence(const struct wally_psbt *psbt, size_t index)
|
||||||
|
{
|
||||||
|
if (psbt->version == WALLY_PSBT_VERSION_0)
|
||||||
|
return psbt->tx->inputs[index].sequence;
|
||||||
|
return psbt->inputs[index].sequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 psbt_output_amount(const struct wally_psbt *psbt, size_t index)
|
||||||
|
{
|
||||||
|
if (psbt->version == WALLY_PSBT_VERSION_0)
|
||||||
|
return psbt->tx->outputs[index].satoshi;
|
||||||
|
return psbt->outputs[index].amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t psbt_output_scriptlen(const struct wally_psbt *psbt, size_t index)
|
||||||
|
{
|
||||||
|
if (psbt->version == WALLY_PSBT_VERSION_0)
|
||||||
|
return psbt->tx->outputs[index].script_len;
|
||||||
|
return psbt->outputs[index].script_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const u8 *psbt_output_script(const struct wally_psbt *psbt, size_t index)
|
||||||
|
{
|
||||||
|
if (psbt->version == WALLY_PSBT_VERSION_0)
|
||||||
|
return psbt->tx->outputs[index].script;
|
||||||
|
return psbt->outputs[index].script;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We consider two PSBTs *equivalent* if they have the same inputs and outputs */
|
||||||
|
static bool psbt_equivalent(const struct wally_psbt *a,
|
||||||
|
const struct wally_psbt *b)
|
||||||
|
{
|
||||||
|
if (a->num_inputs != b->num_inputs)
|
||||||
|
return false;
|
||||||
|
if (a->num_outputs != b->num_outputs)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < a->num_inputs; i++) {
|
||||||
|
if (!memeq(psbt_input_txid(a, i), WALLY_TXHASH_LEN,
|
||||||
|
psbt_input_txid(b, i), WALLY_TXHASH_LEN))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (psbt_input_index(a, i) != psbt_input_index(b, i))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (psbt_input_sequence(a, i) != psbt_input_sequence(b, i))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < a->num_outputs; i++) {
|
||||||
|
size_t a_scriptlen, b_scriptlen;
|
||||||
|
|
||||||
|
if (psbt_output_amount(a, i) != psbt_output_amount(b, i))
|
||||||
|
return false;
|
||||||
|
a_scriptlen = psbt_output_scriptlen(a, i);
|
||||||
|
b_scriptlen = psbt_output_scriptlen(b, i);
|
||||||
|
if (!memeq(psbt_output_script(a, i), a_scriptlen,
|
||||||
|
psbt_output_script(b, i), b_scriptlen))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static struct command_result *json_sendpsbt(struct command *cmd,
|
static struct command_result *json_sendpsbt(struct command *cmd,
|
||||||
const char *buffer,
|
const char *buffer,
|
||||||
const jsmntok_t *obj,
|
const jsmntok_t *obj,
|
||||||
@@ -1075,6 +1155,8 @@ static struct command_result *json_sendpsbt(struct command *cmd,
|
|||||||
struct wally_psbt *psbt;
|
struct wally_psbt *psbt;
|
||||||
struct lightningd *ld = cmd->ld;
|
struct lightningd *ld = cmd->ld;
|
||||||
u32 *reserve_blocks;
|
u32 *reserve_blocks;
|
||||||
|
struct peer *p;
|
||||||
|
struct peer_node_id_map_iter it;
|
||||||
|
|
||||||
if (!param_check(cmd, buffer, params,
|
if (!param_check(cmd, buffer, params,
|
||||||
p_req("psbt", param_psbt, &psbt),
|
p_req("psbt", param_psbt, &psbt),
|
||||||
@@ -1109,6 +1191,30 @@ static struct command_result *json_sendpsbt(struct command *cmd,
|
|||||||
if (command_check_only(cmd))
|
if (command_check_only(cmd))
|
||||||
return command_check_done(cmd);
|
return command_check_done(cmd);
|
||||||
|
|
||||||
|
/* If this corresponds to one or more channels' PSBT, upgrade
|
||||||
|
* those to signed versions! */
|
||||||
|
for (p = peer_node_id_map_first(ld->peers, &it);
|
||||||
|
p;
|
||||||
|
p = peer_node_id_map_next(ld->peers, &it)) {
|
||||||
|
struct channel *c;
|
||||||
|
|
||||||
|
list_for_each(&p->channels, c, list) {
|
||||||
|
if (!c->funding_psbt)
|
||||||
|
continue;
|
||||||
|
if (psbt_is_finalized(c->funding_psbt))
|
||||||
|
continue;
|
||||||
|
if (!psbt_equivalent(psbt, c->funding_psbt))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Found one! */
|
||||||
|
tal_free(c->funding_psbt);
|
||||||
|
c->funding_psbt = clone_psbt(c, sending->psbt);
|
||||||
|
wallet_channel_save(ld->wallet, c);
|
||||||
|
log_info(c->log,
|
||||||
|
"Funding PSBT sent, and stored for rexmit");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < tal_count(sending->utxos); i++) {
|
for (size_t i = 0; i < tal_count(sending->utxos); i++) {
|
||||||
if (!wallet_reserve_utxo(ld->wallet, sending->utxos[i],
|
if (!wallet_reserve_utxo(ld->wallet, sending->utxos[i],
|
||||||
get_block_height(ld->topology),
|
get_block_height(ld->topology),
|
||||||
|
|||||||
Reference in New Issue
Block a user