lightningd: use a better channel if available to next hop.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2022-03-23 09:29:20 +10:30
parent debc1b90d3
commit 75596b3e0f
7 changed files with 66 additions and 35 deletions

View file

@ -601,15 +601,6 @@ struct channel_inflight *channel_inflight_find(struct channel *channel,
return NULL;
}
struct channel *active_channel_by_scid(struct lightningd *ld,
const struct short_channel_id *scid)
{
struct channel *chan = any_channel_by_scid(ld, scid);
if (chan && !channel_active(chan))
chan = NULL;
return chan;
}
struct channel *any_channel_by_scid(struct lightningd *ld,
const struct short_channel_id *scid)
{

View file

@ -394,8 +394,6 @@ struct channel *peer_any_unsaved_channel(struct peer *peer, bool *others);
struct channel *channel_by_dbid(struct lightningd *ld, const u64 dbid);
struct channel *active_channel_by_scid(struct lightningd *ld,
const struct short_channel_id *scid);
struct channel *any_channel_by_scid(struct lightningd *ld,
const struct short_channel_id *scid);

View file

@ -546,7 +546,7 @@ static void subtract_received_htlcs(const struct channel *channel,
}
}
static struct amount_msat channel_amount_spendable(const struct channel *channel)
struct amount_msat channel_amount_spendable(const struct channel *channel)
{
struct amount_msat spendable;
@ -1770,14 +1770,18 @@ command_find_channel(struct command *cmd,
tok->end - tok->start,
buffer + tok->start);
} else if (json_to_short_channel_id(buffer, tok, &scid)) {
*channel = active_channel_by_scid(ld, &scid);
if (*channel)
return NULL;
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Short channel ID not found: '%.*s'",
tok->end - tok->start,
buffer + tok->start);
*channel = any_channel_by_scid(ld, &scid);
if (!*channel)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Short channel ID not found: '%.*s'",
tok->end - tok->start,
buffer + tok->start);
if (!channel_active(*channel))
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Short channel ID not active: '%.*s'",
tok->end - tok->start,
buffer + tok->start);
return NULL;
} else {
return command_fail_badparam(cmd, "id", buffer, tok,
"should be a channel ID or short channel ID");

View file

@ -92,6 +92,10 @@ void channel_watch_funding(struct lightningd *ld, struct channel *channel);
/* If this channel has a "wrong funding" shutdown, watch that too. */
void channel_watch_wrong_funding(struct lightningd *ld, struct channel *channel);
/* How much can we spend in this channel? */
struct amount_msat channel_amount_spendable(const struct channel *channel);
/* How much can we receive in this channel? */
struct amount_msat channel_amount_receivable(const struct channel *channel);
/* Pull peers, channels and HTLCs from db, and wire them up.

View file

@ -621,11 +621,45 @@ static void forward_htlc(struct htlc_in *hin,
{
const u8 *failmsg;
struct lightningd *ld = hin->key.channel->peer->ld;
struct channel *next = active_channel_by_scid(ld, scid);
struct channel *next;
struct htlc_out *hout = NULL;
/* This is a shortcut for specifying next peer; doesn't mean
* the actual channel! */
next = any_channel_by_scid(ld, scid);
if (next) {
struct peer *peer = next->peer;
struct channel *channel;
struct amount_msat best_spendable = channel_amount_spendable(next);
/* Seek channel with largest spendable! */
list_for_each(&peer->channels, channel, list) {
struct amount_msat spendable;
if (!channel_can_add_htlc(channel))
continue;
spendable = channel_amount_spendable(channel);
if (!amount_msat_greater(spendable, best_spendable))
continue;
/* Don't override if fees differ... */
if (channel->feerate_base != next->feerate_base
|| channel->feerate_ppm != next->feerate_ppm)
continue;
/* Or if this would be below min for channel! */
if (amount_msat_less(amt_to_forward,
channel->channel_info.their_config.htlc_minimum))
continue;
/* OK, it's better! */
log_debug(next->log, "Chose a better channel: %s",
type_to_string(tmpctx, struct short_channel_id,
channel->scid));
next = channel;
}
}
/* Unknown peer, or peer not ready. */
if (!next || !next->scid) {
if (!next || !channel_active(next)) {
local_fail_in_htlc(hin, take(towire_unknown_next_peer(NULL)));
wallet_forwarded_payment_add(hin->key.channel->peer->ld->wallet,
hin, next ? next->scid : NULL, NULL,

View file

@ -10,10 +10,10 @@
bool deprecated_apis = false;
/* AUTOGENERATED MOCKS START */
/* Generated stub for active_channel_by_scid */
struct channel *active_channel_by_scid(struct lightningd *ld UNNEEDED,
const struct short_channel_id *scid UNNEEDED)
{ fprintf(stderr, "active_channel_by_scid called!\n"); abort(); }
/* Generated stub for any_channel_by_scid */
struct channel *any_channel_by_scid(struct lightningd *ld UNNEEDED,
const struct short_channel_id *scid UNNEEDED)
{ fprintf(stderr, "any_channel_by_scid called!\n"); abort(); }
/* Generated stub for bitcoind_getutxout_ */
void bitcoind_getutxout_(struct bitcoind *bitcoind UNNEEDED,
const struct bitcoin_outpoint *outpoint UNNEEDED,

View file

@ -3784,11 +3784,11 @@ def test_multichan(node_factory, executor, bitcoind):
scid12 = l1.get_channel_scid(l2)
scid23a = l2.get_channel_scid(l3)
# Now fund *second* channel l2->l3.
# Now fund *second* channel l2->l3 (slightly larger)
bitcoind.rpc.sendtoaddress(l2.rpc.newaddr()['bech32'], 0.1)
bitcoind.generate_block(1)
sync_blockheight(bitcoind, [l2])
l2.rpc.fundchannel(l3.info['id'], '0.05btc')
l2.rpc.fundchannel(l3.info['id'], '0.01001btc')
assert(len(only_one(l2.rpc.listpeers(l3.info['id'])['peers'])['channels']) == 2)
assert(len(only_one(l3.rpc.listpeers(l2.info['id'])['peers'])['channels']) == 2)
@ -3830,9 +3830,9 @@ def test_multichan(node_factory, executor, bitcoind):
chan23a_idx = 1
chan23b_idx = 0
# Check it used the right scid!
assert before[chan23a_idx]['to_us_msat'] != after[chan23a_idx]['to_us_msat']
assert before[chan23b_idx]['to_us_msat'] == after[chan23b_idx]['to_us_msat']
# Check it used the larger channel!
assert before[chan23a_idx]['to_us_msat'] == after[chan23a_idx]['to_us_msat']
assert before[chan23b_idx]['to_us_msat'] != after[chan23b_idx]['to_us_msat']
before = only_one(l2.rpc.listpeers(l3.info['id'])['peers'])['channels']
route[1]['channel'] = scid23b
@ -3843,9 +3843,9 @@ def test_multichan(node_factory, executor, bitcoind):
wait_for(lambda: [c['htlcs'] for c in only_one(l2.rpc.listpeers(l3.info['id'])['peers'])['channels']] == [[], []])
after = only_one(l2.rpc.listpeers(l3.info['id'])['peers'])['channels']
# Check it used the right scid!
assert before[chan23a_idx]['to_us_msat'] == after[chan23a_idx]['to_us_msat']
assert before[chan23b_idx]['to_us_msat'] != after[chan23b_idx]['to_us_msat']
# Now the first channel is larger!
assert before[chan23a_idx]['to_us_msat'] != after[chan23a_idx]['to_us_msat']
assert before[chan23b_idx]['to_us_msat'] == after[chan23b_idx]['to_us_msat']
# Make sure gossip works.
bitcoind.generate_block(5)
@ -3862,5 +3862,5 @@ def test_multichan(node_factory, executor, bitcoind):
assert chan23a['amount_msat'] == Millisatoshi(1000000000)
assert chan23a['short_channel_id'] == scid23a
assert chan23b['amount_msat'] == Millisatoshi(5000000000)
assert chan23b['amount_msat'] == Millisatoshi(1001000000)
assert chan23b['short_channel_id'] == scid23b