diff --git a/lightningd/Makefile b/lightningd/Makefile index 462447fd1..115f2eb90 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -31,6 +31,7 @@ LIGHTNINGD_COMMON_OBJS := \ common/gen_status_wire.o \ common/hash_u5.o \ common/htlc_state.o \ + common/htlc_trim.o \ common/htlc_wire.o \ common/key_derive.o \ common/io_lock.o \ diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 5184534d5..02b457844 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -436,6 +437,7 @@ static void json_add_htlcs(struct lightningd *ld, struct htlc_in_map_iter ini; const struct htlc_out *hout; struct htlc_out_map_iter outi; + u32 local_feerate = channel->channel_info.feerate_per_kw[LOCAL]; /* FIXME: Add more fields. */ json_array_start(response, "htlcs"); @@ -455,6 +457,9 @@ static void json_add_htlcs(struct lightningd *ld, &hin->payment_hash, sizeof(hin->payment_hash)); json_add_string(response, "state", htlc_state_name(hin->hstate)); + if (htlc_is_trimmed(REMOTE, hin->msat, local_feerate, + channel->our_config.dust_limit, LOCAL)) + json_add_bool(response, "local_trimmed", true); json_object_end(response); } @@ -474,6 +479,9 @@ static void json_add_htlcs(struct lightningd *ld, &hout->payment_hash, sizeof(hout->payment_hash)); json_add_string(response, "state", htlc_state_name(hout->hstate)); + if (htlc_is_trimmed(LOCAL, hout->msat, local_feerate, + channel->our_config.dust_limit, LOCAL)) + json_add_bool(response, "local_trimmed", true); json_object_end(response); } json_array_end(response); @@ -491,6 +499,49 @@ static void json_add_sat_only(struct json_stream *result, type_to_string(tmpctx, struct amount_msat, &msat)); } +/* This is quite a lot of work to figure out what it would cost us! */ +static struct amount_sat commit_txfee(const struct channel *channel, + struct amount_msat spendable) +{ + /* FIXME: make per-channel htlc maps! */ + const struct htlc_in *hin; + struct htlc_in_map_iter ini; + const struct htlc_out *hout; + struct htlc_out_map_iter outi; + struct lightningd *ld = channel->peer->ld; + u32 local_feerate = channel->channel_info.feerate_per_kw[LOCAL]; + size_t num_untrimmed_htlcs = 0; + + /* Assume we tried to spend "spendable" */ + if (!htlc_is_trimmed(LOCAL, spendable, + local_feerate, channel->our_config.dust_limit, + LOCAL)) + num_untrimmed_htlcs++; + + for (hin = htlc_in_map_first(&ld->htlcs_in, &ini); + hin; + hin = htlc_in_map_next(&ld->htlcs_in, &ini)) { + if (hin->key.channel != channel) + continue; + if (!htlc_is_trimmed(REMOTE, hin->msat, local_feerate, + channel->our_config.dust_limit, + LOCAL)) + num_untrimmed_htlcs++; + } + for (hout = htlc_out_map_first(&ld->htlcs_out, &outi); + hout; + hout = htlc_out_map_next(&ld->htlcs_out, &outi)) { + if (hout->key.channel != channel) + continue; + if (!htlc_is_trimmed(LOCAL, hout->msat, local_feerate, + channel->our_config.dust_limit, + LOCAL)) + num_untrimmed_htlcs++; + } + + return commit_tx_base_fee(local_feerate, num_untrimmed_htlcs); +} + static void json_add_channel(struct lightningd *ld, struct json_stream *response, const char *key, const struct channel *channel) @@ -605,6 +656,18 @@ static void json_add_channel(struct lightningd *ld, channel->channel_info.their_config.channel_reserve)) spendable = AMOUNT_MSAT(0); + /* If we're funder, subtract txfees we'll need to spend this */ + if (channel->funder == LOCAL) { + if (!amount_msat_sub_sat(&spendable, spendable, + commit_txfee(channel, spendable))) + spendable = AMOUNT_MSAT(0); + } + + /* We can't offer an HTLC less than the other side will accept. */ + if (amount_msat_less(spendable, + channel->channel_info.their_config.htlc_minimum)) + spendable = AMOUNT_MSAT(0); + json_add_amount_msat_compat(response, spendable, "spendable_msatoshi", "spendable_msat"); json_add_amount_msat_compat(response, diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 2197f28db..fb21f5bb6 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -112,6 +112,13 @@ const struct chainparams *get_chainparams(const struct lightningd *ld UNNEEDED) /* Generated stub for get_log_level */ enum log_level get_log_level(struct log_book *lr UNNEEDED) { fprintf(stderr, "get_log_level called!\n"); abort(); } +/* Generated stub for htlc_is_trimmed */ +bool htlc_is_trimmed(enum side htlc_owner UNNEEDED, + struct amount_msat htlc_amount UNNEEDED, + u32 feerate_per_kw UNNEEDED, + struct amount_sat dust_limit UNNEEDED, + enum side side UNNEEDED) +{ fprintf(stderr, "htlc_is_trimmed called!\n"); abort(); } /* Generated stub for htlcs_reconnect */ void htlcs_reconnect(struct lightningd *ld UNNEEDED, struct htlc_in_map *htlcs_in UNNEEDED, diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 13fefd28a..c207b3fa3 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -112,6 +112,13 @@ u32 get_block_height(const struct chain_topology *topo UNNEEDED) /* Generated stub for get_chainparams */ const struct chainparams *get_chainparams(const struct lightningd *ld UNNEEDED) { fprintf(stderr, "get_chainparams called!\n"); abort(); } +/* Generated stub for htlc_is_trimmed */ +bool htlc_is_trimmed(enum side htlc_owner UNNEEDED, + struct amount_msat htlc_amount UNNEEDED, + u32 feerate_per_kw UNNEEDED, + struct amount_sat dust_limit UNNEEDED, + enum side side UNNEEDED) +{ fprintf(stderr, "htlc_is_trimmed called!\n"); abort(); } /* Generated stub for invoices_create */ bool invoices_create(struct invoices *invoices UNNEEDED, struct invoice *pinvoice UNNEEDED,