mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-06 05:49:30 +01:00
8f33f46960
We were actually using the last commit tx's size, since we were setting it in lightningd. Instead, hand the min and desired feerates to closingd, and (as it knows the weight of the closing tx), and have it start negotiation from there. This can be significantly less when anchor outputs are enabled: for example in test_closing.py, the commit tx weight is 1124 Sipa, the close is 672 Sipa! Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Changelog-Changed: Protocol: Use a more accurate fee for mutual close negotiation.
309 lines
8.9 KiB
C
309 lines
8.9 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, &min_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_msat their_msat;
|
|
struct amount_sat feelimit;
|
|
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);
|
|
|
|
/* 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();
|
|
}
|
|
|
|
/* 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,
|
|
feerate_min(ld, NULL), feerate, feelimit,
|
|
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)));
|
|
}
|