Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Route Blinding Error Handling #9

Open
wants to merge 48 commits into
base: master
Choose a base branch
from

Conversation

calvinrzachman
Copy link
Owner

Change Description

Description of change / link to associated issue.

Steps to Test

Steps for reviewers to follow to test the change.

Pull Request Checklist

Testing

  • Your PR passes all CI checks.
  • Tests covering the positive and negative (error paths) are included.
  • Bug fixes contain tests triggering the bug to prevent regressions.

Code Style and Documentation

📝 Please see our Contribution Guidelines for further guidance.

carlaKC and others added 30 commits February 6, 2023 12:08
This commit introduces the concept of a blinded payment, which
consists of a blinded path, aggregate parameters and minimal
constraints for the path and basic/sane validation.

Payment relay info and payment constraints are placed in the
record package, because when the time comes to add support for
forwarding of blinded payments, we'll extract these structs
as TLVs in our encrypted onion blob. For now, this is not
important (it's just an easy way to represent this data),
but Aggregate(Relay/Constraints) aliases are used in the
routing package to emphasize that these a blinded payment uses
aggregate versions of the per-hop struct.
This commit adds the encrypted_data and blinding_point tlvs to
the known set of even tlvs for the onion payload. These TLVs are
added in two places (the onion payload and hop struct) because
lnd uses the same set of TLV types for both structs (and they
inherently represent the same thing).

Note: in some places, unit tests intentionally mimic the style
of older tests, so as to be more consistently readable.
This commit introduces a single struct to hold all of the parameters
that are passed to FindRoute. This cleans up an already overloaded
function signature and prepares us for handling requests with blinded
routes where we need to perform some additional processing on our
para (such as extracting the target node from the blinded path).
Add the option to include a blinded route in a route request (exclusive
to including hop hints, because it's incongruous to include both), and
express the route as a chain of hop hints.

Using a chain of hints over a single hint to represent the whole path
allows us to re-use our route construction to fill in a lot of the
path on our behalf.
When we introduce blinded routes, some of our hops are expected
to have zero amounts to forward in their hop payload. This commit
updates our hop fee logic to attribute the full blinded route's
fees to the introduction node. We can't actually know where/how
these fees are distributed, so we collect them all at the
introduction node.
With the addition of blinded routes, we now need to account for the
possibility that intermediate nodes payloads will not have an amount
and expiry set because that information is provided by the recipient
encrypted data blob. This commit updates our payload packing to only
optionally include those fields.
This commit updates route construction to backfill the fields
required for payment to blinded paths and set amount to forward
and expiry fields to zero for intermediate hops (as is instructed
in the route blinding specification).

We could attempt to do this in the first pass, but that loop
relies on fields like amount to forward and expiry to calculate
each hop backwards, so we keep it simple (stupid) and post
processes the blinded portion, since it's computationally cheap
and more readable.
Note: This commit can be dropped before merge, it's mostly added
to make the PR easier to manually test against other
implementations that have bolt 12 invoices implemented already!
We'll need to pack feature vectors for route blinding, so we pull
the encoding/decoding out into separate functions (currently
contained in ChannelType). Though it's more lines of code, we keep
most of the ChannelType assertions so that we strictly enforce
use of the alias.
This commit adds encoding and decoding for blinded route data blobs.
TLV fields such as path_id (which are only used for the final hop)
are omitted to minimize the change size.
Add blinding points to update_add_htlc. This TLV will be set for
nodes that are relaying payments in blinded routes that are _not_
the introduction node.
If there is a blinding point present in update_add_htlc's TLVs, add
it to our payment descriptor struct so that it can be passed through
to onion decryption. This code path will be used for nodes that are
relaying payments inside of the blinded route (ie, all nodes except
the introduction node).

When we restore HTLCs from disk, we do not have the data provided in
UpdateAddHTLC's TLVs available. This is okay, because once we store
the HTLC as part of our commit state, either have the full wire message
stored (for acked but not signed htlcs) or a forwarding package with
all forwarding information has been produced (for fully locked in
htlcs).
This commit adds a workaround for the fact that we don't have our extra
htlc data (ie, that provided in tlvs) stored in channeldb.HTLC. It
ensures that we have the blinding point populated on restart for the
following set of circumstances:
* The incoming HTLC is irrevocably committed to in our local commitment,
  ie: we have received a CommitSig and sent a RevokeAndAck for a
  commitment that includes the incoming HTLC.
* The incoming HTLC is still pending on the sender, ie: we have not yet
  sent the remote party a CommitSig covering the incoming HTLC.

If we restart at this point, the htlc will be stored as an incoming htlc
on our local commitment (with no blinding point) and the full log update
will be saved as a LogUpdate in our remote pending updates (because we
have not yet provided the remote party with a signature).

We restore our remoteUpdateLog from the local commit's incoming htlcs,
so before this change these htlcs would be loaded into our in-memory log
without their blinding point set (and operation would incorrectly resume
as usual without it). This commit updates our logic to restore blinding
points (if set) to the htlcs in the remoteUpdateLog.
When we have payments inside of a blinded route, we need to know
the incoming amount to be able to back-calculate the amount that
we need to forward using the forwarding parameters provided in the
blinded route encrypted data. This commit adds the payment amount
to our DecodeHopIteratorRequest so that it can be threaded down to
payment forwarding information creation in later commits.
This commit introduces a blinding kits which abstracts over the
operations required to decrypt, deserialize and reconstruct forwarding
data from an encrypted blob of data included for nodes in blinded
routes.

The concept of a BlindingKey is separated into a separate struct so
that it can be used independently of the kit (which is specifically used
to process encrypted blobs). This abstraction will be used later to help
determine how we handle errors.
When we have a HTLC that is part of a blinded route, we need to include
the next ephemeral blinding point in UpdateAddHtlc for the next hop. The
way that we handle the addition of this key is the same for introduction
nodes and relaying nodes within the route.
If we received a payload with a blinding point set, our forwarding
information should be set from the information in our encrypted blob.
This behavior is the same for introduction and relying nodes in a
blinded route.
carlaKC and others added 18 commits February 6, 2023 12:20
Note: the itest is broken up into multiple commits to make it
more readable, they can be squashed post-review.
We don't support receiving blinded in this PR - just intercept and
settle instead.
Enforce that required fields are present for the last hop in a blind route.
Enforce that if an onion has a route blinding payload, then we must
receive a blinding point!

Also, we properly indicate whether a hop is terminal/final during validation
of allowed types.
Verifies that parsing the onion and route blinding TLV payloads
yields the expected errors depending on whether the proper fields
were included or omitted.
I am not sure this is correct. We do eventually need to allow use of
a total_amt_msat field and it seems that MPP record is one way to get that.
- use SendToRouteV2 (as it's not deprecated)
- add MPP fields to final hop
- create invoice so dave can receive payment to blinded route
- ensure alice uses the same preimage/payment hash as invoice in the request to SendToRouteV2
Define an opaque (non-privacy-leaking) error type which is to be used
ubiquitously for errors which occur inside a blinded route regardless
of the internal or downstream reason for failure.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants