mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-12-29 10:04:41 +01:00
ca0358f978
This lets us transition (with a few supporting changes) to closingd, which will happily let them mutual close with us. We already handle the case where this mutual close is redundant (for packet loss), so this is easy. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Changelog-Added: Protocol: We will now reestablish and negotiate mutual close on channels we've already closed (great if peer has lost their database).
320 lines
9.3 KiB
C
320 lines
9.3 KiB
C
#include <bitcoin/feerate.h>
|
|
#include <bitcoin/script.h>
|
|
#include <closingd/closingd_wiregen.h>
|
|
#include <common/close_tx.h>
|
|
#include <common/fee_states.h>
|
|
#include <common/initial_commit_tx.h>
|
|
#include <common/per_peer_state.h>
|
|
#include <common/utils.h>
|
|
#include <errno.h>
|
|
#include <gossipd/gossipd_wiregen.h>
|
|
#include <inttypes.h>
|
|
#include <lightningd/bitcoind.h>
|
|
#include <lightningd/chaintopology.h>
|
|
#include <lightningd/channel.h>
|
|
#include <lightningd/closing_control.h>
|
|
#include <lightningd/hsm_control.h>
|
|
#include <lightningd/lightningd.h>
|
|
#include <lightningd/log.h>
|
|
#include <lightningd/options.h>
|
|
#include <lightningd/peer_control.h>
|
|
#include <lightningd/subd.h>
|
|
#include <wire/common_wiregen.h>
|
|
|
|
static struct amount_sat calc_tx_fee(struct amount_sat sat_in,
|
|
const struct bitcoin_tx *tx)
|
|
{
|
|
struct amount_asset amt;
|
|
struct amount_sat fee = sat_in;
|
|
const u8 *oscript;
|
|
size_t scriptlen;
|
|
for (size_t i = 0; i < tx->wtx->num_outputs; i++) {
|
|
amt = bitcoin_tx_output_get_amount(tx, i);
|
|
oscript = bitcoin_tx_output_get_script(NULL, tx, i);
|
|
scriptlen = tal_bytelen(oscript);
|
|
tal_free(oscript);
|
|
|
|
if (chainparams->is_elements && scriptlen == 0)
|
|
continue;
|
|
|
|
/* Ignore outputs that are not denominated in our main
|
|
* currency. */
|
|
if (!amount_asset_is_main(&amt))
|
|
continue;
|
|
|
|
if (!amount_sat_sub(&fee, fee, amount_asset_to_sat(&amt)))
|
|
fatal("Tx spends more than input %s? %s",
|
|
type_to_string(tmpctx, struct amount_sat, &sat_in),
|
|
type_to_string(tmpctx, struct bitcoin_tx, tx));
|
|
}
|
|
return fee;
|
|
}
|
|
|
|
/* Assess whether a proposed closing fee is acceptable. */
|
|
static bool closing_fee_is_acceptable(struct lightningd *ld,
|
|
struct channel *channel,
|
|
const struct bitcoin_tx *tx)
|
|
{
|
|
struct amount_sat fee, last_fee, min_fee;
|
|
u64 weight;
|
|
u32 min_feerate;
|
|
bool feerate_unknown;
|
|
|
|
/* Calculate actual fee (adds in eliminated outputs) */
|
|
fee = calc_tx_fee(channel->funding, tx);
|
|
last_fee = calc_tx_fee(channel->funding, channel->last_tx);
|
|
|
|
log_debug(channel->log, "Their actual closing tx fee is %s"
|
|
" vs previous %s",
|
|
type_to_string(tmpctx, struct amount_sat, &fee),
|
|
type_to_string(tmpctx, struct amount_sat, &last_fee));
|
|
|
|
/* Weight once we add in sigs. */
|
|
weight = bitcoin_tx_weight(tx) + bitcoin_tx_input_sig_weight() * 2;
|
|
|
|
/* If we don't have a feerate estimate, this gives feerate_floor */
|
|
min_feerate = feerate_min(ld, &feerate_unknown);
|
|
|
|
min_fee = amount_tx_fee(min_feerate, weight);
|
|
if (amount_sat_less(fee, min_fee)) {
|
|
log_debug(channel->log, "... That's below our min %s"
|
|
" for weight %"PRIu64" at feerate %u",
|
|
type_to_string(tmpctx, struct amount_sat, &fee),
|
|
weight, min_feerate);
|
|
return false;
|
|
}
|
|
|
|
/* Prefer new over old: this covers the preference
|
|
* for a mutual close over a unilateral one. */
|
|
|
|
return true;
|
|
}
|
|
|
|
static void peer_received_closing_signature(struct channel *channel,
|
|
const u8 *msg)
|
|
{
|
|
struct bitcoin_signature sig;
|
|
struct bitcoin_tx *tx;
|
|
struct bitcoin_txid tx_id;
|
|
struct lightningd *ld = channel->peer->ld;
|
|
u8 *funding_wscript;
|
|
|
|
if (!fromwire_closingd_received_signature(msg, msg, &sig, &tx)) {
|
|
channel_internal_error(channel,
|
|
"Bad closing_received_signature %s",
|
|
tal_hex(msg, msg));
|
|
return;
|
|
}
|
|
tx->chainparams = chainparams;
|
|
|
|
funding_wscript = bitcoin_redeem_2of2(tmpctx,
|
|
&channel->local_funding_pubkey,
|
|
&channel->channel_info.remote_fundingkey);
|
|
if (!check_tx_sig(tx, 0, NULL, funding_wscript,
|
|
&channel->channel_info.remote_fundingkey, &sig)) {
|
|
channel_internal_error(channel,
|
|
"Bad closing_received_signature %s",
|
|
tal_hex(msg, msg));
|
|
return;
|
|
}
|
|
|
|
if (closing_fee_is_acceptable(ld, channel, tx)) {
|
|
channel_set_last_tx(channel, tx, &sig, TX_CHANNEL_CLOSE);
|
|
wallet_channel_save(ld->wallet, channel);
|
|
}
|
|
|
|
|
|
// Send back the txid so we can update the billboard on selection.
|
|
bitcoin_txid(channel->last_tx, &tx_id);
|
|
/* OK, you can continue now. */
|
|
subd_send_msg(channel->owner,
|
|
take(towire_closingd_received_signature_reply(channel, &tx_id)));
|
|
}
|
|
|
|
static void peer_closing_complete(struct channel *channel, const u8 *msg)
|
|
{
|
|
if (!fromwire_closingd_complete(msg)) {
|
|
channel_internal_error(channel, "Bad closing_complete %s",
|
|
tal_hex(msg, msg));
|
|
return;
|
|
}
|
|
|
|
/* Don't report spurious failure when closingd exits. */
|
|
channel_set_owner(channel, NULL);
|
|
/* Clear any transient negotiation messages */
|
|
channel_set_billboard(channel, false, NULL);
|
|
|
|
/* Retransmission only, ignore closing. */
|
|
if (channel_closed(channel))
|
|
return;
|
|
|
|
/* Channel gets dropped to chain cooperatively. */
|
|
drop_to_chain(channel->peer->ld, channel, true);
|
|
channel_set_state(channel,
|
|
CLOSINGD_SIGEXCHANGE,
|
|
CLOSINGD_COMPLETE,
|
|
REASON_UNKNOWN,
|
|
"Closing complete");
|
|
}
|
|
|
|
static unsigned closing_msg(struct subd *sd, const u8 *msg, const int *fds UNUSED)
|
|
{
|
|
enum closingd_wire t = fromwire_peektype(msg);
|
|
|
|
switch (t) {
|
|
case WIRE_CLOSINGD_RECEIVED_SIGNATURE:
|
|
peer_received_closing_signature(sd->channel, msg);
|
|
break;
|
|
|
|
case WIRE_CLOSINGD_COMPLETE:
|
|
peer_closing_complete(sd->channel, msg);
|
|
break;
|
|
|
|
/* We send these, not receive them */
|
|
case WIRE_CLOSINGD_INIT:
|
|
case WIRE_CLOSINGD_RECEIVED_SIGNATURE_REPLY:
|
|
break;
|
|
}
|
|
|
|
switch ((enum common_wire)t) {
|
|
#if DEVELOPER
|
|
case WIRE_CUSTOMMSG_IN:
|
|
handle_custommsg_in(sd->ld, sd->node_id, msg);
|
|
break;
|
|
#else
|
|
case WIRE_CUSTOMMSG_IN:
|
|
#endif
|
|
/* We send these. */
|
|
case WIRE_CUSTOMMSG_OUT:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void peer_start_closingd(struct channel *channel,
|
|
struct per_peer_state *pps)
|
|
{
|
|
u8 *initmsg;
|
|
u32 feerate;
|
|
struct amount_sat minfee, startfee, feelimit;
|
|
struct amount_msat their_msat;
|
|
int hsmfd;
|
|
struct lightningd *ld = channel->peer->ld;
|
|
u32 final_commit_feerate;
|
|
|
|
if (!channel->shutdown_scriptpubkey[REMOTE]) {
|
|
channel_internal_error(channel,
|
|
"Can't start closing: no remote info");
|
|
return;
|
|
}
|
|
|
|
hsmfd = hsm_get_client_fd(ld, &channel->peer->id, channel->dbid,
|
|
HSM_CAP_SIGN_CLOSING_TX
|
|
| HSM_CAP_COMMITMENT_POINT);
|
|
|
|
channel_set_owner(channel,
|
|
new_channel_subd(ld,
|
|
"lightning_closingd",
|
|
channel, &channel->peer->id,
|
|
channel->log, true,
|
|
closingd_wire_name, closing_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 closing: %s",
|
|
strerror(errno));
|
|
channel_fail_reconnect_later(channel,
|
|
"Failed to subdaemon closing");
|
|
return;
|
|
}
|
|
|
|
/* BOLT #2:
|
|
*
|
|
* The sending node:
|
|
* - MUST set `fee_satoshis` less than or equal to the base
|
|
* fee of the final commitment transaction, as calculated in
|
|
* [BOLT #3](03-transactions.md#fee-calculation).
|
|
*/
|
|
final_commit_feerate = get_feerate(channel->fee_states,
|
|
channel->opener, LOCAL);
|
|
feelimit = commit_tx_base_fee(final_commit_feerate, 0,
|
|
channel->option_anchor_outputs);
|
|
|
|
/* Pick some value above slow feerate (or min possible if unknown) */
|
|
minfee = commit_tx_base_fee(feerate_min(ld, NULL), 0,
|
|
channel->option_anchor_outputs);
|
|
|
|
/* If we can't determine feerate, start at half unilateral feerate. */
|
|
feerate = mutual_close_feerate(ld->topology);
|
|
if (!feerate) {
|
|
feerate = final_commit_feerate / 2;
|
|
if (feerate < feerate_floor())
|
|
feerate = feerate_floor();
|
|
}
|
|
startfee = commit_tx_base_fee(feerate, 0,
|
|
channel->option_anchor_outputs);
|
|
|
|
if (amount_sat_greater(startfee, feelimit))
|
|
startfee = feelimit;
|
|
if (amount_sat_greater(minfee, feelimit))
|
|
minfee = feelimit;
|
|
|
|
/* BOLT #3:
|
|
*
|
|
* Each node offering a signature:
|
|
* - MUST round each output down to whole satoshis.
|
|
*/
|
|
/* What is not ours is theirs */
|
|
if (!amount_sat_sub_msat(&their_msat,
|
|
channel->funding, channel->our_msat)) {
|
|
log_broken(channel->log, "our_msat overflow funding %s minus %s",
|
|
type_to_string(tmpctx, struct amount_sat,
|
|
&channel->funding),
|
|
type_to_string(tmpctx, struct amount_msat,
|
|
&channel->our_msat));
|
|
channel_fail_permanent(channel,
|
|
REASON_LOCAL,
|
|
"our_msat overflow on closing");
|
|
return;
|
|
}
|
|
|
|
initmsg = towire_closingd_init(tmpctx,
|
|
chainparams,
|
|
pps,
|
|
&channel->cid,
|
|
&channel->funding_txid,
|
|
channel->funding_outnum,
|
|
channel->funding,
|
|
&channel->local_funding_pubkey,
|
|
&channel->channel_info.remote_fundingkey,
|
|
channel->opener,
|
|
amount_msat_to_sat_round_down(channel->our_msat),
|
|
amount_msat_to_sat_round_down(their_msat),
|
|
channel->our_config.dust_limit,
|
|
minfee, feelimit, startfee,
|
|
channel->shutdown_scriptpubkey[LOCAL],
|
|
channel->shutdown_scriptpubkey[REMOTE],
|
|
channel->closing_fee_negotiation_step,
|
|
channel->closing_fee_negotiation_step_unit,
|
|
IFDEV(ld->dev_fast_gossip, false),
|
|
channel->shutdown_wrong_funding);
|
|
|
|
/* We don't expect a response: it will give us feedback on
|
|
* signatures sent and received, then closing_complete. */
|
|
subd_send_msg(channel->owner, take(initmsg));
|
|
|
|
/* Now tell gossipd that we're closing and that neither direction should
|
|
* be used. */
|
|
if (channel->scid)
|
|
subd_send_msg(channel->peer->ld->gossip,
|
|
take(towire_gossipd_local_channel_close(
|
|
tmpctx, channel->scid)));
|
|
}
|