Matt Corallo [Fri, 18 Nov 2022 19:02:02 +0000 (19:02 +0000)]
Add additional testing in `montior_tests` for chain idempotency
At the end of our `monitor_tests`, which test `ChannelMonitor`
`SpendableOutputs` and claimable `Balance`s, add new checks that
ensure that, if we're using the new
`ConnectStyle::HighlyRedundantTransactionsFirstSkippingBlocks`, we
can replay the full chain without getting redundant events or
`Balance`s.
Matt Corallo [Fri, 18 Nov 2022 18:54:16 +0000 (18:54 +0000)]
Ensure `transactions_confirmed` is idempotent
In many complexity-reduced implementations of chain syncing using
esplora `transactions_confirmed` may be called redundantly for
transactions which were already confirmed. To ensure this is
idempotent we add two new `ConnectionStyle`s in our tests which
(a) call `transactions_confirmed` twice for each call, ensuring
simple idempotency is ensured and (b) call `transactions_confirmed`
once for each historical block every time we're connecting a new
block, ensuring we're fully idempotent even if every call is
repeated constantly.
In order to actually behave correctly this requires a simple
already-confirmed check in `ChannelMonitor`, which is included.
Matt Corallo [Fri, 18 Nov 2022 22:51:17 +0000 (22:51 +0000)]
Explicitly track the set of spendable transactions which confirm
In `ChannelMonitor`s, when a transaction containing a spend of a
revoked remote output reaches 6 confs, we may have no other
tracking of that txid remaining. Thus, if we see that transaction
again (because a user duplicatively confirms it), we'll generate a
redundant spendable output event for it.
Here we simply explicitly track all txids of transactions which
confirm with a spendable output, allowing us to check this
condition in the next commit.
Matt Corallo [Fri, 18 Nov 2022 18:49:16 +0000 (18:49 +0000)]
Fix one test still connecting invalid blocks
In the next commit we'll add some checks that redundant
transactions aren't confirmed in different blocks, which would
cause test_htlc_ignore_latest_remote_commitment to fail. Here we
fix it to avoid the issue.
Elias Rohrer [Wed, 16 Nov 2022 09:54:25 +0000 (10:54 +0100)]
Mention `user_channel_id` rand. version req.
As it was previously omitted, we clarify here starting from which version users can expect the `user_channel_id` to be randomized for inbound channels.
Matt Corallo [Tue, 15 Nov 2022 00:29:10 +0000 (00:29 +0000)]
Await `Future::poll` `Complete`d before unsetting notify-required
When we mark a future as complete, if the user is using the
`std::future::Future` impl to get notified, we shouldn't just
assume we have completed the `Future` when we call the `Waker`. A
`Future` may have been `drop`'d at that point (or may not be
`poll`'d again) even though we wake the `Waker`.
Because we now have a `callbacks_made` flag, we can fix this rather
trivially, simply not setting the flag until the `Future` is
`poll`'d `Complete`.
Matt Corallo [Tue, 15 Nov 2022 00:24:25 +0000 (00:24 +0000)]
Wipe `Notifier` `FutureState` when returning from a waiter.
When we return from one of the wait functions in `Notifier`, we
should also ensure that the next `Future` doesn't start in the
`complete` state, as we have already notified the user, as far as
we're concerned.
This is technically a regression from the previous commit, but as
it is a logically separate change it is in its own commit.
Matt Corallo [Mon, 14 Nov 2022 23:49:27 +0000 (23:49 +0000)]
Unset the needs-notify bit in a Notifier when a Future is fetched
If a `Notifier` gets `notify()`ed and the a `Future` is fetched,
even though the `Future` is marked completed from the start and
the user may pass callbacks which are called, we'll never wipe the
needs-notify bit in the `Notifier`.
The solution is to keep track of the `FutureState` in the returned
`Future` even though its `complete` from the start, adding a new
flag in the `FutureState` which indicates callbacks have been made
and checking that flag when waiting or returning a second `Future`.
Elias Rohrer [Mon, 24 Oct 2022 08:30:11 +0000 (10:30 +0200)]
Make `user_channel_id` a `u128`
We increase the `user_channel_id` type from `u64` to `u128`. In order to
maintain backwards compatibility, we have to de-/serialize it as two
separate `u64`s in `Event` as well as in the `Channel` itself.
Elias Rohrer [Fri, 21 Oct 2022 09:05:18 +0000 (11:05 +0200)]
Randomize `user_channel_id` for inbound channels
Previously, all inbound channels defaulted to a `user_channel_id` of 0,
which didn't allow for them being discerned on that basis. Here, we
simply randomize the identifier to fix this and enable the use of
`user_channel_id` as a true identifier for channels (assuming an equally
reasonable value is chosen for outbound channels and given upon
`create_channel()`).
After the first persistence-required `Future` wakeup, we'll always
complete additional futures instantly as we don't clear the
"need wake" bit. Instead, we need to just assume that if a future
was generated (and not immediately drop'd) that its sufficient to
notify the user.
Wilmer Paulino [Tue, 8 Nov 2022 02:09:16 +0000 (18:09 -0800)]
Use BaseEventHandler to expose async event handling on InvoicePayer
We introduce a new sealed trait BaseEventHandler that has a blanket
implementation for any T. Since the trait cannot be implemented outside
of the crate, this allow us to expose specific implementations of
InvoicePayer that allow for synchronous and asynchronous event handling.
Matt Corallo [Wed, 2 Nov 2022 23:25:34 +0000 (23:25 +0000)]
Add a separate PaymentSendFailure for idempotency violation
When a user attempts to send a payment but it fails due to
idempotency key violation, they need to know that this was the
reason as they need to handle the error programmatically
differently from other errors.
Here we simply add a new `PaymentSendFailure` enum variant for
`DuplicatePayment` to allow for that.
It was pointed out that its quite confusing that
`AllFailedRetrySafe` does not allow you to call `retry_payment`,
though the documentation on it does specify this. Instead, we
simply rename it to `AllFailedResendSafe` to indicate that the
action that is safe to take is *resending*, not *retrying*.
Elias Rohrer [Tue, 8 Nov 2022 20:45:28 +0000 (21:45 +0100)]
Track block hash, return via `get_relevant_txids`
Previously, `Confirm::get_relevant_txids()` only returned a list of
transactions that have to be monitored for reorganization out of the
chain. This interface however required double bookkeeping: while we
internally keep track of the best block, height, etc, it would also
require the user to keep track which transaction was previously
confirmed in which block and to take actions based on any change, e.g,
to reconfirm them when the block would be reorged-out and the
transactions had been reconfirmed in another block.
Here, we track the confirmation block hash internally and return it via
`Confirm::get_relevant_txids()` to the user, which alleviates the
requirement for double bookkeeping: the user can now simply check
whether the given transaction is still confirmed and in the given block,
and take action if not.
We also split `update_claims_view`: Previously it was one, now it's two
methods: `update_claims_view_from_matched_txn` and
`update_claims_view_from_requests`.
Refactor HTLCForwardInfo::AddHTLC for intercept forwards
In upcoming commit(s), we'll want to store intercepted HTLC forwards in
ChannelManager before the user signals that they should be forwarded. It
wouldn't make sense to store a HTLCForwardInfo as-is because the FailHTLC
variant doesn't make sense, so we refactor out the ::AddHTLC contents into its
own struct for storage.
Co-authored-by: John Cantrell <johncantrell97@gmail.com> Co-authored-by: Valentine Wallace <vwallace@protonmail.com>
Jeffrey Czyz [Tue, 9 Aug 2022 22:40:26 +0000 (17:40 -0500)]
Builder for creating offers
Add a builder for creating offers given a required description and
node_id. Other settings are optional and duplicative settings will
override previous settings for non-Vec fields.
Jeffrey Czyz [Fri, 24 Jun 2022 21:27:42 +0000 (16:27 -0500)]
Serialization macro for TLV streams
BOLT 12's offer message is encoded as a TLV stream (i.e., a sequence of
TLV records). impl_writeable_tlv_based can't be used because it writes
the overall length of the struct, whereas TLV streams only include the
length of each TLV record. Add a `tlv_stream` macro for defining structs
used in encoding.
TLV records containing a single variable-length type should not encode
the types length in the value since it is redundant. Add a wrapper type
that can be used within a TLV stream to support the correct behavior
during serialization and de-serialization.
Jeffrey Czyz [Fri, 7 Oct 2022 04:12:48 +0000 (23:12 -0500)]
Add WithoutLength wrapper
When serializing variable-length types as part of a TLV stream, the
length does not need to be serialized as it is already encoded in TLV
records. Add a WithoutLength wrapper for this encoding. Replace
VecReadWrapper and VecWriteWrapper with this single type to avoid
redundant encoders.
Jeffrey Czyz [Tue, 9 Aug 2022 22:24:10 +0000 (17:24 -0500)]
Offer message interface and data format
Define an interface for BOLT 12 `offer` messages. The underlying format
consists of the original bytes and the parsed contents.
The bytes are later needed when constructing an `invoice_request`
message. This is because it must mirror all the `offer` TLV records,
including unknown ones, which aren't represented in the contents.
The contents will be used in `invoice_request` messages to avoid
duplication. Some fields while required in a typical user-pays-merchant
flow may not be necessary in the merchant-pays-user flow (i.e., refund).
Jeffrey Czyz [Thu, 6 Oct 2022 18:44:35 +0000 (13:44 -0500)]
Add PrintableString utility
Strings defined by third parties may contain control characters. Provide
a wrapper such that these are replaced when displayed. Useful in node
aliases and offer fields.
Jeffrey Czyz [Fri, 24 Jun 2022 21:40:49 +0000 (16:40 -0500)]
Offer features for BOLT 12
The offer message in BOLT 12 contains a features TLV record. Add a
corresponding OfferFeatures type where the length is not included in the
serialization as it would be redundant with the record length.
Otherwise, define the features to be the same as InvoiceFeatures.
Make `process_pending_htlc_forwards` more readable
Refactor `process_pending_htlc_forwards` to ensure that both branches
that fails `pending_forwards` are placed next to eachother for improved
readability.
Consider `channel_id`s in `short_to_chan_info` as unguaranteed
As the `short_to_chan_info` map has been removed from the
`channel_state`, there is no longer any consistency guarantees between
the `by_id` and `short_to_chan_info` maps. This commit ensures that we
don't force unwrap channels where the channel_id has been queried from
the `short_to_chan_info` map.
As the `short_to_chan_info` has been moved out of the `channel_state` to
a standalone lock, several macros no longer need the `channel_state`
passed into the macro.
This is part of moving the Router trait into ChannelManager, which will help
allow ChannelManager to fetch routes on-the-fly as part of supporting
trampoline payments.
Elias Rohrer [Wed, 26 Oct 2022 09:24:28 +0000 (11:24 +0200)]
Rename chan state `ChannelFunded` to `ChannelReady`
We rename `ChannelState::ChannelFunded` to `ChannelState::ChannelReady`
as we'll be in this state when both sides sent the `ChannelReady`
messages, which may also be before funding in the 0conf case.
Matt Corallo [Mon, 31 Oct 2022 03:23:02 +0000 (03:23 +0000)]
Add missing break when scoring a path with a missing channel
If we send payments over a path where a channel ended up being
closed, we'll remove it before we call
`ProbabilisticPaymentScorer::payment_path_failed`. This should be
fine, except that `payment_path_failed` does not break out of its
scoring loop if a channel is missing, causing it to assign a
minimum available-liquidity of the payment amount even to channels
which our attempt never arrived at.
The fix is simple - add the missing check and break.
Avoid generating redundant claims after initial confirmation
These claims will never be valid as a previous claim has already
confirmed. If a previous claim is reorged out of the chain, a new claim
will be generated bypassing the new behavior.
While this doesn't change much for our existing transaction-based
claims, as broadcasting an already confirmed transaction acts as a NOP,
it prevents us from yielding redundant event-based claims, which will be
introduced as part of the anchors patchset.
Matt Corallo [Wed, 2 Nov 2022 01:06:39 +0000 (01:06 +0000)]
Allow users to specify the `PaymentId` used in `InvoicePayer`
In order to allow users to pass a custom idempotency key to the
`send*` methods in `InvoicePayer`, we have to pipe the `PaymentId`
through to the `Payer` methods, which we do here.
By default, existing `InvoicePayer` methods use the `PaymentHash`
as the `PaymentId`, however we also add duplicate `send*_with_id`
methods which allow users to pass a custom `PaymentId`.
Finally, appropriate documentation updates are made to clarify
idempotency guarantees.
Matt Corallo [Sat, 8 Oct 2022 19:54:43 +0000 (19:54 +0000)]
Stop timing out payments automatically, requiring abandon_payment
When the `abandon_payment` flow was added there was some concern
that upgrading users may not migrate to the new flow, causing
memory leaks in the pending-payment tracking.
While this is true, now that we're relying on the
pending_outbound_payments map for `send_payment` idempotency, the
risk of removing a payment prematurely goes up from "spurious
retry failure" to "sending a duplicative payment", which is much
worse.
Thus, we simply remove the automated payment timeout here,
explicitly requiring that users call `abandon_payment` when they
give up retrying a payment.
Matt Corallo [Sat, 8 Oct 2022 23:26:18 +0000 (23:26 +0000)]
Delay removal of fulfilled outbound payments for a few timer ticks
Previously, once a fulfilled outbound payment completed and all
associated HTLCs were resolved, we'd immediately remove the payment
entry from the `pending_outbound_payments` map.
Now that we're using the `pending_outbound_payments` map for send
idempotency, this presents a race condition - if the user makes a
redundant `send_payment` call at the same time that the original
payment's last HTLC is resolved, the user would reasonably expect
the `send_payment` call to fail due to our idempotency guarantees.
However, because the `pending_outbound_payments` entry is being
removed, if it completes first the `send_payment` call will
succeed even though the user has not had a chance to see the
corresponding `Event::PaymentSent`.
Instead, here, we delay removal of `Fulfilled`
`pending_outbound_payments` entries until several timer ticks have
passed without any corresponding event or HTLC pending.
Matt Corallo [Thu, 6 Oct 2022 21:31:02 +0000 (21:31 +0000)]
Allow users to specify the `PaymentId` for new outbound payments
In c986e52ce83e9aeaa9447abebc5f6600470337cf, an `MppId` was added
to `HTLCSource` objects as a way of correlating HTLCs which belong
to the same payment when the `ChannelManager` sees an HTLC
succeed/fail. This allows it to have awareness of the state of all
HTLCs in a payment when it generates the ultimate user-facing
payment success/failure events. This was used in the same PR to
avoid generating duplicative success/failure events for a single
payment.
Because the field was only used as an internal token to correlate
HTLCs, and retries were not supported, it was generated randomly by
calling the `KeysInterface`'s 32-byte random-fetching function.
This also provided a backwards-compatibility story as the existing
HTLC randomization key was re-used for older clients.
In 28eea12bbe0d78d256f79ec725cf02366dce4e36 `MppId` was renamed to
the current `PaymentId` which was then used expose the
`retry_payment` interface, allowing users to send new HTLCs which
are considered a part of an existing payment.
At no point has the payment-sending API seriously considered
idempotency, a major drawback which leaves the API unsafe in most
deployments. Luckily, there is a simple solution - because the
`PaymentId` must be unique, and because payment information for a
given payment is held for several blocks after a payment
completes/fails, it represents an obvious idempotency token.
Here we simply require the user provide the `PaymentId` directly in
`send_payment`, allowing them to use whatever token they may
already have for a payment's idempotency token.