Skip to content

Commit ae9ecba

Browse files
committed
sendpsbt: update channel psbts if this is a channel PSBT.
Signed-off-by: Rusty Russell <[email protected]>
1 parent 5cbab33 commit ae9ecba

File tree

4 files changed

+113
-2
lines changed

4 files changed

+113
-2
lines changed

contrib/msggen/msggen/schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32300,7 +32300,7 @@
3230032300
"rpc": "sendpsbt",
3230132301
"title": "Command to finalize, extract and send a partially signed bitcoin transaction (PSBT).",
3230232302
"description": [
32303-
"The **sendpsbt** is a low-level RPC command which sends a fully-signed PSBT."
32303+
"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."
3230432304
],
3230532305
"request": {
3230632306
"required": [

doc/schemas/sendpsbt.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"rpc": "sendpsbt",
55
"title": "Command to finalize, extract and send a partially signed bitcoin transaction (PSBT).",
66
"description": [
7-
"The **sendpsbt** is a low-level RPC command which sends a fully-signed PSBT."
7+
"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."
88
],
99
"request": {
1010
"required": [

lightningd/channel_control.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2405,6 +2405,11 @@ static struct command_result *single_splice_signed(struct command *cmd,
24052405
SPLICE_INPUT_ERROR,
24062406
"Splice failed to convert to v2");
24072407

2408+
/* Update "funding" psbt now */
2409+
tal_free(channel->funding_psbt);
2410+
channel->funding_psbt = clone_psbt(channel, psbt);
2411+
wallet_channel_save(cmd->ld->wallet, channel);
2412+
24082413
msg = towire_channeld_splice_signed(tmpctx, psbt, sign_first);
24092414
subd_send_msg(channel->owner, take(msg));
24102415
if (success)

wallet/walletrpc.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "config.h"
22
#include <bitcoin/script.h>
3+
#include <ccan/mem/mem.h>
34
#include <common/addr.h>
45
#include <common/base64.h>
56
#include <common/bech32.h>
@@ -1065,6 +1066,85 @@ static const struct json_command dev_finalizepsbt_command = {
10651066
};
10661067
AUTODATA(json_command, &dev_finalizepsbt_command);
10671068

1069+
/* Yuck. */
1070+
static const u8 *psbt_input_txid(const struct wally_psbt *psbt, size_t index)
1071+
{
1072+
if (psbt->version == WALLY_PSBT_VERSION_0)
1073+
return psbt->tx->inputs[index].txhash;
1074+
return psbt->inputs[index].txhash;
1075+
}
1076+
1077+
static u32 psbt_input_index(const struct wally_psbt *psbt, size_t index)
1078+
{
1079+
if (psbt->version == WALLY_PSBT_VERSION_0)
1080+
return psbt->tx->inputs[index].index;
1081+
return psbt->inputs[index].index;
1082+
}
1083+
1084+
static u32 psbt_input_sequence(const struct wally_psbt *psbt, size_t index)
1085+
{
1086+
if (psbt->version == WALLY_PSBT_VERSION_0)
1087+
return psbt->tx->inputs[index].sequence;
1088+
return psbt->inputs[index].sequence;
1089+
}
1090+
1091+
static u64 psbt_output_amount(const struct wally_psbt *psbt, size_t index)
1092+
{
1093+
if (psbt->version == WALLY_PSBT_VERSION_0)
1094+
return psbt->tx->outputs[index].satoshi;
1095+
return psbt->outputs[index].amount;
1096+
}
1097+
1098+
static size_t psbt_output_scriptlen(const struct wally_psbt *psbt, size_t index)
1099+
{
1100+
if (psbt->version == WALLY_PSBT_VERSION_0)
1101+
return psbt->tx->outputs[index].script_len;
1102+
return psbt->outputs[index].script_len;
1103+
}
1104+
1105+
static const u8 *psbt_output_script(const struct wally_psbt *psbt, size_t index)
1106+
{
1107+
if (psbt->version == WALLY_PSBT_VERSION_0)
1108+
return psbt->tx->outputs[index].script;
1109+
return psbt->outputs[index].script;
1110+
}
1111+
1112+
/* We consider two PSBTs *equivalent* if they have the same inputs and outputs */
1113+
static bool psbt_equivalent(const struct wally_psbt *a,
1114+
const struct wally_psbt *b)
1115+
{
1116+
if (a->num_inputs != b->num_inputs)
1117+
return false;
1118+
if (a->num_outputs != b->num_outputs)
1119+
return false;
1120+
1121+
for (size_t i = 0; i < a->num_inputs; i++) {
1122+
if (!memeq(psbt_input_txid(a, i), WALLY_TXHASH_LEN,
1123+
psbt_input_txid(b, i), WALLY_TXHASH_LEN))
1124+
return false;
1125+
1126+
if (psbt_input_index(a, i) != psbt_input_index(b, i))
1127+
return false;
1128+
1129+
if (psbt_input_sequence(a, i) != psbt_input_sequence(b, i))
1130+
return false;
1131+
}
1132+
1133+
for (size_t i = 0; i < a->num_outputs; i++) {
1134+
size_t a_scriptlen, b_scriptlen;
1135+
1136+
if (psbt_output_amount(a, i) != psbt_output_amount(b, i))
1137+
return false;
1138+
a_scriptlen = psbt_output_scriptlen(a, i);
1139+
b_scriptlen = psbt_output_scriptlen(b, i);
1140+
if (!memeq(psbt_output_script(a, i), a_scriptlen,
1141+
psbt_output_script(b, i), b_scriptlen))
1142+
return false;
1143+
}
1144+
1145+
return true;
1146+
}
1147+
10681148
static struct command_result *json_sendpsbt(struct command *cmd,
10691149
const char *buffer,
10701150
const jsmntok_t *obj,
@@ -1075,6 +1155,8 @@ static struct command_result *json_sendpsbt(struct command *cmd,
10751155
struct wally_psbt *psbt;
10761156
struct lightningd *ld = cmd->ld;
10771157
u32 *reserve_blocks;
1158+
struct peer *p;
1159+
struct peer_node_id_map_iter it;
10781160

10791161
if (!param_check(cmd, buffer, params,
10801162
p_req("psbt", param_psbt, &psbt),
@@ -1109,6 +1191,30 @@ static struct command_result *json_sendpsbt(struct command *cmd,
11091191
if (command_check_only(cmd))
11101192
return command_check_done(cmd);
11111193

1194+
/* If this corresponds to one or more channels' PSBT, upgrade
1195+
* those to signed versions! */
1196+
for (p = peer_node_id_map_first(ld->peers, &it);
1197+
p;
1198+
p = peer_node_id_map_next(ld->peers, &it)) {
1199+
struct channel *c;
1200+
1201+
list_for_each(&p->channels, c, list) {
1202+
if (!c->funding_psbt)
1203+
continue;
1204+
if (psbt_is_finalized(c->funding_psbt))
1205+
continue;
1206+
if (!psbt_equivalent(psbt, c->funding_psbt))
1207+
continue;
1208+
1209+
/* Found one! */
1210+
tal_free(c->funding_psbt);
1211+
c->funding_psbt = clone_psbt(c, sending->psbt);
1212+
wallet_channel_save(ld->wallet, c);
1213+
log_info(c->log,
1214+
"Funding PSBT sent, and stored for rexmit");
1215+
}
1216+
}
1217+
11121218
for (size_t i = 0; i < tal_count(sending->utxos); i++) {
11131219
if (!wallet_reserve_utxo(ld->wallet, sending->utxos[i],
11141220
get_block_height(ld->topology),

0 commit comments

Comments
 (0)