Its somewhat strange to have a trait method which is named after
the intended action, rather than the action that occurred, leaving
it up to the implementor what action they want to take.
If the scoring in the routing benchmark causes us to take a
different path from the original scan, we may end up deciding that
the only path to a node has a too-high total CLTV delta, causing us
to panic in the benchmarking phase.
Here we simply check for that possibility and remove paths that
fail post-scoring.
New `funding_locked` messages can include SCID aliases which our
counterparty will recognize as "ours" for the purposes of relaying
transactions to us. This avoids telling the world about our
on-chain transactions every time we want to receive a payment, and
will allow for receiving payments before the funding transaction
appears on-chain.
Here we store the new SCID aliases and use them in invoices instead
of he "standard" SCIDs.
This doesn't (appear) to change behavior, however if we have a
non-public node, we assign an A* heuristic of max-u32 fees, which
may result in us de-prioritizing the path in some rare cases around
multi-hop route hints which compete with public nodes.
When we added support for routing through a multi-hop invoice hint
we failed to remove an assertion that we always are able to fill
in features for each hop except the last one. However, when a
multi-hop invoice hint is used, we will not have features for any
of the hinted hops, causing us to panic.
Add other fields to log for PathBuildingHop
Use DebugStruct to print PathBuildingHop
Fix PathBuildingHop visibility
Add more useful fee print-outs
Remove Features<NodeContext> from hop print-out
Remove logging fields we don’t need
Add fields to log back to PathBuildingHop
The take-self-return-Self idiom in Rust is substantially less
usable than it is in Java, where its more common. Because we have
to take self by move, it prevents using the update methods to
actually update features, something we occasionally want to do.
See, eg, the change in lightning-invoice where we previously had
to copy and re-create an entire vec of fields just to update the
features field, which is nuts.
There are a few places where this makes things a little less clean,
but the tradeoff to enable more effecient and broader uses of the
update methods seems worth it.
The docs were hidden since a type alias should be used. However, the
alias docs don't contain much useful information and don't link to the
corresponding struct.
`cargo bench` sets `cfg(test)`, causing us to hit some test-only
code in the router when benchmarking, throwing off our benchmarks
substantially. Here we swap from the `unstable` feature to a more
clearly internal feature (`_bench_unstable`) and also checking for
it when enabling test-only code.
ProbabilisticScorer uses successful and unsuccessful payments to gain
more certainty of a channel's liquidity balance. Decay this knowledge
over time to indicate decreasing certainty about the liquidity balance.
Add a Score implementation based on "Optimally Reliable & Cheap Payment
Flows on the Lightning Network" by Rene Pickhardt and Stefan Richter[1].
Given the uncertainty of channel liquidity balances, probability
distributions are defined based on knowledge learned from successful and
unsuccessful attempts. Then the negative log of the success probability
is used to determine the cost of routing a specific HTLC amount through
a channel.
[1]: https://arxiv.org/abs/2107.05322
A channel's capacity may be inferred or learned and is used to make
routing decisions, including as a parameter to channel scoring. Define
an EffectiveCapacity for this purpose. Score::channel_penalty_msat takes
the effective capacity (less in-flight HTLCs for the same payment), and
never None. Thus, for hops given in an invoice, the effective capacity
is now considered (near) infinite if over a private channel or based on
learned information if over a public channel.
If a Score implementations needs the effective capacity when updating a
channel's score, i.e. in payment_path_failed or payment_path_successful,
it can access the channel's EffectiveCapacity via the NetworkGraph by
first looking up the channel and then specifying which direction is
desired using ChannelInfo::as_directed.
Scorers may have different performance characteristics after seeing
failed and successful paths. Seed the scorer with some random data
before executing the benchmark in order to exercise such behavior.
Passing first_hops to get_route increases the coverage of the benchmark
test. For scorers needing the sending node, it allows for using a single
scorer in the benchmark rather than re-initializing on each iteration.
As a consequence, the scorer can be seeded with success and failure
data.
Refactor generate_routes and generate_mpp_routes into a single utility
for benchmarking. The utility is parameterized with features in order to
test both single path and multi-path routing. Additionally, it is
parameterized with a Score to be used with other scorers.
Because we time out channel info that is older than two weeks now,
we should also reject new channel info that is older than two
weeks, in addition to rejecting future channel info.
We define "stale" as "haven't heard an updated channel_update in
two weeks", as described in BOLT 7.
We also filter out stale channels at write-time for `std` users, as
we can look up the current time.
An unchecked shift of more than 64 bits on u64 values causes a shift
overflow panic. This may happen if a channel is penalized only once and
(1) is not successfully routed through and (2) after 64 or more half
life decays. Use a checked shift to prevent this from happening.