Skip to content

Commit

Permalink
funder: don't try to spend emergency_reserve
Browse files Browse the repository at this point in the history
We might have (or be getting!) anchor channels, so keep this aside when funding.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Feb 7, 2024
1 parent e4d3cc8 commit 8c52efc
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 3 deletions.
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
4 changes: 2 additions & 2 deletions tests/test_opening.py
Original file line number Diff line number Diff line change
Expand Up @@ -1539,8 +1539,8 @@ def test_funder_contribution_limits(node_factory, bitcoind):

l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l1.fundchannel(l2, 10**7)
assert l2.daemon.is_in_log('Policy .* returned funding amount of 141780sat')
assert l2.daemon.is_in_log(r'calling `signpsbt` .* 6 inputs')
assert l2.daemon.is_in_log('Policy .* returned funding amount of 107530sat')
assert l2.daemon.is_in_log(r'calling `signpsbt` .* inputs')

l1.rpc.connect(l3.info['id'], 'localhost', l3.port)
l1.fundchannel(l3, 10**7)
Expand Down

0 comments on commit 8c52efc

Please sign in to comment.