Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anchors not experimental #6785

Merged
23 changes: 21 additions & 2 deletions contrib/pyln-testing/pyln/testing/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -939,10 +939,10 @@ def fundbalancedchannel(self, remote_node, total_capacity=FUNDAMOUNT, announce=T
else:
total_capacity = int(total_capacity)

self.fundwallet(total_capacity + 10000)
self.fundwallet(total_capacity + 35000)

if remote_node.config('experimental-dual-fund'):
remote_node.fundwallet(total_capacity + 10000)
remote_node.fundwallet(total_capacity + 35000)
# We cut the total_capacity in half, since the peer's
# expected to contribute that same amount
chan_capacity = total_capacity // 2
Expand Down Expand Up @@ -1274,6 +1274,25 @@ def mock_estimatesmartfee(r):
}
self.daemon.rpcproxy.mock_rpc('estimatesmartfee', mock_estimatesmartfee)

def mock_getmempoolinfo(r):
return {
'id': r['id'],
'error': None,
'result': {
'mempoolminfee': Decimal(feerates[4] * 4) / 10**8,
'minrelaytxfee': Decimal(feerates[4] * 4) / 10**8,
},
}

# Did they want to set minfee as well?
if len(feerates) > 4:
assert len(feerates) == 5
self.daemon.rpcproxy.mock_rpc('getmempoolinfo', mock_getmempoolinfo)

if wait_for_effect:
wait_for(lambda:
self.rpc.feerates(style='perkb')['perkb']['floor'] == feerates[4] * 4)

# Technically, this waits until it's called, not until it's processed.
# We wait until all four levels have been called.
if wait_for_effect:
Expand Down
10 changes: 0 additions & 10 deletions doc/lightningd-config.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,6 @@ specified multuple times. (Added in v23.08).
* **min-emergency-msat**=*msat*

This is the amount of funds to keep in the wallet to close anchor channels (which don't carry their own transaction fees). It defaults to 25000sat, and is only maintained if there are any anchor channels (or, when opening an anchor channel). This amount may be insufficient for multiple closes at once, however.


### Cleanup control options:

Expand Down Expand Up @@ -793,15 +792,6 @@ protocol to update channel types. At the moment, we only support setting
this option.


* **experimental-anchors**

Specifying this option turns on the `option_anchors_zero_fee_htlc_tx`
feature, meaning we can open anchor-based channels. This will become
the default for new channels in future, after more testing. Anchor-based
channels use larger commitment transactions, with the trade-off that they
don't have to use a worst-case fee, but can bump the commitment transaction
if it's needed. Note that this means that we need to keep
some funds aside: see `min-emergency-msat`.

BUGS
----
Expand Down
2 changes: 1 addition & 1 deletion lightningd/hsm_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ struct ext_key *hsm_init(struct lightningd *ld)
if (feature_offered(ld->our_features->bits[INIT_FEATURE],
OPT_ANCHORS_ZERO_FEE_HTLC_TX)
&& !hsm_capable(ld, WIRE_HSMD_SIGN_ANCHORSPEND)) {
fatal("--experimental-anchors needs HSM capable of signing anchors!");
fatal("anchors needs HSM capable of signing anchors!");
}

if (feature_offered(ld->our_features->bits[INIT_FEATURE],
Expand Down
7 changes: 5 additions & 2 deletions lightningd/lightningd.c
Original file line number Diff line number Diff line change
Expand Up @@ -906,11 +906,14 @@ static struct feature_set *default_features(const tal_t *ctx)
OPTIONAL_FEATURE(OPT_ZEROCONF),
OPTIONAL_FEATURE(OPT_CHANNEL_TYPE),
OPTIONAL_FEATURE(OPT_ROUTE_BLINDING),
/* Removed later for elements */
OPTIONAL_FEATURE(OPT_ANCHORS_ZERO_FEE_HTLC_TX),
};

for (size_t i = 0; i < ARRAY_SIZE(features); i++) {
struct feature_set *f
= feature_set_for_feature(NULL, features[i]);
struct feature_set *f;

f = feature_set_for_feature(NULL, features[i]);
if (!ret)
ret = tal_steal(ctx, f);
else
Expand Down
35 changes: 24 additions & 11 deletions lightningd/opening_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -1148,7 +1148,7 @@ static struct command_result *json_fundchannel_start(struct command *cmd,
struct node_id *id;
struct peer *peer;
bool *announce_channel;
u32 *feerate_per_kw, *mindepth;
u32 *feerate_non_anchor, feerate_anchor, *mindepth;
int fds[2];
struct amount_sat *amount, *reserve;
struct amount_msat *push_msat;
Expand All @@ -1165,7 +1165,7 @@ static struct command_result *json_fundchannel_start(struct command *cmd,
if (!param_check(fc->cmd, buffer, params,
p_req("id", param_node_id, &id),
p_req("amount", param_sat, &amount),
p_opt("feerate", param_feerate, &feerate_per_kw),
p_opt("feerate", param_feerate, &feerate_non_anchor),
p_opt_def("announce", param_bool, &announce_channel, true),
p_opt("close_to", param_bitcoin_address, &fc->our_upfront_shutdown_script),
p_opt("push_msat", param_msat, &push_msat),
Expand Down Expand Up @@ -1196,19 +1196,32 @@ static struct command_result *json_fundchannel_start(struct command *cmd,
type_to_string(tmpctx, struct amount_sat, amount));

fc->funding_sats = *amount;
if (!feerate_per_kw) {
feerate_per_kw = tal(cmd, u32);
*feerate_per_kw = opening_feerate(cmd->ld->topology);
if (!*feerate_per_kw) {
if (!feerate_non_anchor) {
/* For non-anchors, we default to a low feerate for first
* commitment, and update it almost immediately. That saves
* money in the immediate-close case, which is probably soon
* and thus current feerates are sufficient. */
feerate_non_anchor = tal(cmd, u32);
*feerate_non_anchor = opening_feerate(cmd->ld->topology);
if (!*feerate_non_anchor) {
return command_fail(cmd, LIGHTNINGD,
"Cannot estimate fees");
}
}

if (*feerate_per_kw < get_feerate_floor(cmd->ld->topology)) {
feerate_anchor = unilateral_feerate(cmd->ld->topology, true);
/* Only complain here if we could possibly open one! */
if (!feerate_anchor
&& feature_offered(cmd->ld->our_features->bits[INIT_FEATURE],
OPT_ANCHORS_ZERO_FEE_HTLC_TX)) {
return command_fail(cmd, LIGHTNINGD,
"Feerate below feerate floor %u perkw",
get_feerate_floor(cmd->ld->topology));
"Cannot estimate fees");
}

if (*feerate_non_anchor < get_feerate_floor(cmd->ld->topology)) {
return command_fail(cmd, LIGHTNINGD,
"Feerate for non-anchor (%u perkw) below feerate floor %u perkw",
*feerate_non_anchor, get_feerate_floor(cmd->ld->topology));
}

if (!topology_synced(cmd->ld->topology)) {
Expand Down Expand Up @@ -1324,8 +1337,8 @@ static struct command_result *json_fundchannel_start(struct command *cmd,
fc->push,
fc->our_upfront_shutdown_script,
upfront_shutdown_script_wallet_index,
*feerate_per_kw,
unilateral_feerate(cmd->ld->topology, true),
*feerate_non_anchor,
feerate_anchor,
&tmp_channel_id,
fc->channel_flags,
fc->uc->reserve,
Expand Down
21 changes: 12 additions & 9 deletions lightningd/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -759,9 +759,9 @@ static char *opt_force_featureset(const char *optarg,
return "Invalid feature number";

f = feature_set_for_feature(NULL, n);
if (strstarts(optarg, "-")
&& !feature_set_sub(ld->our_features, take(f)))
return "Feature unknown";
if (strstarts(optarg, "-")) {
feature_set_sub(ld->our_features, take(f));
}

if (strstarts(optarg, "+")
&& !feature_set_or(ld->our_features, take(f)))
Expand Down Expand Up @@ -1258,10 +1258,7 @@ static char *opt_set_quiesce(struct lightningd *ld)

static char *opt_set_anchor_zero_fee_htlc_tx(struct lightningd *ld)
{
/* Requires static_remotekey, but we always set that */
feature_set_or(ld->our_features,
take(feature_set_for_feature(NULL,
OPTIONAL_FEATURE(OPT_ANCHORS_ZERO_FEE_HTLC_TX))));
/* FIXME: deprecated_apis! */
return NULL;
}

Expand Down Expand Up @@ -1469,8 +1466,7 @@ static void register_opts(struct lightningd *ld)
" channels.");
opt_register_early_noarg("--experimental-anchors",
opt_set_anchor_zero_fee_htlc_tx, ld,
"EXPERIMENTAL: enable option_anchors_zero_fee_htlc_tx"
" to open zero-fee-anchor channels");
opt_hidden);
clnopt_witharg("--announce-addr-dns", OPT_EARLY|OPT_SHOWBOOL,
opt_set_bool_arg, opt_show_bool,
&ld->announce_dns,
Expand Down Expand Up @@ -1789,6 +1785,13 @@ void handle_early_opts(struct lightningd *ld, int argc, char *argv[])
else
ld->config = mainnet_config;

/* No anchors if we're elements */
if (chainparams->is_elements) {
feature_set_sub(ld->our_features,
feature_set_for_feature(tmpctx,
OPTIONAL_FEATURE(OPT_ANCHORS_ZERO_FEE_HTLC_TX)));
}

/* Set the ln_port given from chainparams */
ld->config.ip_discovery_port = chainparams->ln_port;

Expand Down
35 changes: 34 additions & 1 deletion plugins/funder.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "config.h"
#include <bitcoin/feerate.h>
#include <bitcoin/psbt.h>
#include <bitcoin/script.h>
#include <ccan/array_size/array_size.h>
#include <ccan/json_out/json_out.h>
#include <ccan/tal/str/str.h>
Expand Down Expand Up @@ -35,6 +36,9 @@ struct pending_open {
const struct wally_psbt *psbt;
};

/* How much do we need to keep in reserve for anchor spends? */
static struct amount_sat emergency_reserve;

static struct pending_open *
find_channel_pending_open(const struct channel_id *cid)
{
Expand Down Expand Up @@ -564,7 +568,7 @@ listfunds_success(struct command *cmd,
const jsmntok_t *result,
struct open_info *info)
{
struct amount_sat available_funds, committed_funds, est_fee;
struct amount_sat available_funds, committed_funds, total_fee;
const jsmntok_t *outputs_tok, *tok;
struct out_req *req;
struct bitcoin_outpoint **avail_prev_outs;
Expand All @@ -583,9 +587,11 @@ listfunds_success(struct command *cmd,

available_funds = AMOUNT_SAT(0);
committed_funds = AMOUNT_SAT(0);
total_fee = AMOUNT_SAT(0);
avail_prev_outs = tal_arr(info, struct bitcoin_outpoint *, 0);
json_for_each_arr(i, tok, outputs_tok) {
struct funder_utxo *utxo;
struct amount_sat est_fee;
bool is_reserved;
struct bitcoin_outpoint *prev_out;
char *status;
Expand Down Expand Up @@ -639,6 +645,10 @@ listfunds_success(struct command *cmd,
plugin_err(cmd->plugin,
"`listfunds` overflowed output values");

if (!amount_sat_add(&total_fee, total_fee, est_fee))
plugin_err(cmd->plugin,
"`listfunds` overflowed fee values");

/* If this is an RBF, we keep track of available utxos */
if (info->prev_outs) {
/* if not previously reserved, it's committed */
Expand All @@ -660,6 +670,21 @@ listfunds_success(struct command *cmd,
}
}

/* Even if we don't have an anchor channel yet, we might soon:
* keep reserve, even after fee! Assume two outputs, one for
* change. */
if (!amount_sat_add(&total_fee, total_fee,
amount_tx_fee(info->funding_feerate_perkw,
BITCOIN_SCRIPTPUBKEY_P2WSH_LEN
+ change_weight()))) {
plugin_err(cmd->plugin,
"fee value overflow for estimating total fee");
}

if (!amount_sat_sub(&available_funds, available_funds, total_fee)
|| !amount_sat_sub(&available_funds, available_funds, emergency_reserve))
available_funds = AMOUNT_SAT(0);

funding_err = calculate_our_funding(current_policy,
info->id,
info->their_funding,
Expand Down Expand Up @@ -1467,6 +1492,7 @@ static void memleak_mark(struct plugin *p, struct htable *memtable)
static const char *init(struct plugin *p, const char *b, const jsmntok_t *t)
{
const char *err;
struct amount_msat msat;

list_head_init(&pending_opens);

Expand All @@ -1477,6 +1503,13 @@ static const char *init(struct plugin *p, const char *b, const jsmntok_t *t)
if (current_policy->rates)
tell_lightningd_lease_rates(p, current_policy->rates);

rpc_scan(p, "listconfigs",
take(json_out_obj(NULL, NULL, NULL)),
"{configs:"
"{min-emergency-msat:{value_msat:%}}}",
JSON_SCAN(json_to_msat, &msat));

emergency_reserve = amount_msat_to_sat_round_down(msat);
plugin_set_memleak_handler(p, memleak_mark);

return NULL;
Expand Down
3 changes: 1 addition & 2 deletions tests/test_bookkeeper.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,7 @@ def test_bookkeeping_missed_chans_leases(node_factory, bitcoind):
opts = {'funder-policy': 'match', 'funder-policy-mod': 100,
'lease-fee-base-sat': '100sat', 'lease-fee-basis': 100,
'plugin': str(coin_mvt_plugin),
'disable-plugin': 'bookkeeper',
'experimental-anchors': None}
'disable-plugin': 'bookkeeper'}

l1, l2 = node_factory.get_nodes(2, opts=opts)

Expand Down
Loading
Loading