core-lightning/lightningd/dual_open_control.c
niftynei b8b910e4c4 df-rbf: update channel data on depth reached
When the funding tx reaches depth, update the channel's data to the
"correct" funding transaction info from inflights (if necessary).

This will be necessary if:
    - the transaction has been successfully RBF'd and
    - the lesser fee transaction is the one successfully mined, OR
    - the channel is in the process of being RBF'd
2021-03-03 12:28:22 +10:30

2202 lines
64 KiB
C

/* This is the lightningd handler for messages to/from various
* dualopend subdaemons. It manages the callbacks and database
* saves and funding tx watching for a channel open */
#include <bitcoin/psbt.h>
#include <bitcoin/script.h>
#include <ccan/ccan/take/take.h>
#include <ccan/short_types/short_types.h>
#include <common/amount.h>
#include <common/channel_config.h>
#include <common/channel_id.h>
#include <common/derive_basepoints.h>
#include <common/features.h>
#include <common/fee_states.h>
#include <common/htlc.h>
#include <common/json_helpers.h>
#include <common/json_tok.h>
#include <common/per_peer_state.h>
#include <common/psbt_open.h>
#include <common/type_to_string.h>
#include <hsmd/capabilities.h>
#include <lightningd/chaintopology.h>
#include <lightningd/channel_control.h>
#include <lightningd/closing_control.h>
#include <lightningd/dual_open_control.h>
#include <lightningd/hsm_control.h>
#include <lightningd/notification.h>
#include <lightningd/opening_common.h>
#include <lightningd/peer_control.h>
#include <lightningd/plugin_hook.h>
#include <openingd/dualopend_wiregen.h>
#include <wire/common_wiregen.h>
#include <wire/peer_wire.h>
struct commit_rcvd {
struct channel *channel;
struct channel_id cid;
struct uncommitted_channel *uc;
};
static void handle_signed_psbt(struct lightningd *ld,
struct subd *dualopend,
const struct wally_psbt *psbt,
struct commit_rcvd *rcvd)
{
/* Now that we've got the signed PSBT, save it */
rcvd->channel->psbt =
tal_steal(rcvd->channel,
cast_const(struct wally_psbt *, psbt));
wallet_channel_save(ld->wallet, rcvd->channel);
channel_watch_funding(ld, rcvd->channel);
/* Send peer our signatures */
subd_send_msg(dualopend,
take(towire_dualopend_send_tx_sigs(NULL, psbt)));
}
/* ~Map of the Territory~
*
* openchannel hook
- reserveinputs feerate [{"amt": amt, "script": ""}] excludecommon=true -> psbt
-> psbt_set
*
* openchannel_changed hook
- psbt --> most recent
-> psbt_set (if same as orig) | complete flag
*
* openchannel_sign hook
- signpsbt psbt -> partially_signed_psbt
-> partially_signed_psbt
*/
struct openchannel2_payload {
struct subd *dualopend;
struct node_id peer_id;
struct channel_id channel_id;
struct amount_sat their_funding;
struct amount_sat dust_limit_satoshis;
struct amount_msat max_htlc_value_in_flight_msat;
struct amount_msat htlc_minimum_msat;
u32 funding_feerate_max;
u32 funding_feerate_min;
u32 funding_feerate_best;
u32 feerate_our_max;
u32 feerate_our_min;
u32 commitment_feerate_per_kw;
u16 to_self_delay;
u16 max_accepted_htlcs;
u8 channel_flags;
u32 locktime;
u8 *shutdown_scriptpubkey;
/* FIXME: include the podle? */
struct amount_sat accepter_funding;
u32 funding_feerate_per_kw;
struct wally_psbt *psbt;
const u8 *our_shutdown_scriptpubkey;
char *err_msg;
};
static void
openchannel2_hook_serialize(struct openchannel2_payload *payload,
struct json_stream *stream)
{
json_object_start(stream, "openchannel2");
json_add_node_id(stream, "id", &payload->peer_id);
json_add_channel_id(stream, "channel_id", &payload->channel_id);
json_add_amount_sat_only(stream, "their_funding",
payload->their_funding);
json_add_amount_sat_only(stream, "dust_limit_satoshis",
payload->dust_limit_satoshis);
json_add_amount_msat_only(stream, "max_htlc_value_in_flight_msat",
payload->max_htlc_value_in_flight_msat);
json_add_amount_msat_only(stream, "htlc_minimum_msat",
payload->htlc_minimum_msat);
json_add_num(stream, "funding_feerate_max",
payload->funding_feerate_max);
json_add_num(stream, "funding_feerate_min",
payload->funding_feerate_min);
json_add_num(stream, "funding_feerate_best",
payload->funding_feerate_best);
json_add_num(stream, "feerate_our_max",
payload->feerate_our_max);
json_add_num(stream, "feerate_our_min",
payload->feerate_our_min);
json_add_num(stream, "commitment_feerate_per_kw",
payload->commitment_feerate_per_kw);
json_add_num(stream, "to_self_delay", payload->to_self_delay);
json_add_num(stream, "max_accepted_htlcs", payload->max_accepted_htlcs);
json_add_num(stream, "channel_flags", payload->channel_flags);
json_add_num(stream, "locktime", payload->locktime);
if (tal_bytelen(payload->shutdown_scriptpubkey) != 0)
json_add_hex_talarr(stream, "shutdown_scriptpubkey",
payload->shutdown_scriptpubkey);
/* FIXME: include the podle? */
json_object_end(stream);
}
struct openchannel2_psbt_payload {
struct subd *dualopend;
struct wally_psbt *psbt;
struct commit_rcvd *rcvd;
struct lightningd *ld;
};
static void
openchannel2_changed_hook_serialize(struct openchannel2_psbt_payload *payload,
struct json_stream *stream)
{
json_object_start(stream, "openchannel2_changed");
json_add_psbt(stream, "psbt", payload->psbt);
json_add_string(stream, "channel_id",
type_to_string(tmpctx, struct channel_id,
&payload->rcvd->cid));
json_object_end(stream);
}
static void
openchannel2_sign_hook_serialize(struct openchannel2_psbt_payload *payload,
struct json_stream *stream)
{
json_object_start(stream, "openchannel2_sign");
json_add_psbt(stream, "psbt", payload->psbt);
json_add_string(stream, "channel_id",
type_to_string(tmpctx, struct channel_id,
&payload->rcvd->channel->cid));
json_object_end(stream);
}
static const u8 *hook_extract_shutdown_script(struct subd* dualopend,
const char *buffer,
const jsmntok_t *toks)
{
const u8 *close_to_script;
enum address_parse_result parse_res;
if (!buffer)
return NULL;
const jsmntok_t *t = json_get_member(buffer, toks, "result");
if (!t)
fatal("Plugin must return a 'result'"
"%.*s", toks[0].end - toks[0].start,
buffer + toks[0].start);
if (!json_tok_streq(buffer, t, "continue")) {
char *errmsg = "Client error. Unable to continue";
subd_send_msg(dualopend,
take(towire_dualopend_fail(NULL, errmsg)));
return NULL;
}
const jsmntok_t *close_to_tok = json_get_member(buffer, toks, "close_to");
if (!close_to_tok)
return NULL;
parse_res = json_to_address_scriptpubkey(tmpctx, chainparams, buffer,
close_to_tok, &close_to_script);
switch (parse_res) {
case ADDRESS_PARSE_UNRECOGNIZED:
fatal("Plugin returned an invalid response to the"
" openchannel2.close_to hook: %.*s",
t->end - t->start, buffer + t->start);
case ADDRESS_PARSE_WRONG_NETWORK:
fatal("Plugin returned invalid response to the"
" openchannel2.close_to hook: address %s is"
" not on network %s",
tal_hex(NULL, close_to_script),
chainparams->network_name);
case ADDRESS_PARSE_SUCCESS:
return close_to_script;
}
return NULL;
}
static bool
hook_extract_psbt(const tal_t *ctx, struct subd *dualopend, const char *buffer,
const jsmntok_t *toks, char *hook_name,
bool allow_empty,
struct wally_psbt **out)
{
if (!buffer)
fatal("Plugin must return a valid response to %s", hook_name);
const jsmntok_t *t = json_get_member(buffer, toks, "result");
if (!t)
fatal("Plugin must return a 'result' to %s"
"%.*s", hook_name, toks[0].end - toks[0].start,
buffer + toks[0].start);
if (!json_tok_streq(buffer, t, "continue")) {
/* dualopend might have closed if we're on the signed round */
if (dualopend) {
char *errmsg = "Client error. Unable to continue";
subd_send_msg(dualopend,
take(towire_dualopend_fail(NULL, errmsg)));
}
return false;
}
const jsmntok_t *psbt_tok = json_get_member(buffer, toks, "psbt");
if (!psbt_tok) {
if (!allow_empty)
fatal("Plugin must return a 'psbt' to a 'continue'd"
"%s %.*s", hook_name,
toks[0].end - toks[0].start,
buffer + toks[0].start);
*out = NULL;
return true;
}
*out = json_to_psbt(ctx, buffer, psbt_tok);
if (!*out)
fatal("Plugin must return a valid 'psbt' to a 'continue'd"
"%s %.*s", hook_name,
toks[0].end - toks[0].start,
buffer + toks[0].start);
return true;
}
/* The field is *always* assumed msats, as that's the unit
* amount we're transitioning our API over to. A 'xxxsat'
* unit will be interpreted correctly, but a value given
* without a unit will always be interpreted as msats */
static bool
hook_extract_amount(struct subd *dualopend,
const char *buffer,
const jsmntok_t *toks,
char *field_name,
struct amount_sat *amount)
{
struct amount_msat msats;
if (!buffer)
return false;
const jsmntok_t *t = json_get_member(buffer, toks, "result");
if (!t)
fatal("Plugin must return a 'result' "
" %.*s", toks[0].end - toks[0].start,
buffer + toks[0].start);
if (!json_tok_streq(buffer, t, "continue")) {
char *errmsg = "Client error. Unable to continue";
subd_send_msg(dualopend,
take(towire_dualopend_fail(NULL, errmsg)));
return false;
}
/* If there's no amount_sat field, that's ok */
const jsmntok_t *amt_tok = json_get_member(buffer, toks, field_name);
if (!amt_tok) {
*amount = AMOUNT_SAT(0);
return true;
}
if (!json_to_msat(buffer, amt_tok, &msats))
fatal("Plugin must return a valid '%s' to a 'continue'd"
" %.*s", field_name,
toks[0].end - toks[0].start,
buffer + toks[0].start);
*amount = amount_msat_to_sat_round_down(msats);
return true;
}
#define CHECK_CHANGES(set, dir) \
do { \
for (size_t i = 0; i < tal_count(set); i++) { \
ok = psbt_get_serial_id(&set[i].dir.unknowns, \
&serial_id); \
assert(ok); \
if (serial_id % 2 != opener_side) \
return true; \
} \
} while (false)
static bool psbt_side_contribs_changed(struct wally_psbt *orig,
struct wally_psbt *new,
enum side opener_side)
{
struct psbt_changeset *cs;
u64 serial_id;
bool ok;
cs = psbt_get_changeset(tmpctx, orig, new);
if (tal_count(cs->added_ins) == 0 &&
tal_count(cs->rm_ins) == 0 &&
tal_count(cs->added_outs) == 0 &&
tal_count(cs->rm_outs) == 0)
return false;
/* If there were *any* changes, then the answer to the 'both sides'
* question is "yes, there were changes" */
if (opener_side == NUM_SIDES)
return true;
/* Check that none of the included updates have a serial
* id that's the peer's parity */
CHECK_CHANGES(cs->added_ins, input);
CHECK_CHANGES(cs->rm_ins, input);
CHECK_CHANGES(cs->added_outs, output);
CHECK_CHANGES(cs->rm_outs, output);
return false;
}
/* dualopend dies? Remove dualopend ptr from payload */
static void openchannel2_remove_dualopend(struct subd *dualopend,
struct openchannel2_payload *payload)
{
assert(payload->dualopend == dualopend);
payload->dualopend = NULL;
}
static void
openchannel2_hook_cb(struct openchannel2_payload *payload STEALS)
{
struct subd *dualopend = payload->dualopend;
struct uncommitted_channel *uc;
u8 *msg;
/* Free payload regardless of what happens next */
tal_steal(tmpctx, payload);
/* If our daemon died, we're done */
if (!dualopend)
return;
assert(dualopend->ctype == UNCOMMITTED);
uc = dualopend->channel;
/* Channel open is currently in progress elsewhere! */
if (uc->fc || uc->got_offer) {
msg = towire_dualopend_fail(NULL, "Already initiated channel"
" open");
log_debug(dualopend->ld->log,
"Our open in progress, denying their offer");
return subd_send_msg(dualopend, take(msg));
}
tal_del_destructor2(dualopend, openchannel2_remove_dualopend, payload);
if (payload->err_msg) {
log_debug(dualopend->ld->log,
"openchannel2 hook rejects and says '%s'",
payload->err_msg);
msg = towire_dualopend_fail(NULL, payload->err_msg);
return subd_send_msg(dualopend, take(msg));
}
/* If there's no plugin, the funding_feerate_per_kw will be zero.
* In this case, we set the funding_feerate_per_kw to the default,
* the 'best' */
if (payload->funding_feerate_per_kw == 0) {
u32 best_feerate
= payload->funding_feerate_per_kw
= payload->funding_feerate_best;
/* We use the old checks here now, against the base feerate */
if (best_feerate < payload->feerate_our_min) {
msg = towire_dualopend_fail(NULL, tal_fmt(tmpctx,
"feerate_per_kw %u below"
" minimum %u",
best_feerate,
payload->feerate_our_min));
return subd_send_msg(dualopend, take(msg));
}
if (best_feerate > payload->feerate_our_max) {
msg = towire_dualopend_fail(NULL, tal_fmt(tmpctx,
"feerate_per_kw %u above"
" maximum %u",
best_feerate,
payload->feerate_our_max));
return subd_send_msg(dualopend, take(msg));
}
}
uc->got_offer = true;
msg = towire_dualopend_got_offer_reply(NULL, payload->accepter_funding,
payload->funding_feerate_per_kw,
payload->psbt,
payload->our_shutdown_scriptpubkey);
subd_send_msg(dualopend, take(msg));
}
static bool
openchannel2_hook_deserialize(struct openchannel2_payload *payload,
const char *buffer,
const jsmntok_t *toks)
{
struct subd *dualopend = payload->dualopend;
/* If our daemon died, we're done */
if (!dualopend) {
tal_free(payload);
return false;
}
const jsmntok_t *t_result = json_get_member(buffer, toks, "result");
if (!t_result)
fatal("Plugin returned an invalid response to the"
" openchannel2 hook: %.*s",
json_tok_full_len(toks),
json_tok_full(buffer, toks));
if (json_tok_streq(buffer, t_result, "reject")) {
/* Should not have set any other fields if 'reject'ing */
if (json_get_member(buffer, toks, "close_to"))
fatal("Plugin rejected openchannel2 but"
" also set close_to");
if (json_get_member(buffer, toks, "psbt"))
fatal("Plugin rejected openchannel2 but"
" also set `psbt`");
if (json_get_member(buffer, toks, "accepter_funding_msat"))
fatal("Plugin rejected openchannel2 but"
" also set `accepter_funding_psbt`");
if (json_get_member(buffer, toks, "funding_feerate"))
fatal("Plugin rejected openchannel2 but"
" also set `funding_feerate`");
const jsmntok_t *t_errmsg = json_get_member(buffer, toks,
"error_message");
if (t_errmsg)
payload->err_msg = json_strdup(payload,
buffer, t_errmsg);
else
payload->err_msg = "";
openchannel2_hook_cb(payload);
return false;
} else if (!json_tok_streq(buffer, t_result, "continue"))
fatal("Plugin returned an invalid response to the"
" openchannel2 hook: %.*s",
json_tok_full_len(toks),
json_tok_full(buffer, toks));
if (!hook_extract_psbt(payload, dualopend, buffer, toks,
"openchannel2", true, &payload->psbt))
return false;
payload->our_shutdown_scriptpubkey =
hook_extract_shutdown_script(dualopend, buffer, toks);
/* Add a serial_id to everything that doesn't have one yet */
if (payload->psbt)
psbt_add_serials(payload->psbt, TX_ACCEPTER);
if (payload->psbt && !psbt_has_required_fields(payload->psbt))
fatal("Plugin supplied PSBT that's missing required fields. %s",
type_to_string(tmpctx, struct wally_psbt, payload->psbt));
if (!hook_extract_amount(dualopend, buffer, toks,
"accepter_funding_msat",
&payload->accepter_funding))
fatal("Plugin failed to supply accepter_funding_msat field");
const jsmntok_t *t = json_get_member(buffer, toks, "funding_feerate");
/* If they don't return a feerate, we use the best */
if (!t)
payload->funding_feerate_per_kw = payload->funding_feerate_best;
else {
if (!json_to_number(buffer, t,
&payload->funding_feerate_per_kw))
fatal("Unable to parse 'funding-feerate'");
if (payload->funding_feerate_per_kw
< payload->funding_feerate_min
|| payload->funding_feerate_per_kw
> payload->funding_feerate_max)
/* FIXME: return an error instead of failing? */
fatal("Plugin supplied invalid funding feerate %d."
" Outside valid range %d - %d",
payload->funding_feerate_per_kw,
payload->funding_feerate_min,
payload->funding_feerate_max);
}
if (!payload->psbt &&
!amount_sat_eq(payload->accepter_funding, AMOUNT_SAT(0))) {
/* Gotta give a PSBT if you set the accepter_funding amount */
/* Let dualopend know we've failed */
payload->err_msg = "Client error. Unable to continue";
openchannel2_hook_cb(payload);
return false;
}
return true;
}
/* dualopend dies? Remove dualopend ptr from payload */
static void
openchannel2_psbt_remove_dualopend(struct subd *dualopend,
struct openchannel2_psbt_payload *payload)
{
assert(payload->dualopend == dualopend);
payload->dualopend = NULL;
}
static bool
openchannel2_changed_deserialize(struct openchannel2_psbt_payload *payload,
const char *buffer, const jsmntok_t *toks)
{
struct subd *dualopend = payload->dualopend;
struct wally_psbt *psbt;
if (!hook_extract_psbt(NULL, dualopend, buffer,
toks, "openchannel2_changed",
false, &psbt))
return false;
/* Add serials to PSBT, before checking for required fields */
psbt_add_serials(psbt, TX_ACCEPTER);
if (!psbt_has_required_fields(psbt))
fatal("Plugin supplied PSBT that's missing required fields. %s",
type_to_string(tmpctx, struct wally_psbt, psbt));
if (payload->psbt)
tal_free(payload->psbt);
payload->psbt = tal_steal(payload, psbt);
return true;
}
static void
openchannel2_changed_hook_cb(struct openchannel2_psbt_payload *payload STEALS)
{
struct subd *dualopend = payload->dualopend;
/* Free payload regardless of what happens next */
tal_steal(tmpctx, payload);
/* If our daemon died, we're done */
if (!dualopend)
return;
tal_del_destructor2(dualopend,
openchannel2_psbt_remove_dualopend,
payload);
subd_send_msg(dualopend,
take(towire_dualopend_psbt_updated(NULL,
payload->psbt)));
}
static bool
openchannel2_signed_deserialize(struct openchannel2_psbt_payload *payload,
const char *buffer, const jsmntok_t *toks)
{
struct subd *dualopend = payload->dualopend;
struct wally_psbt *psbt;
if (!hook_extract_psbt(NULL, dualopend, buffer,
toks, "openchannel2_sign",
false, &psbt))
return false;
if (!psbt_has_required_fields(psbt))
fatal("Plugin supplied PSBT that's missing required fields. %s",
type_to_string(tmpctx, struct wally_psbt, psbt));
/* Verify that inputs/outputs are the same. Note that this is a
* 'de minimus' check -- we just look at serial_ids. If you've
* totally managled the data here but left the serial_ids intact,
* you'll get a failure back from the peer when you send
* commitment sigs */
if (psbt_side_contribs_changed(payload->psbt, psbt, NUM_SIDES))
fatal("Plugin must not change psbt input/output set. "
"orig: %s. updated: %s",
type_to_string(tmpctx, struct wally_psbt,
payload->psbt),
type_to_string(tmpctx, struct wally_psbt,
psbt));
if (payload->psbt)
tal_free(payload->psbt);
payload->psbt = tal_steal(payload, psbt);
return true;
}
static void
openchannel2_sign_hook_cb(struct openchannel2_psbt_payload *payload STEALS)
{
/* Whatever happens, we free the payload */
tal_steal(tmpctx, payload);
if (!payload->dualopend) {
log_broken(payload->ld->log, "dualopend daemon died"
" before signed PSBT returned");
channel_internal_error(payload->rcvd->channel, "daemon died");
return;
}
tal_del_destructor2(payload->dualopend,
openchannel2_psbt_remove_dualopend,
payload);
/* Finalize it, if not already. It shouldn't work entirely */
psbt_finalize(payload->psbt);
if (!psbt_side_finalized(payload->psbt, TX_ACCEPTER))
fatal("Plugin must return a 'psbt' with signatures "
"for their inputs %s",
type_to_string(tmpctx, struct wally_psbt, payload->psbt));
handle_signed_psbt(payload->ld, payload->dualopend,
payload->psbt, payload->rcvd);
}
REGISTER_PLUGIN_HOOK(openchannel2,
openchannel2_hook_deserialize,
openchannel2_hook_cb,
openchannel2_hook_serialize,
struct openchannel2_payload *);
REGISTER_PLUGIN_HOOK(openchannel2_changed,
openchannel2_changed_deserialize,
openchannel2_changed_hook_cb,
openchannel2_changed_hook_serialize,
struct openchannel2_psbt_payload *);
REGISTER_PLUGIN_HOOK(openchannel2_sign,
openchannel2_signed_deserialize,
openchannel2_sign_hook_cb,
openchannel2_sign_hook_serialize,
struct openchannel2_psbt_payload *);
/* Steals fields from uncommitted_channel: returns NULL if can't generate a
* key for this channel (shouldn't happen!). */
static struct channel *
wallet_commit_channel(struct lightningd *ld,
struct uncommitted_channel *uc,
struct channel_id *cid,
struct bitcoin_tx *remote_commit,
struct bitcoin_signature *remote_commit_sig,
const struct bitcoin_txid *funding_txid,
u16 funding_outnum,
struct amount_sat total_funding,
struct amount_sat our_funding,
u8 channel_flags,
const struct channel_info *channel_info,
u32 feerate,
enum side opener,
const u8 *our_upfront_shutdown_script,
const u8 *remote_upfront_shutdown_script)
{
struct channel *channel;
s64 final_key_idx;
bool option_static_remotekey;
bool option_anchor_outputs;
struct amount_msat our_msat;
/* Get a key to use for closing outputs from this tx */
final_key_idx = wallet_get_newindex(ld);
if (final_key_idx == -1) {
log_broken(uc->log, "Can't get final key index");
return NULL;
}
if (!amount_sat_to_msat(&our_msat, our_funding)) {
log_broken(uc->log, "Unable to convert funds");
return NULL;
}
/* BOLT-7b04b1461739c5036add61782d58ac490842d98b #9
* | 222/223 | `option_dual_fund`
* | Use v2 of channel open, enables dual funding
* | IN9
* | `option_anchor_outputs` */
option_static_remotekey = true;
option_anchor_outputs = true;
channel = new_channel(uc->peer, uc->dbid,
NULL, /* No shachain yet */
DUALOPEND_OPEN_INIT,
opener,
uc->log,
take(uc->transient_billboard),
channel_flags,
&uc->our_config,
uc->minimum_depth,
1, 1, 0,
funding_txid,
funding_outnum,
total_funding,
AMOUNT_MSAT(0),
our_funding,
false, /* !remote_funding_locked */
false, /* !remote_tx_sigs */
NULL, /* no scid yet */
cid,
/* The three arguments below are msatoshi_to_us,
* msatoshi_to_us_min, and msatoshi_to_us_max.
* Because, this is a newly-funded channel,
* all three are same value. */
our_msat,
our_msat, /* msat_to_us_min */
our_msat, /* msat_to_us_max */
remote_commit,
remote_commit_sig,
NULL, /* No HTLC sigs yet */
channel_info,
take(new_fee_states(NULL, opener, &feerate)),
NULL, /* No shutdown_scriptpubkey[REMOTE] yet */
our_upfront_shutdown_script,
final_key_idx, false,
NULL, /* No commit sent yet */
/* If we're fundee, could be a little before this
* in theory, but it's only used for timing out. */
get_block_height(ld->topology),
feerate, feerate,
/* We are connected */
true,
&uc->local_basepoints,
&uc->local_funding_pubkey,
NULL,
ld->config.fee_base,
ld->config.fee_per_satoshi,
remote_upfront_shutdown_script,
option_static_remotekey,
option_anchor_outputs,
NULL,
NUM_SIDES, /* closer not yet known */
opener == LOCAL ? REASON_USER : REASON_REMOTE);
/* Now we finally put it in the database. */
wallet_channel_insert(ld->wallet, channel);
return channel;
}
static void handle_peer_wants_to_close(struct subd *dualopend,
const u8 *msg)
{
u8 *scriptpubkey;
struct lightningd *ld = dualopend->ld;
struct channel *channel;
char *errmsg;
/* We shouldn't get this message while we're waiting to finish */
if (dualopend->ctype == UNCOMMITTED) {
log_broken(dualopend->ld->log, "Channel in wrong state for"
" shutdown, still has uncommitted"
" channel pending.");
errmsg = "Channel not established yet, shutdown invalid";
subd_send_msg(dualopend,
take(towire_dualopend_fail(NULL, errmsg)));
return;
}
channel = dualopend->channel;
if (!fromwire_dualopend_got_shutdown(channel, msg, &scriptpubkey)) {
channel_internal_error(channel, "bad channel_got_shutdown %s",
tal_hex(msg, msg));
return;
}
tal_free(channel->shutdown_scriptpubkey[REMOTE]);
channel->shutdown_scriptpubkey[REMOTE] = scriptpubkey;
/* BOLT #2:
*
* 1. `OP_DUP` `OP_HASH160` `20` 20-bytes `OP_EQUALVERIFY` `OP_CHECKSIG`
* (pay to pubkey hash), OR
* 2. `OP_HASH160` `20` 20-bytes `OP_EQUAL` (pay to script hash), OR
* 3. `OP_0` `20` 20-bytes (version 0 pay to witness pubkey), OR
* 4. `OP_0` `32` 32-bytes (version 0 pay to witness script hash)
*
* A receiving node:
*...
* - if the `scriptpubkey` is not in one of the above forms:
* - SHOULD fail the connection.
*/
if (!is_p2pkh(scriptpubkey, NULL) && !is_p2sh(scriptpubkey, NULL)
&& !is_p2wpkh(scriptpubkey, NULL) && !is_p2wsh(scriptpubkey, NULL)) {
channel_fail_permanent(channel,
REASON_PROTOCOL,
"Bad shutdown scriptpubkey %s",
tal_hex(channel, scriptpubkey));
return;
}
/* If we weren't already shutting down, we are now */
if (channel->state != CHANNELD_SHUTTING_DOWN)
channel_set_state(channel,
channel->state,
CHANNELD_SHUTTING_DOWN,
REASON_REMOTE,
"Peer closes channel");
/* TODO(cdecker) Selectively save updated fields to DB */
wallet_channel_save(ld->wallet, channel);
/* Now we send back our scriptpubkey to close with */
subd_send_msg(dualopend, take(towire_dualopend_send_shutdown(NULL,
channel->shutdown_scriptpubkey[LOCAL])));
}
static void handle_channel_closed(struct subd *dualopend,
const int *fds,
const u8 *msg)
{
struct per_peer_state *pps;
struct channel *channel;
if (!fromwire_dualopend_shutdown_complete(tmpctx, msg, &pps)) {
channel_internal_error(dualopend->channel,
"bad shutdown_complete: %s",
tal_hex(msg, msg));
close(fds[0]);
close(fds[1]);
close(fds[2]);
return;
}
per_peer_state_set_fds_arr(pps, fds);
assert(dualopend->ctype == CHANNEL);
channel = dualopend->channel;
peer_start_closingd(channel, pps, false, NULL);
channel_set_state(channel,
CHANNELD_SHUTTING_DOWN,
CLOSINGD_SIGEXCHANGE,
REASON_UNKNOWN,
"Start closingd");
}
static void opener_psbt_changed(struct subd *dualopend,
struct uncommitted_channel *uc,
const u8 *msg)
{
struct channel_id cid;
u64 funding_serial;
struct wally_psbt *psbt;
struct json_stream *response;
struct command *cmd = uc->fc->cmd;
if (!fromwire_dualopend_psbt_changed(cmd, msg,
&cid, &funding_serial,
&psbt)) {
log_broken(dualopend->log,
"Malformed dual_open_psbt_changed %s",
tal_hex(tmpctx, msg));
tal_free(dualopend);
return;
}
response = json_stream_success(cmd);
json_add_string(response, "channel_id",
type_to_string(tmpctx, struct channel_id, &cid));
json_add_psbt(response, "psbt", psbt);
json_add_bool(response, "commitments_secured", false);
json_add_u64(response, "funding_serial", funding_serial);
uc->cid = cid;
uc->fc->inflight = true;
uc->fc->cmd = NULL;
was_pending(command_success(cmd, response));
}
static void accepter_commit_received(struct subd *dualopend,
struct uncommitted_channel *uc,
const int *fds,
const u8 *msg)
{
struct openchannel2_psbt_payload *payload;
struct lightningd *ld = dualopend->ld;
struct channel_info channel_info;
struct bitcoin_tx *remote_commit;
struct bitcoin_signature remote_commit_sig;
struct channel_id cid;
struct bitcoin_txid funding_txid;
u16 funding_outnum;
u32 feerate;
struct amount_sat total_funding, funding_ours;
u8 channel_flags, *remote_upfront_shutdown_script,
*local_upfront_shutdown_script;
struct penalty_base *pbase;
struct wally_psbt *psbt;
payload = tal(dualopend, struct openchannel2_psbt_payload);
payload->rcvd = tal(payload, struct commit_rcvd);
/* This is a new channel_info.their_config so set its ID to 0 */
channel_info.their_config.id = 0;
if (!fromwire_dualopend_commit_rcvd(tmpctx, msg,
&channel_info.their_config,
&remote_commit,
&pbase,
&remote_commit_sig,
&psbt,
&cid,
&channel_info.theirbase.revocation,
&channel_info.theirbase.payment,
&channel_info.theirbase.htlc,
&channel_info.theirbase.delayed_payment,
&channel_info.remote_per_commit,
&channel_info.remote_fundingkey,
&funding_txid,
&funding_outnum,
&total_funding,
&funding_ours,
&channel_flags,
&feerate,
&uc->our_config.channel_reserve,
&local_upfront_shutdown_script,
&remote_upfront_shutdown_script)) {
log_broken(uc->log, "bad WIRE_DUALOPEND_COMMIT_RCVD %s",
tal_hex(msg, msg));
uncommitted_channel_disconnect(uc, LOG_BROKEN, "bad"
" WIRE_DUALOPEND_COMMIT_RCVD");
goto failed;
}
payload->dualopend = dualopend;
tal_add_destructor2(dualopend, openchannel2_psbt_remove_dualopend,
payload);
payload->psbt = tal_steal(payload, psbt);
payload->ld = ld;
if (peer_active_channel(uc->peer)) {
uncommitted_channel_disconnect(uc, LOG_BROKEN,
"already have active channel");
goto failed;
}
/* old_remote_per_commit not valid yet, copy valid one. */
channel_info.old_remote_per_commit = channel_info.remote_per_commit;
payload->rcvd->channel =
wallet_commit_channel(ld, uc,
&cid,
remote_commit,
&remote_commit_sig,
&funding_txid,
funding_outnum,
total_funding,
funding_ours,
channel_flags,
&channel_info,
feerate,
REMOTE,
local_upfront_shutdown_script,
remote_upfront_shutdown_script);
if (!payload->rcvd->channel) {
uncommitted_channel_disconnect(uc, LOG_BROKEN,
"commit channel failed");
goto failed;
}
if (pbase)
wallet_penalty_base_add(ld->wallet,
payload->rcvd->channel->dbid,
pbase);
subd_swap_channel(uc->open_daemon, payload->rcvd->channel, CHANNEL,
channel_errmsg, channel_set_billboard);
payload->rcvd->channel->owner = dualopend;
/* We don't have a command, so set to NULL here */
payload->rcvd->channel->openchannel_signed_cmd = NULL;
uc->open_daemon = NULL;
tal_free(uc);
/* We call out to our hook friend who will provide signatures for us! */
plugin_hook_call_openchannel2_sign(ld, payload);
return;
failed:
tal_free(uc);
}
static void opener_commit_received(struct subd *dualopend,
struct uncommitted_channel *uc,
const int *fds,
const u8 *msg)
{
struct lightningd *ld = dualopend->ld;
struct channel_info channel_info;
struct bitcoin_tx *remote_commit;
struct bitcoin_signature remote_commit_sig;
struct channel_id cid;
struct bitcoin_txid funding_txid;
struct json_stream *response;
u16 funding_outnum;
u32 feerate;
struct amount_sat total_funding, funding_ours;
u8 channel_flags, *remote_upfront_shutdown_script,
*unused_script;
struct penalty_base *pbase;
struct wally_psbt *psbt;
struct channel *channel;
char *err_reason;
/* This is a new channel_info.their_config so set its ID to 0 */
channel_info.their_config.id = 0;
if (!fromwire_dualopend_commit_rcvd(tmpctx, msg,
&channel_info.their_config,
&remote_commit,
&pbase,
&remote_commit_sig,
&psbt,
&cid,
&channel_info.theirbase.revocation,
&channel_info.theirbase.payment,
&channel_info.theirbase.htlc,
&channel_info.theirbase.delayed_payment,
&channel_info.remote_per_commit,
&channel_info.remote_fundingkey,
&funding_txid,
&funding_outnum,
&total_funding,
&funding_ours,
&channel_flags,
&feerate,
&uc->our_config.channel_reserve,
&unused_script,
&remote_upfront_shutdown_script)) {
log_broken(uc->log, "bad WIRE_DUALOPEND_COMMIT_RCVD %s",
tal_hex(msg, msg));
err_reason = "bad WIRE_DUALOPEND_COMMIT_RCVD";
uncommitted_channel_disconnect(uc, LOG_BROKEN, err_reason);
goto failed;
}
/* old_remote_per_commit not valid yet, copy valid one. */
channel_info.old_remote_per_commit = channel_info.remote_per_commit;
if (peer_active_channel(uc->peer)) {
err_reason = "already have active channel";
uncommitted_channel_disconnect(uc, LOG_BROKEN, err_reason);
goto failed;
}
/* Our end game is to save the channel to the database, and return the
* command with 'commitments_secured' set to true */
channel = wallet_commit_channel(ld, uc, &cid,
remote_commit,
&remote_commit_sig,
&funding_txid,
funding_outnum,
total_funding,
funding_ours,
channel_flags,
&channel_info,
feerate,
LOCAL,
uc->fc->our_upfront_shutdown_script,
remote_upfront_shutdown_script);
if (!channel) {
err_reason = "commit channel failed";
uncommitted_channel_disconnect(uc, LOG_BROKEN, err_reason);
goto failed;
}
if (pbase)
wallet_penalty_base_add(ld->wallet, channel->dbid, pbase);
response = json_stream_success(uc->fc->cmd);
json_add_string(response, "channel_id",
type_to_string(tmpctx, struct channel_id, &cid));
json_add_psbt(response, "psbt", psbt);
json_add_bool(response, "commitments_secured", true);
/* For convenience sake, we include the funding outnum */
json_add_num(response, "funding_outnum", funding_outnum);
if (uc->fc->our_upfront_shutdown_script)
json_add_hex_talarr(response, "close_to",
uc->fc->our_upfront_shutdown_script);
/* Now that we've got the final PSBT, save it */
channel->psbt = tal_steal(channel, psbt);
wallet_channel_save(uc->fc->cmd->ld->wallet, channel);
was_pending(command_success(uc->fc->cmd, response));
subd_swap_channel(uc->open_daemon, channel, CHANNEL,
channel_errmsg, channel_set_billboard);
channel->owner = dualopend;
goto cleanup;
failed:
was_pending(command_fail(uc->fc->cmd, LIGHTNINGD,
"%s", err_reason));
subd_release_channel(dualopend, uc);
cleanup:
uc->open_daemon = NULL;
tal_free(uc);
}
static void
opening_failed_cancel_commands(struct uncommitted_channel *uc,
const char *desc)
{
if (!uc->fc)
return;
/* FIXME: cancels? */
if (uc->fc->cmd)
was_pending(command_fail(uc->fc->cmd, LIGHTNINGD, "%s", desc));
uc->fc = tal_free(uc->fc);
}
static void open_failed(struct subd *dualopend, const u8 *msg)
{
char *desc;
struct uncommitted_channel *uc;
assert(dualopend->ctype == UNCOMMITTED);
uc = dualopend->channel;
uc->got_offer = false;
if (!fromwire_dualopend_failed(msg, msg, &desc)) {
log_broken(uc->log,
"Bad DUALOPEND_FAILED %s",
tal_hex(msg, msg));
if (uc->fc && uc->fc->cmd)
was_pending(command_fail(uc->fc->cmd, LIGHTNINGD, "%s",
tal_hex(uc->fc->cmd, msg)));
notify_channel_open_failed(dualopend->ld, &uc->cid);
tal_free(uc);
}
notify_channel_open_failed(dualopend->ld, &uc->cid);
opening_failed_cancel_commands(uc, desc);
}
struct channel_send {
const struct wally_tx *wtx;
struct channel *channel;
};
static void sendfunding_done(struct bitcoind *bitcoind UNUSED,
bool success, const char *msg,
struct channel_send *cs)
{
struct lightningd *ld = cs->channel->peer->ld;
struct channel *channel = cs->channel;
const struct wally_tx *wtx = cs->wtx;
struct json_stream *response;
struct bitcoin_txid txid;
struct amount_sat unused;
int num_utxos;
struct command *cmd = channel->openchannel_signed_cmd;
channel->openchannel_signed_cmd = NULL;
if (!cmd && channel->opener == LOCAL)
log_broken(channel->log,
"No outstanding command for channel %s,"
" funding sent was success? %d",
type_to_string(tmpctx, struct channel_id,
&channel->cid),
success);
if (!success) {
if (cmd)
was_pending(command_fail(cmd,
FUNDING_BROADCAST_FAIL,
"Error broadcasting funding "
"tx: %s. Unsent tx discarded "
"%s.",
msg,
type_to_string(tmpctx,
struct wally_tx,
wtx)));
log_unusual(channel->log,
"Error broadcasting funding "
"tx: %s. Unsent tx discarded "
"%s.",
msg,
type_to_string(tmpctx, struct wally_tx, wtx));
tal_free(cs);
return;
}
/* This might have spent UTXOs from our wallet */
num_utxos = wallet_extract_owned_outputs(ld->wallet,
wtx, NULL,
&unused);
if (num_utxos)
wallet_transaction_add(ld->wallet, wtx, 0, 0);
if (cmd) {
response = json_stream_success(cmd);
wally_txid(wtx, &txid);
json_add_hex_talarr(response, "tx", linearize_wtx(tmpctx, wtx));
json_add_txid(response, "txid", &txid);
json_add_string(response, "channel_id",
type_to_string(tmpctx, struct channel_id,
&channel->cid));
was_pending(command_success(cmd, response));
}
tal_free(cs);
}
static void send_funding_tx(struct channel *channel,
const struct wally_tx *wtx TAKES)
{
struct lightningd *ld = channel->peer->ld;
struct channel_send *cs;
cs = tal(channel, struct channel_send);
cs->channel = channel;
if (taken(wtx))
cs->wtx = tal_steal(cs, wtx);
else {
tal_wally_start();
wally_tx_clone_alloc(wtx, 0,
cast_const2(struct wally_tx **,
&cs->wtx));
tal_wally_end(tal_steal(cs, cs->wtx));
}
log_debug(channel->log,
"Broadcasting funding tx for channel %s. %s",
type_to_string(tmpctx, struct channel_id, &channel->cid),
type_to_string(tmpctx, struct wally_tx, cs->wtx));
bitcoind_sendrawtx(ld->topology->bitcoind,
tal_hex(tmpctx, linearize_wtx(tmpctx, cs->wtx)),
sendfunding_done, cs);
}
static void handle_peer_tx_sigs_sent(struct subd *dualopend,
const int *fds,
const u8 *msg)
{
struct channel *channel = dualopend->channel;
const struct wally_tx *wtx;
if (!fromwire_dualopend_tx_sigs_sent(msg)) {
channel_internal_error(channel,
"bad WIRE_DUALOPEND_TX_SIGS_SENT %s",
tal_hex(tmpctx, msg));
return;
}
if (psbt_finalize(cast_const(struct wally_psbt *, channel->psbt))) {
wtx = psbt_final_tx(NULL, channel->psbt);
if (!wtx) {
channel_internal_error(channel,
"Unable to extract final tx"
" from PSBT %s",
type_to_string(tmpctx,
struct wally_psbt,
channel->psbt));
return;
}
send_funding_tx(channel, take(wtx));
channel_set_state(channel, DUALOPEND_OPEN_INIT,
DUALOPEND_AWAITING_LOCKIN,
REASON_UNKNOWN,
"Sigs exchanged, waiting for lock-in");
/* Mimic the old behavior, notify a channel has been opened,
* for the accepter side */
if (channel->opener == REMOTE)
/* Tell plugins about the success */
notify_channel_opened(dualopend->ld,
&channel->peer->id,
&channel->funding,
&channel->funding_txid,
&channel->remote_funding_locked);
}
}
static void handle_peer_locked(struct subd *dualopend, const u8 *msg)
{
struct pubkey remote_per_commit;
struct channel *channel;
assert(dualopend->ctype == CHANNEL);
channel = dualopend->channel;
if (!fromwire_dualopend_peer_locked(msg, &remote_per_commit))
channel_internal_error(channel,
"bad WIRE_DUALOPEND_PEER_LOCKED %s",
tal_hex(msg, msg));
/* Updates channel with the next per-commit point etc */
if (!channel_on_funding_locked(channel, &remote_per_commit))
channel_internal_error(channel,
"Got funding_locked twice");
/* Remember that we got the lock-in */
wallet_channel_save(dualopend->ld->wallet, channel);
}
static void handle_channel_locked(struct subd *dualopend,
const int *fds,
const u8 *msg)
{
struct channel *channel = dualopend->channel;
struct per_peer_state *pps;
if (!fromwire_dualopend_channel_locked(tmpctx, msg, &pps)) {
log_broken(dualopend->log,
"bad WIRE_DUALOPEND_CHANNEL_LOCKED %s",
tal_hex(msg, msg));
close(fds[0]);
close(fds[1]);
close(fds[2]);
goto cleanup;
}
per_peer_state_set_fds_arr(pps, fds);
assert(channel->scid);
assert(channel->remote_funding_locked);
if (channel->state != DUALOPEND_AWAITING_LOCKIN) {
log_debug(channel->log, "Lockin complete, but state %s",
channel_state_name(channel));
} else {
channel_set_state(channel,
DUALOPEND_AWAITING_LOCKIN,
CHANNELD_NORMAL,
REASON_UNKNOWN,
"Lockin complete");
channel_record_open(channel);
}
/* FIXME: LND sigs/update_fee msgs? */
peer_start_channeld(channel, pps, NULL, false);
return;
cleanup:
subd_release_channel(dualopend, channel);
}
void dualopen_tell_depth(struct subd *dualopend,
struct channel *channel,
const struct bitcoin_txid *txid,
u32 depth)
{
const u8 *msg;
u32 to_go;
if (depth < channel->minimum_depth)
to_go = channel->minimum_depth - depth;
else
to_go = 0;
/* Are we there yet? */
if (to_go == 0) {
assert(channel->scid);
/* Update the channel's info to the correct tx, if we need to */
if (!bitcoin_txid_eq(&channel->funding_txid, txid)) {
struct channel_inflight *inf;
inf = channel_inflight_find(channel, txid);
if (!inf) {
channel_internal_error(channel,
"Txid %s for channel"
" not found in available inflights."
" (peer %s)",
type_to_string(tmpctx,
struct bitcoin_txid,
txid),
type_to_string(tmpctx,
struct node_id,
&channel->peer->id));
return;
}
channel->funding_txid = inf->funding->txid;
channel->funding_outnum = inf->funding->outnum;
channel->funding = inf->funding->total_funds;
channel->our_funds = inf->funding->our_funds;
channel->psbt = clone_psbt(channel, inf->funding_psbt);
channel->last_tx = tal_steal(channel, inf->last_tx);
channel->last_sig = inf->last_sig;
wallet_channel_save(dualopend->ld->wallet, channel);
/* FIXME: delete inflights */
}
msg = towire_dualopend_depth_reached(NULL, depth);
subd_send_msg(dualopend, take(msg));
} else
channel_set_billboard(channel, false,
tal_fmt(tmpctx, "Funding needs %d more"
" confirmations for lockin.",
to_go));
}
static void accepter_psbt_changed(struct subd *dualopend,
const u8 *msg)
{
u64 unused;
struct openchannel2_psbt_payload *payload =
tal(dualopend, struct openchannel2_psbt_payload);
payload->dualopend = dualopend;
payload->psbt = NULL;
payload->rcvd = tal(payload, struct commit_rcvd);
if (!fromwire_dualopend_psbt_changed(payload, msg,
&payload->rcvd->cid,
&unused,
&payload->psbt)) {
log_broken(dualopend->log, "Malformed dual_open_psbt_changed %s",
tal_hex(tmpctx, msg));
tal_free(dualopend);
return;
}
tal_add_destructor2(dualopend, openchannel2_psbt_remove_dualopend, payload);
plugin_hook_call_openchannel2_changed(dualopend->ld, payload);
}
static void accepter_got_offer(struct subd *dualopend,
struct uncommitted_channel *uc,
const u8 *msg)
{
struct openchannel2_payload *payload;
if (peer_active_channel(uc->peer)) {
subd_send_msg(dualopend,
take(towire_dualopend_fail(NULL,
"Already have active channel")));
return;
}
if (uc->fc) {
subd_send_msg(dualopend,
take(towire_dualopend_fail(NULL,
"Already initiated channel open")));
return;
}
payload = tal(dualopend, struct openchannel2_payload);
payload->dualopend = dualopend;
payload->psbt = NULL;
payload->accepter_funding = AMOUNT_SAT(0);
payload->our_shutdown_scriptpubkey = NULL;
payload->peer_id = uc->peer->id;
payload->err_msg = NULL;
if (!fromwire_dualopend_got_offer(payload, msg,
&payload->channel_id,
&payload->their_funding,
&payload->dust_limit_satoshis,
&payload->max_htlc_value_in_flight_msat,
&payload->htlc_minimum_msat,
&payload->funding_feerate_max,
&payload->funding_feerate_min,
&payload->funding_feerate_best,
&payload->commitment_feerate_per_kw,
&payload->to_self_delay,
&payload->max_accepted_htlcs,
&payload->channel_flags,
&payload->locktime,
&payload->shutdown_scriptpubkey)) {
log_broken(uc->log, "Malformed dual_open_got_offer %s",
tal_hex(tmpctx, msg));
tal_free(dualopend);
return;
}
/* As a convenience to the plugin, we provide our current known
* min + max feerates. Ideally, the plugin will fail to
* contribute funds if the peer's feerate range is outside of
* this acceptable range, but we delegate that decision to
* the plugin's logic */
payload->feerate_our_min = feerate_min(dualopend->ld, NULL);
payload->feerate_our_max = feerate_max(dualopend->ld, NULL);
/* Set the inital to feerate to zero, in case there is no plugin */
payload->funding_feerate_per_kw = 0;
tal_add_destructor2(dualopend, openchannel2_remove_dualopend, payload);
plugin_hook_call_openchannel2(dualopend->ld, payload);
}
static void handle_peer_tx_sigs_msg(struct subd *dualopend,
const u8 *msg)
{
struct wally_psbt *psbt;
const struct wally_tx *wtx;
struct lightningd *ld = dualopend->ld;
struct channel *channel = dualopend->channel;
if (!fromwire_dualopend_funding_sigs(tmpctx, msg, &psbt)) {
channel_internal_error(channel,
"bad dualopend_funding_sigs: %s",
tal_hex(tmpctx, msg));
return;
}
/* Save that we've gotten their sigs. Sometimes
* the peer doesn't send any sigs (no inputs), otherwise
* we could just check the PSBT was finalized */
channel->remote_tx_sigs = true;
tal_wally_start();
if (wally_psbt_combine(channel->psbt, psbt) != WALLY_OK) {
channel_internal_error(channel,
"Unable to combine PSBTs: %s, %s",
type_to_string(tmpctx,
struct wally_psbt,
channel->psbt),
type_to_string(tmpctx,
struct wally_psbt,
psbt));
tal_wally_end(channel->psbt);
return;
}
tal_wally_end(channel->psbt);
if (psbt_finalize(cast_const(struct wally_psbt *, channel->psbt))) {
wtx = psbt_final_tx(NULL, channel->psbt);
if (!wtx) {
channel_internal_error(channel,
"Unable to extract final tx"
" from PSBT %s",
type_to_string(tmpctx,
struct wally_psbt,
channel->psbt));
return;
}
send_funding_tx(channel, take(wtx));
channel_set_state(channel, DUALOPEND_OPEN_INIT,
DUALOPEND_AWAITING_LOCKIN,
REASON_UNKNOWN,
"Sigs exchanged, waiting for lock-in");
/* Mimic the old behavior, notify a channel has been opened,
* for the accepter side */
if (channel->opener == REMOTE)
/* Tell plugins about the success */
notify_channel_opened(dualopend->ld,
&channel->peer->id,
&channel->funding,
&channel->funding_txid,
&channel->remote_funding_locked);
}
wallet_channel_save(ld->wallet, channel);
/* Send notification with peer's signed PSBT */
notify_openchannel_peer_sigs(ld, &channel->cid,
channel->psbt);
}
static struct command_result *
json_openchannel_signed(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct wally_psbt *psbt;
struct uncommitted_channel *uc;
struct channel_id *cid;
struct channel *channel;
struct bitcoin_txid txid;
if (!param(cmd, buffer, params,
p_req("channel_id", param_channel_id, &cid),
p_req("signed_psbt", param_psbt, &psbt),
NULL))
return command_param_failed();
channel = channel_by_cid(cmd->ld, cid, &uc);
if (uc)
return command_fail(cmd, LIGHTNINGD,
"Commitments for this channel not "
"yet secured, see `openchannel_update`");
if (!channel)
return command_fail(cmd, FUNDING_UNKNOWN_CHANNEL,
"Unknown channel");
if (channel->psbt && psbt_is_finalized(channel->psbt))
return command_fail(cmd, LIGHTNINGD,
"Already have a finalized PSBT for "
"this channel");
if (channel->openchannel_signed_cmd)
return command_fail(cmd, LIGHTNINGD,
"Already sent sigs, waiting for"
" peer's");
/* Verify that the psbt's txid matches that of the
* funding txid for this channel */
psbt_txid(NULL, psbt, &txid, NULL);
if (!bitcoin_txid_eq(&txid, &channel->funding_txid))
return command_fail(cmd, FUNDING_PSBT_INVALID,
"Txid for passed in PSBT does not match"
" funding txid for channel. Expected %s, "
"received %s",
type_to_string(tmpctx, struct bitcoin_txid,
&channel->funding_txid),
type_to_string(tmpctx, struct bitcoin_txid,
&txid));
/* Go ahead and try to finalize things, or what we can */
psbt_finalize(psbt);
/* Check that all of *our* outputs are finalized */
if (!psbt_side_finalized(psbt, TX_INITIATOR))
return command_fail(cmd, FUNDING_PSBT_INVALID,
"Local PSBT input(s) not finalized");
/* Now that we've got the signed PSBT, save it */
tal_wally_start();
if (wally_psbt_combine(cast_const(struct wally_psbt *,
channel->psbt),
psbt) != WALLY_OK) {
tal_wally_end(tal_free(channel->psbt));
return command_fail(cmd, FUNDING_PSBT_INVALID,
"Failed adding sigs");
}
/* Make memleak happy, (otherwise cleaned up with `cmd`) */
tal_free(psbt);
tal_wally_end(tal_steal(channel, channel->psbt));
wallet_channel_save(cmd->ld->wallet, channel);
channel_watch_funding(cmd->ld, channel);
/* Send our tx_sigs to the peer */
subd_send_msg(channel->owner,
take(towire_dualopend_send_tx_sigs(NULL, channel->psbt)));
channel->openchannel_signed_cmd = tal_steal(channel, cmd);
return command_still_pending(cmd);
}
static struct command_result *json_openchannel_update(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct wally_psbt *psbt;
struct channel_id *cid;
struct channel *channel;
struct uncommitted_channel *uc;
u8 *msg;
if (!param(cmd, buffer, params,
p_req("channel_id", param_channel_id, &cid),
p_req("psbt", param_psbt, &psbt),
NULL))
return command_param_failed();
/* We expect this to return NULL, as the channel hasn't been
* created yet. Instead, the uncommitted channel is populated */
channel = channel_by_cid(cmd->ld, cid, &uc);
if (channel)
return command_fail(cmd, LIGHTNINGD, "Channel already %s",
channel_state_name(channel));
if (!uc)
return command_fail(cmd, FUNDING_UNKNOWN_CHANNEL,
"Unknown channel %s",
type_to_string(tmpctx, struct channel_id,
cid));
if (!uc->fc || !uc->fc->inflight)
return command_fail(cmd, LIGHTNINGD,
"No channel funding in progress");
if (uc->fc->cmd)
return command_fail(cmd, LIGHTNINGD,
"Channel funding in progress");
/* Add serials to PSBT */
psbt_add_serials(psbt, TX_INITIATOR);
if (!psbt_has_required_fields(psbt))
return command_fail(cmd, FUNDING_PSBT_INVALID,
"PSBT is missing required fields %s",
type_to_string(tmpctx, struct wally_psbt,
psbt));
uc->fc->cmd = cmd;
msg = towire_dualopend_psbt_updated(NULL, psbt);
subd_send_msg(uc->open_daemon, take(msg));
return command_still_pending(cmd);
}
static struct command_result *json_openchannel_init(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct funding_channel *fc = tal(cmd, struct funding_channel);
struct node_id *id;
struct peer *peer;
struct channel *channel;
bool *announce_channel;
u32 *feerate_per_kw_funding;
u32 *feerate_per_kw;
struct amount_sat *amount, psbt_val;
struct wally_psbt *psbt;
u8 *msg = NULL;
fc->cmd = cmd;
fc->cancels = tal_arr(fc, struct command *, 0);
fc->uc = NULL;
fc->inflight = false;
if (!param(fc->cmd, buffer, params,
p_req("id", param_node_id, &id),
p_req("amount", param_sat, &amount),
p_req("initialpsbt", param_psbt, &psbt),
p_opt("commitment_feerate", param_feerate, &feerate_per_kw),
p_opt("funding_feerate", param_feerate, &feerate_per_kw_funding),
p_opt_def("announce", param_bool, &announce_channel, true),
p_opt("close_to", param_bitcoin_address, &fc->our_upfront_shutdown_script),
NULL))
return command_param_failed();
psbt_val = AMOUNT_SAT(0);
for (size_t i = 0; i < psbt->num_inputs; i++) {
struct amount_sat in_amt = psbt_input_get_amount(psbt, i);
if (!amount_sat_add(&psbt_val, psbt_val, in_amt))
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Overflow in adding PSBT input"
" values. %s",
type_to_string(tmpctx,
struct wally_psbt,
psbt));
}
/* If they don't pass in at least enough in the PSBT to cover
* their amount, nope */
if (!amount_sat_greater(psbt_val, *amount))
return command_fail(cmd, FUND_CANNOT_AFFORD,
"Provided PSBT cannot afford funding of "
"amount %s. %s",
type_to_string(tmpctx,
struct amount_sat,
amount),
type_to_string(tmpctx,
struct wally_psbt,
psbt));
fc->funding = *amount;
if (!feerate_per_kw_funding) {
feerate_per_kw_funding = tal(cmd, u32);
*feerate_per_kw_funding = opening_feerate(cmd->ld->topology);
if (!*feerate_per_kw_funding)
return command_fail(cmd, LIGHTNINGD,
"`funding_feerate` not specified and fee "
"estimation failed");
}
if (!feerate_per_kw) {
feerate_per_kw = tal(cmd, u32);
/* FIXME: Anchors are on by default, we should use the lowest
* possible feerate */
*feerate_per_kw = *feerate_per_kw_funding;
}
if (!topology_synced(cmd->ld->topology)) {
return command_fail(cmd, FUNDING_STILL_SYNCING_BITCOIN,
"Still syncing with bitcoin network");
}
peer = peer_by_id(cmd->ld, id);
if (!peer) {
return command_fail(cmd, FUNDING_UNKNOWN_PEER, "Unknown peer");
}
channel = peer_active_channel(peer);
if (channel) {
return command_fail(cmd, LIGHTNINGD, "Peer already %s",
channel_state_name(channel));
}
if (!peer->uncommitted_channel) {
return command_fail(cmd, FUNDING_PEER_NOT_CONNECTED,
"Peer not connected");
}
if (peer->uncommitted_channel->fc) {
return command_fail(cmd, LIGHTNINGD, "Already funding channel");
}
if (peer->uncommitted_channel->got_offer) {
return command_fail(cmd, LIGHTNINGD,
"Channel open in progress");
}
#if EXPERIMENTAL_FEATURES
if (!feature_negotiated(cmd->ld->our_features,
peer->their_features,
OPT_DUAL_FUND)) {
return command_fail(cmd, FUNDING_V2_NOT_SUPPORTED,
"v2 openchannel not supported "
"by peer");
}
#endif /* EXPERIMENTAL_FEATURES */
/* BOLT #2:
* - if both nodes advertised `option_support_large_channel`:
* - MAY set `funding_satoshis` greater than or equal to 2^24 satoshi.
* - otherwise:
* - MUST set `funding_satoshis` to less than 2^24 satoshi.
*/
if (!feature_negotiated(cmd->ld->our_features,
peer->their_features, OPT_LARGE_CHANNELS)
&& amount_sat_greater(*amount, chainparams->max_funding))
return command_fail(cmd, FUND_MAX_EXCEEDED,
"Amount exceeded %s",
type_to_string(tmpctx, struct amount_sat,
&chainparams->max_funding));
fc->channel_flags = OUR_CHANNEL_FLAGS;
if (!*announce_channel) {
fc->channel_flags &= ~CHANNEL_FLAGS_ANNOUNCE_CHANNEL;
log_info(peer->ld->log, "Will open private channel with node %s",
type_to_string(fc, struct node_id, id));
}
/* Add serials to any input that's missing them */
psbt_add_serials(psbt, TX_INITIATOR);
if (!psbt_has_required_fields(psbt))
return command_fail(cmd, FUNDING_PSBT_INVALID,
"PSBT is missing required fields %s",
type_to_string(tmpctx, struct wally_psbt,
psbt));
peer->uncommitted_channel->fc = tal_steal(peer->uncommitted_channel, fc);
fc->uc = peer->uncommitted_channel;
/* Needs to be stolen away from cmd */
if (fc->our_upfront_shutdown_script)
fc->our_upfront_shutdown_script
= tal_steal(fc, fc->our_upfront_shutdown_script);
msg = towire_dualopend_opener_init(NULL,
psbt, *amount,
fc->our_upfront_shutdown_script,
*feerate_per_kw,
*feerate_per_kw_funding,
fc->channel_flags);
subd_send_msg(peer->uncommitted_channel->open_daemon, take(msg));
return command_still_pending(cmd);
}
static void
channel_fail_fallen_behind(struct subd* dualopend, const u8 *msg)
{
struct channel *channel;
assert(dualopend->ctype == CHANNEL);
channel = dualopend->channel;
if (!fromwire_dualopend_fail_fallen_behind(msg)) {
channel_internal_error(channel,
"bad dualopen_fail_fallen_behind %s",
tal_hex(tmpctx, msg));
return;
}
channel_fallen_behind(channel, msg);
}
static unsigned int dual_opend_msg(struct subd *dualopend,
const u8 *msg, const int *fds)
{
enum dualopend_wire t = fromwire_peektype(msg);
/* FIXME: might be channel? */
struct uncommitted_channel *uc = dualopend->channel;
switch (t) {
case WIRE_DUALOPEND_GOT_OFFER:
accepter_got_offer(dualopend, uc, msg);
return 0;
case WIRE_DUALOPEND_PSBT_CHANGED:
if (uc->fc) {
if (!uc->fc->cmd) {
log_unusual(dualopend->log,
"Unexpected PSBT_CHANGED %s",
tal_hex(tmpctx, msg));
tal_free(dualopend);
return 0;
}
opener_psbt_changed(dualopend, uc, msg);
} else
accepter_psbt_changed(dualopend, msg);
return 0;
case WIRE_DUALOPEND_COMMIT_RCVD:
if (uc->fc) {
if (!uc->fc->cmd) {
log_unusual(dualopend->log,
"Unexpected COMMIT_RCVD %s",
tal_hex(tmpctx, msg));
tal_free(dualopend);
return 0;
}
opener_commit_received(dualopend,
uc, fds, msg);
} else
accepter_commit_received(dualopend,
uc, fds, msg);
return 0;
case WIRE_DUALOPEND_FUNDING_SIGS:
handle_peer_tx_sigs_msg(dualopend, msg);
return 0;
case WIRE_DUALOPEND_TX_SIGS_SENT:
handle_peer_tx_sigs_sent(dualopend, fds, msg);
return 0;
case WIRE_DUALOPEND_PEER_LOCKED:
handle_peer_locked(dualopend, msg);
return 0;
case WIRE_DUALOPEND_CHANNEL_LOCKED:
if (tal_count(fds) != 3)
return 3;
handle_channel_locked(dualopend, fds, msg);
return 0;
case WIRE_DUALOPEND_GOT_SHUTDOWN:
handle_peer_wants_to_close(dualopend, msg);
return 0;
case WIRE_DUALOPEND_SHUTDOWN_COMPLETE:
if (tal_count(fds) != 3)
return 3;
handle_channel_closed(dualopend, fds, msg);
return 0;
case WIRE_DUALOPEND_FAIL_FALLEN_BEHIND:
channel_fail_fallen_behind(dualopend, msg);
return 0;
case WIRE_DUALOPEND_FAILED:
open_failed(dualopend, msg);
return 0;
case WIRE_DUALOPEND_DEV_MEMLEAK_REPLY:
/* Messages we send */
case WIRE_DUALOPEND_INIT:
case WIRE_DUALOPEND_REINIT:
case WIRE_DUALOPEND_OPENER_INIT:
case WIRE_DUALOPEND_GOT_OFFER_REPLY:
case WIRE_DUALOPEND_FAIL:
case WIRE_DUALOPEND_PSBT_UPDATED:
case WIRE_DUALOPEND_SEND_TX_SIGS:
case WIRE_DUALOPEND_SEND_SHUTDOWN:
case WIRE_DUALOPEND_DEPTH_REACHED:
case WIRE_DUALOPEND_DEV_MEMLEAK:
break;
}
switch ((enum common_wire)t) {
#if DEVELOPER
case WIRE_CUSTOMMSG_IN:
handle_custommsg_in(dualopend->ld, dualopend->node_id, msg);
return 0;
#else
case WIRE_CUSTOMMSG_IN:
#endif
/* We send these. */
case WIRE_CUSTOMMSG_OUT:
break;
}
log_broken(dualopend->log, "Unexpected msg %s: %s",
dualopend_wire_name(t), tal_hex(tmpctx, msg));
tal_free(dualopend);
return 0;
}
static const struct json_command openchannel_init_command = {
"openchannel_init",
"channels",
json_openchannel_init,
"Init an open channel to {id} with {initialpsbt} for {amount} satoshis. "
"Returns updated {psbt} with (partial) contributions from peer"
};
static const struct json_command openchannel_update_command = {
"openchannel_update",
"channels",
json_openchannel_update,
"Update {channel_id} with {psbt}. "
"Returns updated {psbt} with (partial) contributions from peer. "
"If {commitments_secured} is true, next call should be to openchannel_signed"
};
static const struct json_command openchannel_signed_command = {
"openchannel_signed",
"channels",
json_openchannel_signed,
"Send our {signed_psbt}'s tx sigs for {channel_id}."
};
#if EXPERIMENTAL_FEATURES
AUTODATA(json_command, &openchannel_init_command);
AUTODATA(json_command, &openchannel_update_command);
AUTODATA(json_command, &openchannel_signed_command);
#endif /* EXPERIMENTAL_FEATURES */
void peer_restart_dualopend(struct peer *peer,
struct per_peer_state *pps,
struct channel *channel,
const u8 *send_msg)
{
u32 max_to_self_delay;
struct amount_msat min_effective_htlc_capacity;
struct channel_config unused_config;
int hsmfd;
u8 *msg;
hsmfd = hsm_get_client_fd(peer->ld, &peer->id, channel->dbid,
HSM_CAP_COMMITMENT_POINT
| HSM_CAP_SIGN_REMOTE_TX);
channel_set_owner(channel,
new_channel_subd(peer->ld, "lightning_dualopend",
channel, CHANNEL,
&peer->id,
channel->log, true,
dualopend_wire_name,
dual_opend_msg,
channel_errmsg,
channel_set_billboard,
take(&pps->peer_fd),
take(&pps->gossip_fd),
take(&pps->gossip_store_fd),
take(&hsmfd), NULL));
if (!channel->owner) {
log_broken(channel->log, "Could not subdaemon channel: %s",
strerror(errno));
channel_fail_reconnect_later(channel,
"Failed to subdaemon channel");
return;
}
/* Find the max self delay and min htlc capacity */
channel_config(peer->ld, &unused_config,
&max_to_self_delay,
&min_effective_htlc_capacity);
msg = towire_dualopend_reinit(NULL,
chainparams,
peer->ld->our_features,
peer->their_features,
&channel->our_config,
&channel->channel_info.their_config,
&channel->cid,
max_to_self_delay,
min_effective_htlc_capacity,
pps,
&channel->local_basepoints,
&channel->local_funding_pubkey,
&channel->channel_info.remote_fundingkey,
channel->minimum_depth,
feerate_min(peer->ld, NULL),
feerate_max(peer->ld, NULL),
&channel->funding_txid,
channel->funding_outnum,
channel->funding,
channel->our_msat,
&channel->channel_info.theirbase,
&channel->channel_info.remote_per_commit,
channel->psbt,
channel->opener,
channel->scid != NULL,
channel->remote_funding_locked,
channel->state == CHANNELD_SHUTTING_DOWN,
channel->shutdown_scriptpubkey[REMOTE] != NULL,
channel->shutdown_scriptpubkey[LOCAL],
channel->remote_upfront_shutdown_script,
channel->remote_tx_sigs,
channel->fee_states,
send_msg);
subd_send_msg(channel->owner, take(msg));
}
void peer_start_dualopend(struct peer *peer,
struct per_peer_state *pps,
const u8 *send_msg)
{
int hsmfd;
u32 max_to_self_delay;
struct amount_msat min_effective_htlc_capacity;
struct uncommitted_channel *uc;
const u8 *msg;
assert(!peer->uncommitted_channel);
uc = peer->uncommitted_channel = new_uncommitted_channel(peer);
hsmfd = hsm_get_client_fd(peer->ld, &peer->id, uc->dbid,
HSM_CAP_COMMITMENT_POINT
| HSM_CAP_SIGN_REMOTE_TX);
uc->open_daemon = new_channel_subd(peer->ld,
"lightning_dualopend",
uc, UNCOMMITTED, &peer->id,
uc->log, true,
dualopend_wire_name,
dual_opend_msg,
opend_channel_errmsg,
opend_channel_set_billboard,
take(&pps->peer_fd),
take(&pps->gossip_fd),
take(&pps->gossip_store_fd),
take(&hsmfd), NULL);
if (!uc->open_daemon) {
char *errmsg;
errmsg = tal_fmt(tmpctx,
"Running lightning_dualopend: %s",
strerror(errno));
uncommitted_channel_disconnect(uc, LOG_BROKEN, errmsg);
tal_free(uc);
return;
}
channel_config(peer->ld, &uc->our_config,
&max_to_self_delay,
&min_effective_htlc_capacity);
/* BOLT #2:
*
* The sender:
* - SHOULD set `minimum_depth` to a number of blocks it
* considers reasonable to avoid double-spending of the
* funding transaction.
*/
uc->minimum_depth = peer->ld->config.anchor_confirms;
msg = towire_dualopend_init(NULL, chainparams,
peer->ld->our_features,
peer->their_features,
&uc->our_config,
max_to_self_delay,
min_effective_htlc_capacity,
pps, &uc->local_basepoints,
&uc->local_funding_pubkey,
uc->minimum_depth,
feerate_min(peer->ld, NULL),
feerate_max(peer->ld, NULL),
send_msg);
subd_send_msg(uc->open_daemon, take(msg));
}