2022-05-24 22:40:08 +02:00
|
|
|
#include "config.h"
|
|
|
|
#include <bitcoin/chainparams.h>
|
|
|
|
#include <bitcoin/psbt.h>
|
|
|
|
#include <bitcoin/script.h>
|
|
|
|
#include <ccan/array_size/array_size.h>
|
|
|
|
#include <ccan/cast/cast.h>
|
|
|
|
#include <ccan/mem/mem.h>
|
|
|
|
#include <ccan/tal/str/str.h>
|
|
|
|
#include <common/billboard.h>
|
|
|
|
#include <common/blockheight_states.h>
|
|
|
|
#include <common/gossip_store.h>
|
|
|
|
#include <common/initial_channel.h>
|
|
|
|
#include <common/interactivetx.h>
|
|
|
|
#include <common/lease_rates.h>
|
|
|
|
#include <common/memleak.h>
|
|
|
|
#include <common/peer_billboard.h>
|
|
|
|
#include <common/peer_failed.h>
|
2023-07-27 22:13:33 +02:00
|
|
|
#include <common/peer_io.h>
|
2022-05-24 22:40:08 +02:00
|
|
|
#include <common/psbt_internal.h>
|
|
|
|
#include <common/psbt_open.h>
|
|
|
|
#include <common/setup.h>
|
|
|
|
#include <common/status.h>
|
|
|
|
#include <common/subdaemon.h>
|
2023-10-22 06:07:32 +02:00
|
|
|
#include <common/wire_error.h>
|
2022-05-24 22:40:08 +02:00
|
|
|
|
|
|
|
/*
|
2024-03-18 06:32:47 +01:00
|
|
|
* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - if has received 4096 `tx_add_input` messages during this negotiation
|
|
|
|
*/
|
|
|
|
#define MAX_TX_ADD_INPUT_MSG_RCVD 4096
|
|
|
|
/*
|
2024-03-18 06:32:47 +01:00
|
|
|
* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - it has received 4096 `tx_add_output` messages during this negotiation
|
|
|
|
*/
|
|
|
|
#define MAX_TX_ADD_OUTPUT_MSG_RCVD 4096
|
|
|
|
|
|
|
|
/*
|
2024-03-18 06:32:47 +01:00
|
|
|
* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - there are more than 252 inputs
|
|
|
|
* - there are more than 252 outputs
|
|
|
|
*/
|
|
|
|
#define MAX_FUNDING_INPUTS 252
|
|
|
|
#define MAX_FUNDING_OUTPUTS 252
|
|
|
|
|
|
|
|
static struct wally_psbt *default_next_update(const tal_t *ctx,
|
|
|
|
struct interactivetx_context *ictx)
|
|
|
|
{
|
|
|
|
return ictx->desired_psbt;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct interactivetx_context *new_interactivetx_context(const tal_t *ctx,
|
|
|
|
enum tx_role our_role,
|
|
|
|
struct per_peer_state *pps,
|
|
|
|
struct channel_id channel_id)
|
|
|
|
{
|
|
|
|
struct interactivetx_context *ictx = tal(ctx, struct interactivetx_context);
|
|
|
|
|
|
|
|
ictx->our_role = our_role;
|
|
|
|
ictx->pps = pps;
|
|
|
|
ictx->channel_id = channel_id;
|
|
|
|
ictx->tx_add_input_count = 0;
|
|
|
|
ictx->tx_add_output_count = 0;
|
2023-07-27 22:13:33 +02:00
|
|
|
ictx->next_update_fn = default_next_update;
|
|
|
|
ictx->current_psbt = create_psbt(ictx, 0, 0, 0);
|
2022-05-24 22:40:08 +02:00
|
|
|
ictx->desired_psbt = NULL;
|
|
|
|
ictx->pause_when_complete = false;
|
|
|
|
ictx->change_set = NULL;
|
|
|
|
|
|
|
|
return ictx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool is_segwit_output(const tal_t *ctx,
|
|
|
|
struct wally_tx_output *output,
|
|
|
|
const u8 *redeemscript)
|
|
|
|
{
|
2024-02-21 22:03:07 +01:00
|
|
|
const u8 *maybe_witness = redeemscript;
|
|
|
|
size_t script_len = tal_bytelen(maybe_witness);
|
2022-05-24 22:40:08 +02:00
|
|
|
|
2024-02-21 22:03:07 +01:00
|
|
|
if (!script_len) {
|
|
|
|
maybe_witness = output->script;
|
|
|
|
script_len = output->script_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return is_known_segwit_scripttype(maybe_witness, script_len);
|
2022-05-24 22:40:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Return first non-handled message or NULL if connection is aborted */
|
|
|
|
static u8 *read_next_msg(const tal_t *ctx,
|
|
|
|
struct interactivetx_context *state,
|
|
|
|
char **error)
|
|
|
|
{
|
|
|
|
u8 *msg = NULL;
|
|
|
|
|
|
|
|
for (;;) {
|
2023-09-12 06:23:14 +02:00
|
|
|
const char *desc;
|
2022-05-24 22:40:08 +02:00
|
|
|
enum peer_wire t;
|
|
|
|
|
|
|
|
/* Prevent runaway memory usage from many messages */
|
|
|
|
if (msg)
|
|
|
|
tal_free(msg);
|
|
|
|
|
|
|
|
/* This helper routine polls the peer. */
|
2023-07-27 22:13:33 +02:00
|
|
|
msg = peer_read(ctx, state->pps);
|
2022-05-24 22:40:08 +02:00
|
|
|
|
|
|
|
/* BOLT #1:
|
|
|
|
*
|
|
|
|
* A receiving node:
|
|
|
|
* - upon receiving a message of _odd_, unknown type:
|
|
|
|
* - MUST ignore the received message.
|
|
|
|
*/
|
|
|
|
if (is_unknown_msg_discardable(msg))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* A helper which decodes an error. */
|
2023-09-12 06:23:14 +02:00
|
|
|
desc = is_peer_error(msg, msg);
|
|
|
|
if (desc) {
|
|
|
|
*error = tal_fmt(ctx, "They sent an error: %s", desc);
|
2022-05-24 22:40:08 +02:00
|
|
|
|
2023-09-12 06:23:14 +02:00
|
|
|
/* Return NULL so caller knows to stop negotiating. */
|
|
|
|
return tal_free(msg);
|
|
|
|
}
|
2022-05-24 22:40:08 +02:00
|
|
|
|
2023-09-12 06:23:14 +02:00
|
|
|
desc = is_peer_warning(msg, msg);
|
|
|
|
if (desc) {
|
|
|
|
status_info("They sent %s", desc);
|
2024-01-22 23:47:35 +01:00
|
|
|
return tal_free(msg);
|
2022-05-24 22:40:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* In theory, we're in the middle of an open/RBF/splice, but
|
|
|
|
* it's possible we can get some different messages in
|
|
|
|
* the meantime! */
|
|
|
|
t = fromwire_peektype(msg);
|
|
|
|
switch (t) {
|
|
|
|
case WIRE_TX_ADD_INPUT:
|
|
|
|
case WIRE_TX_REMOVE_INPUT:
|
|
|
|
case WIRE_TX_ADD_OUTPUT:
|
|
|
|
case WIRE_TX_REMOVE_OUTPUT:
|
|
|
|
case WIRE_TX_COMPLETE:
|
2023-07-27 22:13:33 +02:00
|
|
|
case WIRE_TX_ABORT:
|
2024-01-22 23:47:35 +01:00
|
|
|
return msg;
|
2022-05-24 22:40:08 +02:00
|
|
|
case WIRE_TX_SIGNATURES:
|
2023-07-27 22:13:33 +02:00
|
|
|
case WIRE_CHANNEL_READY:
|
|
|
|
case WIRE_TX_INIT_RBF:
|
2022-05-24 22:40:08 +02:00
|
|
|
case WIRE_OPEN_CHANNEL2:
|
|
|
|
case WIRE_INIT:
|
|
|
|
case WIRE_ERROR:
|
|
|
|
case WIRE_OPEN_CHANNEL:
|
|
|
|
case WIRE_ACCEPT_CHANNEL:
|
|
|
|
case WIRE_FUNDING_CREATED:
|
|
|
|
case WIRE_FUNDING_SIGNED:
|
|
|
|
case WIRE_CLOSING_SIGNED:
|
|
|
|
case WIRE_UPDATE_ADD_HTLC:
|
|
|
|
case WIRE_UPDATE_FULFILL_HTLC:
|
|
|
|
case WIRE_UPDATE_FAIL_HTLC:
|
|
|
|
case WIRE_UPDATE_FAIL_MALFORMED_HTLC:
|
|
|
|
case WIRE_COMMITMENT_SIGNED:
|
|
|
|
case WIRE_REVOKE_AND_ACK:
|
|
|
|
case WIRE_UPDATE_FEE:
|
|
|
|
case WIRE_UPDATE_BLOCKHEIGHT:
|
|
|
|
case WIRE_CHANNEL_REESTABLISH:
|
|
|
|
case WIRE_ANNOUNCEMENT_SIGNATURES:
|
|
|
|
case WIRE_GOSSIP_TIMESTAMP_FILTER:
|
|
|
|
case WIRE_ONION_MESSAGE:
|
|
|
|
case WIRE_ACCEPT_CHANNEL2:
|
2023-07-27 22:13:33 +02:00
|
|
|
case WIRE_TX_ACK_RBF:
|
2022-05-24 22:40:08 +02:00
|
|
|
case WIRE_CHANNEL_ANNOUNCEMENT:
|
|
|
|
case WIRE_CHANNEL_UPDATE:
|
|
|
|
case WIRE_NODE_ANNOUNCEMENT:
|
|
|
|
case WIRE_QUERY_CHANNEL_RANGE:
|
|
|
|
case WIRE_REPLY_CHANNEL_RANGE:
|
|
|
|
case WIRE_QUERY_SHORT_CHANNEL_IDS:
|
|
|
|
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
|
|
|
|
case WIRE_WARNING:
|
|
|
|
case WIRE_PING:
|
|
|
|
case WIRE_PONG:
|
|
|
|
case WIRE_SHUTDOWN:
|
|
|
|
case WIRE_STFU:
|
2023-07-27 22:13:33 +02:00
|
|
|
case WIRE_PEER_STORAGE:
|
|
|
|
case WIRE_YOUR_PEER_STORAGE:
|
|
|
|
case WIRE_SPLICE:
|
|
|
|
case WIRE_SPLICE_ACK:
|
|
|
|
case WIRE_SPLICE_LOCKED:
|
2022-05-24 22:40:08 +02:00
|
|
|
*error = tal_fmt(ctx,
|
|
|
|
"Received invalid message from peer: %d", t);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *send_next(const tal_t *ctx,
|
|
|
|
struct interactivetx_context *ictx,
|
|
|
|
bool *finished)
|
|
|
|
{
|
|
|
|
struct channel_id *cid = &ictx->channel_id;
|
|
|
|
struct psbt_changeset *set = ictx->change_set;
|
|
|
|
u64 serial_id;
|
2023-07-27 22:13:33 +02:00
|
|
|
u8 *msg;
|
2022-05-24 22:40:08 +02:00
|
|
|
*finished = false;
|
|
|
|
|
|
|
|
if (!set)
|
|
|
|
goto tx_complete;
|
|
|
|
|
|
|
|
if (tal_count(set->added_ins) != 0) {
|
|
|
|
const struct input_set *in = &set->added_ins[0];
|
|
|
|
u8 *prevtx;
|
|
|
|
|
|
|
|
if (!psbt_get_serial_id(&in->input.unknowns, &serial_id))
|
2023-07-27 22:13:33 +02:00
|
|
|
return "interactivetx ADD_INPUT PSBT has invalid"
|
|
|
|
" serial_id.";
|
2022-05-24 22:40:08 +02:00
|
|
|
|
|
|
|
if (in->input.utxo)
|
2023-07-27 22:13:33 +02:00
|
|
|
prevtx = linearize_wtx(ctx, in->input.utxo);
|
2022-05-24 22:40:08 +02:00
|
|
|
else
|
2023-07-27 22:13:33 +02:00
|
|
|
return "interactivetx ADD_INPUT PSBT needs the previous"
|
|
|
|
" transaction set.";
|
2022-05-24 22:40:08 +02:00
|
|
|
|
|
|
|
msg = towire_tx_add_input(NULL, cid, serial_id,
|
2023-07-27 22:13:33 +02:00
|
|
|
prevtx, in->input.index,
|
|
|
|
in->input.sequence);
|
2022-05-24 22:40:08 +02:00
|
|
|
|
|
|
|
tal_arr_remove(&set->added_ins, 0);
|
|
|
|
}
|
|
|
|
else if (tal_count(set->rm_ins) != 0) {
|
|
|
|
if (!psbt_get_serial_id(&set->rm_ins[0].input.unknowns,
|
|
|
|
&serial_id))
|
2023-07-27 22:13:33 +02:00
|
|
|
return "interactivetx RM_INPUT PSBT has invalid"
|
|
|
|
" serial_id.";
|
2022-05-24 22:40:08 +02:00
|
|
|
|
|
|
|
msg = towire_tx_remove_input(NULL, cid, serial_id);
|
|
|
|
|
|
|
|
tal_arr_remove(&set->rm_ins, 0);
|
|
|
|
}
|
|
|
|
else if (tal_count(set->added_outs) != 0) {
|
|
|
|
struct amount_sat sats;
|
|
|
|
struct amount_asset asset_amt;
|
|
|
|
const struct output_set *out;
|
|
|
|
const u8 *script;
|
|
|
|
|
|
|
|
out = &set->added_outs[0];
|
|
|
|
|
|
|
|
if (!psbt_get_serial_id(&out->output.unknowns, &serial_id))
|
2023-07-27 22:13:33 +02:00
|
|
|
return "interactivetx ADD_OUTPUT PSBT has invalid"
|
|
|
|
" serial_id.";
|
2022-05-24 22:40:08 +02:00
|
|
|
|
2023-07-27 22:13:33 +02:00
|
|
|
asset_amt = wally_psbt_output_get_amount(&out->output);
|
2022-05-24 22:40:08 +02:00
|
|
|
sats = amount_asset_to_sat(&asset_amt);
|
2023-07-27 22:13:33 +02:00
|
|
|
script = wally_psbt_output_get_script(ctx, &out->output);
|
2022-05-24 22:40:08 +02:00
|
|
|
|
|
|
|
msg = towire_tx_add_output(NULL,
|
|
|
|
cid,
|
|
|
|
serial_id,
|
|
|
|
sats.satoshis, /* Raw: wire interface */
|
|
|
|
script);
|
|
|
|
|
|
|
|
tal_arr_remove(&set->added_outs, 0);
|
|
|
|
}
|
|
|
|
else if (tal_count(set->rm_outs) != 0) {
|
|
|
|
if (!psbt_get_serial_id(&set->rm_outs[0].output.unknowns,
|
|
|
|
&serial_id))
|
|
|
|
return "interactivetx RM_OUTPUT PSBT has invalid serial_id.";
|
|
|
|
|
|
|
|
msg = towire_tx_remove_output(NULL, cid, serial_id);
|
|
|
|
|
|
|
|
tal_arr_remove(&set->rm_outs, 0);
|
|
|
|
}
|
|
|
|
else /* no changes to psbt */
|
|
|
|
goto tx_complete;
|
|
|
|
|
|
|
|
if (!msg)
|
|
|
|
return "Interactivetx send_next failed to build a message";
|
2023-07-27 22:13:33 +02:00
|
|
|
peer_write(ictx->pps, take(msg));
|
2022-05-24 22:40:08 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
tx_complete:
|
|
|
|
|
|
|
|
if (!ictx->pause_when_complete) {
|
|
|
|
if (ictx->current_psbt->num_inputs > MAX_FUNDING_INPUTS)
|
|
|
|
return tal_fmt(ctx, "Humbly refusing to `tx_complete` "
|
|
|
|
"because we have too many inputs (%zu). "
|
2023-07-27 22:13:33 +02:00
|
|
|
"Limit is %d.",
|
2022-05-24 22:40:08 +02:00
|
|
|
ictx->current_psbt->num_inputs,
|
|
|
|
MAX_FUNDING_INPUTS);
|
|
|
|
|
|
|
|
if (ictx->current_psbt->num_outputs > MAX_FUNDING_OUTPUTS)
|
|
|
|
return tal_fmt(ctx, "Humbly refusing to `tx_complete` "
|
|
|
|
"because we have too many outputs (%zu). "
|
2023-07-27 22:13:33 +02:00
|
|
|
"Limit is %d.",
|
2022-05-24 22:40:08 +02:00
|
|
|
ictx->current_psbt->num_outputs,
|
|
|
|
MAX_FUNDING_OUTPUTS);
|
|
|
|
|
2023-07-27 22:13:33 +02:00
|
|
|
msg = towire_tx_complete(NULL, cid);
|
|
|
|
peer_write(ictx->pps, take(msg));
|
2022-05-24 22:40:08 +02:00
|
|
|
}
|
2023-07-27 22:13:33 +02:00
|
|
|
*finished = true;
|
2022-05-24 22:40:08 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-07-27 22:13:33 +02:00
|
|
|
static struct psbt_changeset *get_changes(const tal_t *ctx,
|
|
|
|
struct interactivetx_context *ictx,
|
|
|
|
struct wally_psbt *next_psbt)
|
|
|
|
{
|
|
|
|
u64 serial_id;
|
|
|
|
struct psbt_changeset *set = psbt_get_changeset(tmpctx,
|
|
|
|
ictx->current_psbt,
|
|
|
|
next_psbt);
|
|
|
|
|
|
|
|
/* Remove duplicate serial_ids from the change set. */
|
|
|
|
for (int i = 0; i < tal_count(set->added_ins); i++) {
|
|
|
|
struct bitcoin_outpoint point;
|
|
|
|
wally_psbt_input_get_outpoint(&set->added_ins[i].input, &point);
|
|
|
|
if (psbt_get_serial_id(&set->added_ins[i].input.unknowns,
|
|
|
|
&serial_id)) {
|
|
|
|
if (psbt_find_serial_input(ictx->current_psbt,
|
|
|
|
serial_id) != -1)
|
|
|
|
tal_arr_remove(&set->added_ins, i--);
|
|
|
|
else if (psbt_has_input(ictx->current_psbt, &point))
|
|
|
|
tal_arr_remove(&set->added_ins, i--);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < tal_count(set->added_outs); i++)
|
|
|
|
if (psbt_get_serial_id(&set->added_outs[i].output.unknowns,
|
|
|
|
&serial_id))
|
|
|
|
if (psbt_find_serial_output(ictx->current_psbt,
|
|
|
|
serial_id) != -1)
|
|
|
|
tal_arr_remove(&set->added_outs, i--);
|
|
|
|
|
|
|
|
return set;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool interactivetx_has_changes(struct interactivetx_context *ictx,
|
|
|
|
struct wally_psbt *next_psbt)
|
|
|
|
{
|
|
|
|
struct psbt_changeset *set = get_changes(tmpctx, ictx, next_psbt);
|
|
|
|
|
|
|
|
return tal_count(set->added_ins) || tal_count(set->rm_ins)
|
|
|
|
|| tal_count(set->added_outs) || tal_count(set->rm_outs);
|
|
|
|
}
|
|
|
|
|
2022-05-24 22:40:08 +02:00
|
|
|
char *process_interactivetx_updates(const tal_t *ctx,
|
|
|
|
struct interactivetx_context *ictx,
|
2024-01-22 23:47:35 +01:00
|
|
|
bool *received_tx_complete,
|
|
|
|
u8 **abort_msg)
|
2022-05-24 22:40:08 +02:00
|
|
|
{
|
|
|
|
bool we_complete = false, they_complete = false;
|
|
|
|
u8 *msg;
|
|
|
|
char *error = NULL;
|
|
|
|
struct wally_psbt *next_psbt;
|
|
|
|
|
2024-01-22 23:47:35 +01:00
|
|
|
*abort_msg = NULL;
|
|
|
|
|
2022-05-24 22:40:08 +02:00
|
|
|
if (received_tx_complete)
|
|
|
|
they_complete = *received_tx_complete;
|
|
|
|
|
|
|
|
/* Build change_set and handle PSBT variables */
|
|
|
|
ictx->change_set = tal_free(ictx->change_set);
|
|
|
|
|
2023-07-27 22:13:33 +02:00
|
|
|
/* Call next_update_fn or default to 'desired_psbt' */
|
|
|
|
next_psbt = ictx->next_update_fn(ictx, ictx);
|
2022-05-24 22:40:08 +02:00
|
|
|
|
2023-07-27 22:13:33 +02:00
|
|
|
/* Returning NULL from next_update_fn is the same as using `current_psbt`
|
2022-05-24 22:40:08 +02:00
|
|
|
* with no changes -- both indicate no changes */
|
|
|
|
if (!next_psbt)
|
|
|
|
next_psbt = ictx->current_psbt;
|
|
|
|
|
2023-07-27 22:13:33 +02:00
|
|
|
ictx->change_set = get_changes(ctx, ictx, next_psbt);
|
2022-05-24 22:40:08 +02:00
|
|
|
|
|
|
|
/* If current_psbt and next_psbt are the same, dont double free it!
|
|
|
|
* Otherwise we advance `current_psbt` to `next_psbt` and begin
|
|
|
|
* processing the change set in `ictx->change_set` */
|
|
|
|
if (ictx->current_psbt != next_psbt) {
|
|
|
|
/* psbt_get_changeset requires we keep the current_psbt until
|
|
|
|
* we're done withh change_set */
|
2023-07-27 22:13:33 +02:00
|
|
|
tal_steal(ictx->change_set, ictx->current_psbt);
|
2022-05-24 22:40:08 +02:00
|
|
|
ictx->current_psbt = next_psbt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* As initiator we always start with a single send to start it off */
|
|
|
|
if (ictx->our_role == TX_INITIATOR) {
|
|
|
|
error = send_next(ctx, ictx, &we_complete);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
|
|
|
if (ictx->pause_when_complete && we_complete) {
|
|
|
|
psbt_sort_by_serial_id(ictx->current_psbt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loop through tx update turns with peer */
|
|
|
|
while (!(we_complete && they_complete)) {
|
|
|
|
struct channel_id cid;
|
|
|
|
enum peer_wire t;
|
|
|
|
u64 serial_id;
|
|
|
|
|
|
|
|
/* Reset their_complete to false every round,
|
|
|
|
* they have to re-affirm every time */
|
|
|
|
they_complete = false;
|
|
|
|
|
|
|
|
if (received_tx_complete)
|
|
|
|
*received_tx_complete = false;
|
|
|
|
|
|
|
|
msg = read_next_msg(ctx, ictx, &error);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
|
|
|
t = fromwire_peektype(msg);
|
|
|
|
switch (t) {
|
|
|
|
case WIRE_TX_ADD_INPUT: {
|
2023-07-27 22:13:33 +02:00
|
|
|
const u8 *tx_bytes;
|
2022-05-24 22:40:08 +02:00
|
|
|
u32 sequence;
|
|
|
|
size_t len;
|
|
|
|
struct bitcoin_tx *tx;
|
|
|
|
struct bitcoin_outpoint outpoint;
|
|
|
|
|
|
|
|
if (!fromwire_tx_add_input(ctx, msg, &cid,
|
|
|
|
&serial_id,
|
|
|
|
cast_const2(u8 **,
|
|
|
|
&tx_bytes),
|
2023-07-27 22:13:33 +02:00
|
|
|
&outpoint.n, &sequence))
|
2022-05-24 22:40:08 +02:00
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Parsing tx_add_input %s",
|
|
|
|
tal_hex(ctx, msg));
|
|
|
|
|
|
|
|
/*
|
2024-03-18 06:32:47 +01:00
|
|
|
* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - if has received 4096 `tx_add_input`
|
|
|
|
* messages during this negotiation
|
|
|
|
*/
|
|
|
|
if (++ictx->tx_add_input_count >= MAX_TX_ADD_INPUT_MSG_RCVD)
|
|
|
|
return tal_fmt(ctx, "Too many `tx_add_input`s"
|
|
|
|
" received %d",
|
|
|
|
MAX_TX_ADD_INPUT_MSG_RCVD);
|
|
|
|
/*
|
2024-03-18 06:32:47 +01:00
|
|
|
* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - the `serial_id` has the wrong parity
|
|
|
|
*/
|
|
|
|
if (serial_id % 2 == ictx->our_role)
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Invalid serial_id rcvd. %"PRIu64,
|
|
|
|
serial_id);
|
|
|
|
/*
|
2024-03-18 06:32:47 +01:00
|
|
|
* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - the `serial_id` is already included in
|
|
|
|
* the transaction
|
|
|
|
*/
|
|
|
|
if (psbt_find_serial_input(ictx->current_psbt, serial_id) != -1)
|
2023-07-27 22:13:33 +02:00
|
|
|
return tal_fmt(ctx, "Duplicate serial_id rcvd"
|
2022-05-24 22:40:08 +02:00
|
|
|
" %"PRIu64, serial_id);
|
|
|
|
|
|
|
|
/* Convert tx_bytes to a tx! */
|
|
|
|
len = tal_bytelen(tx_bytes);
|
2024-01-09 08:33:36 +01:00
|
|
|
tx = pull_bitcoin_tx_only(ctx, &tx_bytes, &len);
|
2022-05-24 22:40:08 +02:00
|
|
|
|
|
|
|
if (!tx || len != 0)
|
|
|
|
return tal_fmt(ctx, "Invalid tx sent. len: %d",
|
|
|
|
(int)len);
|
|
|
|
|
|
|
|
if (outpoint.n >= tx->wtx->num_outputs)
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Invalid tx outnum sent. %u",
|
|
|
|
outpoint.n);
|
|
|
|
/*
|
|
|
|
* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2:
|
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - the `prevtx_out` input of `prevtx` is
|
|
|
|
* not an `OP_0` to `OP_16` followed by a single push
|
|
|
|
*/
|
|
|
|
if (!is_segwit_output(ctx,
|
|
|
|
&tx->wtx->outputs[outpoint.n],
|
2023-07-27 22:13:33 +02:00
|
|
|
NULL))
|
2022-05-24 22:40:08 +02:00
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Invalid tx sent. Not SegWit %s",
|
2024-03-20 01:47:52 +01:00
|
|
|
fmt_bitcoin_tx(ctx, tx));
|
2022-05-24 22:40:08 +02:00
|
|
|
|
|
|
|
/*
|
2024-03-18 06:32:47 +01:00
|
|
|
* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
2024-03-18 06:32:47 +01:00
|
|
|
* - MUST fail the negotiation if:...
|
2022-05-24 22:40:08 +02:00
|
|
|
* - the `prevtx` and `prevtx_vout` are
|
|
|
|
* identical to a previously added (and not
|
|
|
|
* removed) input's
|
|
|
|
*/
|
|
|
|
bitcoin_txid(tx, &outpoint.txid);
|
|
|
|
if (psbt_has_input(ictx->current_psbt, &outpoint))
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Unable to add input %s- "
|
|
|
|
"already present",
|
2024-03-20 01:47:52 +01:00
|
|
|
fmt_bitcoin_outpoint(ctx, &outpoint));
|
2022-05-24 22:40:08 +02:00
|
|
|
|
|
|
|
/*
|
2024-03-18 06:32:47 +01:00
|
|
|
* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - there are more than 252 inputs
|
|
|
|
*/
|
|
|
|
if (ictx->current_psbt->num_inputs + 1 > MAX_FUNDING_INPUTS)
|
|
|
|
return tal_fmt(ctx, "Too many inputs. Have %zu,"
|
2023-07-27 22:13:33 +02:00
|
|
|
" Max allowed %d",
|
2022-05-24 22:40:08 +02:00
|
|
|
ictx->current_psbt->num_inputs + 1,
|
|
|
|
MAX_FUNDING_INPUTS);
|
|
|
|
|
|
|
|
/*
|
2024-03-18 06:32:47 +01:00
|
|
|
* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node:
|
|
|
|
* - MUST add all received inputs to the transaction
|
|
|
|
*/
|
|
|
|
struct wally_psbt_input *in =
|
|
|
|
psbt_append_input(ictx->current_psbt, &outpoint,
|
|
|
|
sequence, NULL, NULL, NULL);
|
|
|
|
if (!in)
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Unable to add input %s",
|
2024-03-20 01:47:52 +01:00
|
|
|
fmt_bitcoin_outpoint(ctx, &outpoint));
|
2022-05-24 22:40:08 +02:00
|
|
|
|
|
|
|
tal_wally_start();
|
|
|
|
wally_psbt_input_set_utxo(in, tx->wtx);
|
|
|
|
tal_wally_end(ictx);
|
|
|
|
|
|
|
|
psbt_input_set_serial_id(ictx->current_psbt,
|
|
|
|
in, serial_id);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WIRE_TX_REMOVE_INPUT: {
|
|
|
|
int input_index;
|
|
|
|
|
|
|
|
if (!fromwire_tx_remove_input(msg, &cid, &serial_id))
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Parsing tx_remove_input %s",
|
|
|
|
tal_hex(ctx, msg));
|
|
|
|
|
2024-03-18 06:32:47 +01:00
|
|
|
/* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - the input or output identified by the
|
|
|
|
* `serial_id` was not added by the sender
|
|
|
|
*/
|
|
|
|
if (serial_id % 2 == ictx->our_role)
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Input can't be removed by peer "
|
|
|
|
"because they did not add it. "
|
|
|
|
"serial_id: %"PRIu64,
|
|
|
|
serial_id);
|
|
|
|
|
2024-03-18 06:32:47 +01:00
|
|
|
/* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - the `serial_id` does not correspond
|
|
|
|
* to a currently added input (or output)
|
|
|
|
*/
|
|
|
|
input_index = psbt_find_serial_input(ictx->current_psbt,
|
|
|
|
serial_id);
|
|
|
|
/* We choose to error/fail negotiation */
|
|
|
|
if (input_index == -1)
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"No input added with serial_id"
|
|
|
|
" %"PRIu64, serial_id);
|
|
|
|
|
|
|
|
psbt_rm_input(ictx->current_psbt, input_index);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WIRE_TX_ADD_OUTPUT: {
|
|
|
|
u64 value;
|
|
|
|
u8 *scriptpubkey;
|
|
|
|
struct wally_psbt_output *out;
|
|
|
|
struct amount_sat amt;
|
|
|
|
if (!fromwire_tx_add_output(ctx, msg, &cid,
|
|
|
|
&serial_id, &value,
|
|
|
|
&scriptpubkey))
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Parsing tx_add_output %s",
|
|
|
|
tal_hex(ctx, msg));
|
|
|
|
|
|
|
|
/*
|
2024-03-18 06:32:47 +01:00
|
|
|
* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - it has received 4096 `tx_add_output`
|
|
|
|
* messages during this negotiation
|
|
|
|
*/
|
|
|
|
if (++ictx->tx_add_output_count >= MAX_TX_ADD_OUTPUT_MSG_RCVD)
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Too many `tx_add_output`s"
|
|
|
|
" received (%d)",
|
|
|
|
MAX_TX_ADD_OUTPUT_MSG_RCVD);
|
|
|
|
|
2024-03-18 06:32:47 +01:00
|
|
|
/* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - the `serial_id` has the wrong parity
|
|
|
|
*/
|
|
|
|
if (serial_id % 2 == ictx->our_role)
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Invalid serial_id rcvd. %"PRIu64,
|
|
|
|
serial_id);
|
|
|
|
|
2024-03-18 06:32:47 +01:00
|
|
|
/* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - the `serial_id` is already included
|
|
|
|
* in the transaction */
|
|
|
|
if (psbt_find_serial_output(ictx->current_psbt, serial_id) != -1)
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Duplicate serial_id rcvd."
|
|
|
|
" %"PRIu64, serial_id);
|
|
|
|
amt = amount_sat(value);
|
|
|
|
|
2024-03-18 06:32:47 +01:00
|
|
|
/* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MAY fail the negotiation if `script`
|
|
|
|
* is non-standard */
|
2024-02-21 22:03:07 +01:00
|
|
|
if (!is_known_scripttype(scriptpubkey, tal_bytelen(scriptpubkey)))
|
2022-05-24 22:40:08 +02:00
|
|
|
return tal_fmt(ctx, "Script is not standard");
|
|
|
|
|
|
|
|
/*
|
2024-03-18 06:32:47 +01:00
|
|
|
* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - there are more than 252 outputs
|
|
|
|
*/
|
|
|
|
if (ictx->current_psbt->num_outputs + 1 > MAX_FUNDING_OUTPUTS)
|
|
|
|
return tal_fmt(ctx, "Too many inputs. Have %zu,"
|
2023-07-27 22:13:33 +02:00
|
|
|
" Max allowed %d",
|
2022-05-24 22:40:08 +02:00
|
|
|
ictx->current_psbt->num_outputs + 1,
|
|
|
|
MAX_FUNDING_OUTPUTS);
|
|
|
|
|
|
|
|
out = psbt_append_output(ictx->current_psbt,
|
|
|
|
scriptpubkey,
|
|
|
|
amt);
|
|
|
|
|
|
|
|
psbt_output_set_serial_id(ictx->current_psbt,
|
|
|
|
out,
|
|
|
|
serial_id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WIRE_TX_REMOVE_OUTPUT: {
|
|
|
|
int output_index;
|
|
|
|
|
|
|
|
if (!fromwire_tx_remove_output(msg, &cid, &serial_id))
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Parsing tx_remove_output %s",
|
|
|
|
tal_hex(ctx, msg));
|
|
|
|
|
2024-03-18 06:32:47 +01:00
|
|
|
/* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - the input or output identified by the
|
|
|
|
* `serial_id` was not added by the sender
|
|
|
|
*/
|
|
|
|
if (serial_id % 2 == ictx->our_role)
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Output can't be removed by peer "
|
|
|
|
"because they did not add it. "
|
|
|
|
"serial_id: %"PRIu64,
|
|
|
|
serial_id);
|
|
|
|
|
2024-03-18 06:32:47 +01:00
|
|
|
/* BOLT #2:
|
2022-05-24 22:40:08 +02:00
|
|
|
* The receiving node: ...
|
|
|
|
* - MUST fail the negotiation if: ...
|
|
|
|
* - the `serial_id` does not correspond to a
|
|
|
|
* currently added input (or output)
|
|
|
|
*/
|
|
|
|
output_index = psbt_find_serial_output(ictx->current_psbt,
|
|
|
|
serial_id);
|
|
|
|
if (output_index == -1)
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"No output added with serial_id"
|
|
|
|
" %"PRIu64, serial_id);
|
|
|
|
psbt_rm_output(ictx->current_psbt, output_index);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WIRE_TX_COMPLETE:
|
|
|
|
if (!fromwire_tx_complete(msg, &cid))
|
|
|
|
return tal_fmt(ctx,
|
|
|
|
"Parsing tx_complete %s",
|
|
|
|
tal_hex(ctx, msg));
|
|
|
|
they_complete = true;
|
|
|
|
if (received_tx_complete)
|
|
|
|
*received_tx_complete = true;
|
|
|
|
break;
|
2023-07-27 22:13:33 +02:00
|
|
|
case WIRE_TX_ABORT:
|
2024-01-22 23:47:35 +01:00
|
|
|
*abort_msg = msg;
|
|
|
|
return NULL;
|
2022-05-24 22:40:08 +02:00
|
|
|
case WIRE_INIT:
|
|
|
|
case WIRE_ERROR:
|
|
|
|
case WIRE_WARNING:
|
|
|
|
case WIRE_OPEN_CHANNEL:
|
|
|
|
case WIRE_ACCEPT_CHANNEL:
|
|
|
|
case WIRE_FUNDING_CREATED:
|
|
|
|
case WIRE_FUNDING_SIGNED:
|
2023-07-27 22:13:33 +02:00
|
|
|
case WIRE_CHANNEL_READY:
|
2022-05-24 22:40:08 +02:00
|
|
|
case WIRE_SHUTDOWN:
|
|
|
|
case WIRE_CLOSING_SIGNED:
|
|
|
|
case WIRE_UPDATE_ADD_HTLC:
|
|
|
|
case WIRE_UPDATE_FULFILL_HTLC:
|
|
|
|
case WIRE_UPDATE_FAIL_HTLC:
|
|
|
|
case WIRE_UPDATE_FAIL_MALFORMED_HTLC:
|
|
|
|
case WIRE_COMMITMENT_SIGNED:
|
|
|
|
case WIRE_REVOKE_AND_ACK:
|
|
|
|
case WIRE_UPDATE_FEE:
|
|
|
|
case WIRE_UPDATE_BLOCKHEIGHT:
|
|
|
|
case WIRE_CHANNEL_REESTABLISH:
|
|
|
|
case WIRE_ANNOUNCEMENT_SIGNATURES:
|
|
|
|
case WIRE_GOSSIP_TIMESTAMP_FILTER:
|
|
|
|
case WIRE_ONION_MESSAGE:
|
|
|
|
case WIRE_TX_SIGNATURES:
|
|
|
|
case WIRE_OPEN_CHANNEL2:
|
|
|
|
case WIRE_ACCEPT_CHANNEL2:
|
2023-07-27 22:13:33 +02:00
|
|
|
case WIRE_TX_INIT_RBF:
|
|
|
|
case WIRE_TX_ACK_RBF:
|
2022-05-24 22:40:08 +02:00
|
|
|
case WIRE_CHANNEL_ANNOUNCEMENT:
|
|
|
|
case WIRE_CHANNEL_UPDATE:
|
|
|
|
case WIRE_NODE_ANNOUNCEMENT:
|
|
|
|
case WIRE_QUERY_CHANNEL_RANGE:
|
|
|
|
case WIRE_REPLY_CHANNEL_RANGE:
|
|
|
|
case WIRE_QUERY_SHORT_CHANNEL_IDS:
|
|
|
|
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
|
|
|
|
case WIRE_PING:
|
|
|
|
case WIRE_PONG:
|
2023-07-27 22:13:33 +02:00
|
|
|
case WIRE_PEER_STORAGE:
|
|
|
|
case WIRE_YOUR_PEER_STORAGE:
|
2022-05-24 22:40:08 +02:00
|
|
|
case WIRE_SPLICE:
|
|
|
|
case WIRE_SPLICE_ACK:
|
2023-07-27 22:13:33 +02:00
|
|
|
case WIRE_STFU:
|
|
|
|
case WIRE_SPLICE_LOCKED:
|
2022-05-24 22:40:08 +02:00
|
|
|
return tal_fmt(ctx, "Unexpected wire message %s",
|
|
|
|
tal_hex(ctx, msg));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(we_complete && they_complete))
|
|
|
|
send_next(ctx, ictx, &we_complete);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sort psbt! */
|
|
|
|
psbt_sort_by_serial_id(ictx->current_psbt);
|
|
|
|
|
2023-07-27 22:13:33 +02:00
|
|
|
tal_steal(ictx, ictx->current_psbt);
|
|
|
|
|
2022-05-24 22:40:08 +02:00
|
|
|
return NULL;
|
|
|
|
}
|