.. and bump its MSRV to 1.75.
Recently, `rustls` bumped their MSRV to 1.71. As we depend on them and
don't want to continuously pin this security-critical dependency back,
we have no choice left but to bump the MSRV for
`lightning-transaction-sync` to a version >= 1.71, too.
Here, we hence move the `lightning-transaction-sync` tests to a
dedicated script and propose to introduce a secondary MSRV of 1.75.
We chose this particular version, because:
a) it's > 1 year old
b) it provides a buffer to 1.71, i.e., if some crate bumped to a version
> 1.71, there is a chance we don't immediately have to react again
c) it
stabilized `async fn`s in traits (see
https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html),
which might become handy for related (BDK) crates, which hopefully will
adopt the same target.
When either the amount or the `max_total_cltv_expiry_delta` are
set to max-value, `set_max_path_length` can trigger overflows in
`build_onion_payloads_callback`, leading to debug-panics.
With the `Confirm` interface, transaction confirmations can come
in at any time, so asserting that a confirmation is more recent
than the last time we broadcasted a transaction can lead to
spurious assertion failures.
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, define a conversion from PendingV2Channel
to ChannelPhase (to be renamed Channel).
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, define a conversion from InboundV1Channel
to ChannelPhase (to be renamed Channel).
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, define a conversion from OutboundV1Channel
to ChannelPhase (to be renamed Channel).
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, define a conversion from Channel (to be
renamed FundedChannel) to ChannelPhase (to be renamed Channel).
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, update ChannelManager methods to use
methods on ChannelPhase for obtaining the appropriate V1 channel types.
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, update the convert_chan_phase_err macro to
use ChannelPhase::as_funded_mut instead.
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, update ChannelManager methods to use
ChannelPhase::as_unfunded_v2_mut and ChannelPhase::into_unfunded_v2
methods.
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, update ChannelManager::timer_tick_occurred
to use ChannelPhase::as_funded_mut and a new
ChannelPhase::unfunded_context_mut method.
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, update ChannelManager::handle_error to use
a new ChannelPhase::maybe_handle_error_without_close.
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, update ChannelManager::peer_connected to
use ChannelPhase::as_funded_mut and a new
ChannelPhase::maybe_get_open_channel method.
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, update ChannelManager::peer_disconnected to
use ChannelPhase::as_funded_mut and a new ChannelPhase::is_resumable
method.
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, update ChannelManager::signer_unblocked to
use ChannelPhase::as_funded and a new method on ChannelPhase dispatching
to each variant's signer_maybe_unblocked method.
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, update ChannelManager::internal_tx_abort to
use ChannelPhase::is_funded and a new ChannelPhase::as_unfunded_v2_mut
method.
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, rewrite ChannelManager's
unfunded_channel_count method to use ChannelPhase::as_funded and a new
ChannelPhase::as_unfunded_v2 method.
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, introduce ChannelPhase::is_funded for use
in ChannelManager when a Channel (to be later renamed FundedChannel)
needs to be tested for.
Lack of bindings support was because the method used to return a slice
of tuples, it seems. Now that it returns &[BlindedPaymentPath], bindings
should be possible given that they can be generated for
Bolt12Invoice::message_paths.
Rust 1.84.0 was recently released along with some new clippy lints, one
of which is `unnecessary_map_or`. Unfortunately this lint suggests using
`Option::is_some_and` as a fix, but this is only available in Rust
version >= 1.70, while we still have an MSRV of 1.63. So we silence that
lint for now.
We'd still like our lint CI to use stable Rust so that we can benefit from
new lint checks which may be helpful and don't require an MSRV bump, but
sometimes new lints (like in this case) do.
See:
https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_orhttps://doc.rust-lang.org/std/option/enum.Option.html#method.is_some_and
Exposing ChannelPhase in ChannelManager has led to verbose match
statements, which need to be modified each time a ChannelPhase is added.
Making ChannelPhase an implementation detail of Channel would help avoid
this.
As a step in this direction, introduce ChannelPhase::as_funded and
ChannelPhase::as_funded_mut for use in ChannelManager when a Channel (to
be later renamed FundedChannel) is needed.
Pending v2 channels will need to be broken up into separate phases for
constructing and signing the funding transaction. To avoid increasing
the number of phases, combine the InboundV2Channel and OutboundV2Channel
types so that the can be used in one phase. Whether the channel is
inbound or outbound can be inferred from the ChannelContext.
We recently introduced `TRACE`-level logging for event handling.
However, in onion messenger we'd now log (twice, actually) every time
`process_events_async` is called, which is very very spammy. Here we fix
this by short-cutting to only proceed when we actualy have any event
futures to poll.
Previously, we would fail parsing `Offer`s if the HRP didn't match our
expected (lowercase) HRP. Here, we relax this check in accordance with
the spec to also allow all-uppercase HRPs.
Since adding support for creating static invoices from ChannelManager, it's
easier to test these failure cases that went untested when we added support for
paying static invoices.
We can't use our regular offer creation util for receiving async payments
because the recipient can't be relied on to be online to service
invoice_requests.
Therefore, add a new offer creation util that is parameterized by blinded
message paths to another node on the network that *is* always-online and can
serve static invoices on behalf of the often-offline recipient.
Also add a utility for creating static invoices corresponding to these offers.
See new utils' docs and BOLTs PR 1149 for more info.
Utilizing the results of probes sent once a minute to a random node
in the network for a random amount (within a reasonable range), we
were able to analyze the accuracy of our resulting success
probability estimation with various PDFs across the historical and
live-bounds models.
For each candidate PDF (as well as other parameters, including the
histogram bucket weight), we used the
`min_zero_implies_no_successes` fudge factor in
`success_probability` as well as a total probability multiple fudge
factor to get both the historical success model and the a priori
model to be neither too optimistic nor too pessimistic (as measured
by the relative log-loss between succeeding and failing hops in our
sample data).
We then compared the resulting log-loss for the historical success
model and selected the candidate PDF with the lowest log-loss,
skipping a few candidates with similar resulting log-loss but with
more extreme constants (such as a power of 11 with a higher
`min_zero_implies_no_successes` penalty).
Somewhat surprisingly (to me at least), the (fairly strongly)
preferred model was one where the bucket weights in the historical
histograms are exponentiated. In the current design, the weights
are effectively squared as we multiply the minimum- and maximum-
histogram buckets together before adding the weight*probabilities
together.
Here we multiply the weights yet again before addition. While the
simulation runs seemed to prefer a slightly stronger weight than
the 4th power we do here, the difference wasn't substantial
(log-loss 0.5058 to 0.4941), so we do the simpler single extra
multiply here.
Note that if we did this naively we'd run out of bits in our
arithmetic operations - we have 16-bit buckets, which when raised
to the 4th can fully fill a 64-bit int. Additionally, when looking
at the 0th min-bucket we occasionally add up to 32 weights together
before multiplying by the probability, requiring an additional five
bits.
Instead, we move to using floats during our histogram walks, which
further avoids some float -> int conversions because it allows for
retaining the floats we're already using to calculate probability.
Across the last handful of commits, the increased pessimism more
than makes up for the increased runtime complexity, leading to a
40-45% pathfinding speedup on a Xeon Silver 4116 and a 25-45%
speedup on a Xeon E5-2687W v3.
Thanks to @twood22 for being a sounding board and helping analyze
the resulting PDF.
In the next commit we'll want to return floats or ints from
`success_probability` depending on the callsite, so instead of
duplicating the calculation logic, here we split the linear (which
always uses int math) and nonlinear (which always uses float math)
into separate methods, allowing us to write trivial
`success_probability` wrappers that return the desired type.