-
Notifications
You must be signed in to change notification settings - Fork 366
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
Support sending PaymentMetadata
in HTLCs
#2127
Support sending PaymentMetadata
in HTLCs
#2127
Conversation
2853050
to
64ed1a1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Had some nits and questions
/// | ||
/// (C-not exported) as we likely need to manually select one set of boolean type parameters. | ||
#[derive(Eq, PartialEq, Debug, Clone)] | ||
pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> { | ||
pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Woah, this is the first time I'm really looking at this part of the repo, this is so cool. Just to make sure I'm getting things right, these type parameters are here to basically conditionally implement/expose functions to the user based on the state of the invoice (what fields have been added) (such that a user's error will be caught at compile time), and then the PhantomData
is there to just use the types because rust doesn't allow unused type params?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep!
lightning-invoice/src/lib.rs
Outdated
self.set_flags() | ||
} | ||
} | ||
|
||
impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool> InvoiceBuilder<D, H, T, C, tb::True> { | ||
impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, T, C, S, tb::True> { | ||
/// Sets the payment secret and relevant features. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment needs to be changed :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ This wasn't resolved in the right commit
lightning/src/ln/msgs.rs
Outdated
OnionHopDataFormat::NonFinalNode { | ||
short_channel_id, | ||
} | ||
} else { | ||
if let &Some(ref data) = &payment_data { | ||
if let Some(data) = &mut payment_data { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the mut
may be unnecessary here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh, funny that didn't generate a compilation warning.
401187d
to
bea53eb
Compare
Codecov ReportPatch coverage:
📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more Additional details and impacted files@@ Coverage Diff @@
## main #2127 +/- ##
==========================================
+ Coverage 91.40% 92.08% +0.68%
==========================================
Files 102 102
Lines 50306 58635 +8329
Branches 50306 58635 +8329
==========================================
+ Hits 45982 53996 +8014
- Misses 4324 4639 +315
... and 20 files with indirect coverage changes Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report in Codecov by Sentry. |
RecipientOnionFields::secret_only(payment_secret_1), PaymentId(payment_hash_1.0)), | ||
true, APIError::ChannelUnavailable {..}, {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: weird indentation and below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, I was trying to find something compact that also showed which parameters went with which method? I guess should have moved the closing )
to the next line, would that address this? Its repeated in a bunch of places so only want to fix it once.
lightning/src/ln/channelmanager.rs
Outdated
@@ -2711,14 +2744,14 @@ where | |||
/// Note that `route` must have exactly one path. | |||
/// | |||
/// [`send_payment`]: Self::send_payment | |||
pub fn send_spontaneous_payment(&self, route: &Route, payment_preimage: Option<PaymentPreimage>, payment_id: PaymentId) -> Result<PaymentHash, PaymentSendFailure> { | |||
pub fn send_spontaneous_payment(&self, route: &Route, payment_preimage: Option<PaymentPreimage>, recipient_onion: RecipientOnionFields, payment_id: PaymentId) -> Result<PaymentHash, PaymentSendFailure> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should bring back the invoice util for spontaneous payments, tbh
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean....its still a one-line util to call a method by passing two None
s in...if we want a util we can just add a second method here that calls the first, but I'm not super convinced...
bea53eb
to
4770ce9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking basically good to me. Will give it another look after a 2nd reviewer comes in
lightning/src/ln/channelmanager.rs
Outdated
/// receives, thus you should generally never be providing a secret here for spontaneous | ||
/// payments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that apparently lnd will reject keysends with payment secrets: ACINQ/eclair#2574
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, should I indicate more strongly in the docs here that it'll be rejected (independent of the MPP context)?
* Payments sent with the legacy `*_with_route` methods on LDK 0.0.115+ will no | ||
longer be retryable via the LDK 0.0.114- `retry_payment` method (#XXXX). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this just because we might be re-attempting a payment with payment_metadata
as a required feature? I see we add an even TLV in this PR but it's only for the onion payload...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking we'd fail because the PaymentSecret was ripped out of the HTLCSource::OutboundRoute
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah that makes sense... Looks like we'll allow retry if it's not an MPP, but obviously the receiver will then fail it
Gonna reorder the commits here to put the refactor bulk work into another PR and then pick this back up after, maybe with receive too. |
4770ce9
to
866fca8
Compare
0239343
to
91cd8c5
Compare
91cd8c5
to
567d11d
Compare
Rebased after the dependent PR merge and added the receive end of thing. Still need to add some testing but otherwise should be good. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - the receive validation refactoring looks great 👍
Okay, pushed some tests and even a doc cleanup. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did a first pass, but will do a more thorough one after poking around spec/current code for some more context.
@@ -278,6 +278,7 @@ mod sealed { | |||
} | |||
|
|||
flags[Self::BYTE_OFFSET] |= Self::REQUIRED_MASK; | |||
flags[Self::BYTE_OFFSET] &= !Self::OPTIONAL_MASK; | |||
} | |||
|
|||
/// Sets the feature's optional (odd) bit in the given flags. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So related question: we could technically get back to a case where both are set by calling set_optional_bit
with flags
. Do we care or just assume it cannot override and unset the required bit? Seems like a misuse of the methods by the caller of course, but just wondering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we care particularly - afaik there's nothing that says we cant set both bits, it just seems like we don't need to, and mostly it made testing easier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good from a first pass, just some comments/nits.
/// Sets the payment metadata. | ||
/// | ||
/// By default features are set to *optionally* allow the sender to include the payment metadata. | ||
/// If you wish to require that the sender include the metadata (and fail to parse the invoice if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// If you wish to require that the sender include the metadata (and fail to parse the invoice if | |
/// If you wish to require that senders include the metadata (and fail to parse the invoice if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But there's only one sender?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, then it should probably be "...that the sender includes the metadata (and fails to parse the invoice if..."
3077967
to
e1f3246
Compare
lightning-invoice/src/lib.rs
Outdated
self.set_flags() | ||
} | ||
} | ||
|
||
impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool> InvoiceBuilder<D, H, T, C, tb::True> { | ||
impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, T, C, S, tb::True> { | ||
/// Sets the payment secret and relevant features. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ This wasn't resolved in the right commit
@@ -278,6 +278,7 @@ mod sealed { | |||
} | |||
|
|||
flags[Self::BYTE_OFFSET] |= Self::REQUIRED_MASK; | |||
flags[Self::BYTE_OFFSET] &= !Self::OPTIONAL_MASK; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also unset the required bit when setting the optional bit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe? Let's consider that in #2193, this change is really just for testing.
} else { | ||
for (purpose, (payment_hash, htlcs)) in purposes.into_iter().zip(claimable_htlcs_list.into_iter()) { | ||
let existing_payment = claimable_payments.insert(payment_hash, ClaimablePayment { | ||
purpose, htlcs, onion_fields: None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we fill this in using the purpose
? Not sure it has to be Option
al
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can, yes, but I don't think we should. onion_fields
being Some
indicates that we understood but didn't have a metadata, and maybe in the future TLV fields. We don't support retrying these anyway so I kinda preferred to leave it None
.
/// identical in each HTLC involved in the payment will be included here. | ||
/// | ||
/// Payments received on LDK versions prior to 0.0.115 will have this field unset. | ||
onion_fields: Option<RecipientOnionFields>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like we could get rid of PaymentPurpose::Invoice::payment_secret
if we wanted to avoid including it redundantly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, I started to do that but we'd have to break out the TLV serialization and kinda figured it wasn't worth it. We can do it later, too, there's no real reason to do it now given the size of this PR anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
e1f3246
to
3580020
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some nits. LGTM after squash
There is no reason to set both, and this currently makes testing the new BOLT invoice tests slightly harder, so we just unset it.
This adds support for reading the new `PaymentMetadata` BOLT11 invoice field, giving us access to the `Vec<u8>` storing arbitrary bytes we have to send to the recipient.
This adds support for setting the new payment metadata field in BOLT11 invoices, using a new type flag on the builder to enforce transition correctness. We allow users to set the payment metadata as either optional or required, defaulting to optional so that invoice parsing does not fail if the sender does not support payment metadata fields.
This adds the new `payment_metadata` to `RecipientOnionFields`, passing the metadata from BOLT11 invoices through the send pipeline and finally copying them info the onion when sending HTLCs. This completes send-side support for the new payment metadata feature.
This makes the `claimable_payments` code more upgradable allowing us to add new fields in the coming commit(s).
3580020
to
c5d52ce
Compare
Squashed all the fixup commits down, with new comments and a test failure addressed as well:
|
lightning/src/ln/outbound_payment.rs
Outdated
} | ||
|
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: extra spacing here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, happy for outstanding comments to be addressed in follow-ups.
@@ -332,6 +332,56 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> { | |||
true, // Different features than set in InvoiceBuilder | |||
true, // Some unknown fields | |||
), | |||
( // Older version of the payment metadata test with a payment_pubkey set | |||
"lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66sp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgqy9gw6ymamd20jumvdgpfphkhp8fzhhdhycw36egcmla5vlrtrmhs9t7psfy3hkkdqzm9eq64fjg558znccds5nhsfmxveha5xe0dykgpspdha0".to_owned(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Could linebreak the strings here and below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you mean? You mean break the strings into a few lines via concat!()
? We haven't done it elsewhere in the file, and not sure that's really nicer?
/// they don't support payment metadata fields), you need to call | ||
/// [`InvoiceBuilder::require_payment_metadata`] after this. | ||
pub fn payment_metadata(mut self, payment_metadata: Vec<u8>) -> InvoiceBuilder<D, H, T, C, S, tb::True> { | ||
self.tagged_fields.push(TaggedField::PaymentMetadata(payment_metadata)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a follow-up we might want to look into: Do we need/want to limit the size of the payment metadata field? How can we communicate the influence it might have on the maximum path length?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll need to rework all that code for blinded paths too, indeed let's do it in a followup - #2201
If we add an entry to `claimable_payments` we have to ensure we actually accept the HTLC we're considering, otherwise we'll end up with an empty `claimable_payments` entry.
If we receive an HTLC and are processing it a potential MPP part, we always continue in the per-HTLC loop if we call the `fail_htlc` macro, thus its nice to actually do the `continue` therein rather than at the callsites.
When we receive an HTLC, we want to pass the `payment_metadata` through to the `PaymentClaimable` event. This does most of the internal refactoring required to do so - storing a `RecipientOnionFields` in the inbound HTLC tracking structs, including the `payment_metadata`. In the future this struct will allow us to do MPP keysend receipts (as it now stores an Optional `payment_secret` for all inbound payments) as well as custom TLV receipts (as the struct is extensible to store additional fields and the internal API supports filtering for fields which are consistent across HTLCs).
This finally completes the piping of the `payment_metadata` from from the BOLT11 invoice on the sending side all the way through the onion sending + receiving ends to the user on the receive events.
c5d52ce
to
ef8e377
Compare
Added one commit for a new debug_assertion, and dropped some excess \n while at it:
|
0.0.115 - Apr 24, 2023 - "Rebroadcast the Bugfixes" API Updates =========== * The MSRV of the main LDK crates has been increased to 1.48 (lightningdevkit#2107). * Attempting to claim an un-expired payment on a channel which has closed no longer fails. The expiry time of payments is exposed via `PaymentClaimable::claim_deadline` (lightningdevkit#2148). * `payment_metadata` is now supported in `Invoice` deserialization, sending, and receiving (via a new `RecipientOnionFields` struct) (lightningdevkit#2139, lightningdevkit#2127). * `Event::PaymentFailed` now exposes a failure reason (lightningdevkit#2142). * BOLT12 messages now support stateless generation and validation (lightningdevkit#1989). * The `NetworkGraph` is now pruned of stale data after RGS processing (lightningdevkit#2161). * Max inbound HTLCs in-flight can be changed in the handshake config (lightningdevkit#2138). * `lightning-transaction-sync` feature `esplora-async-https` was added (lightningdevkit#2085). * A `ChannelPending` event is now emitted after the initial handshake (lightningdevkit#2098). * `PaymentForwarded::outbound_amount_forwarded_msat` was added (lightningdevkit#2136). * `ChannelManager::list_channels_by_counterparty` was added (lightningdevkit#2079). * `ChannelDetails::feerate_sat_per_1000_weight` was added (lightningdevkit#2094). * `Invoice::fallback_addresses` was added to fetch `bitcoin` types (lightningdevkit#2023). * The offer/refund description is now exposed in `Invoice{,Request}` (lightningdevkit#2206). Backwards Compatibility ======================= * Payments sent with the legacy `*_with_route` methods on LDK 0.0.115+ will no longer be retryable via the LDK 0.0.114- `retry_payment` method (lightningdevkit#2139). * `Event::PaymentPathFailed::retry` was removed and will always be `None` for payments initiated on 0.0.115 which fail on an earlier version (lightningdevkit#2063). * `Route`s and `PaymentParameters` with blinded path information will not be readable on prior versions of LDK. Such objects are not currently constructed by LDK, but may be when processing BOLT12 data in a coming release (lightningdevkit#2146). * Providing `ChannelMonitorUpdate`s generated by LDK 0.0.115 to a `ChannelMonitor` on 0.0.114 or before may panic (lightningdevkit#2059). Note that this is in general unsupported, and included here only for completeness. Bug Fixes ========= * Fixed a case where `process_events_async` may `poll` a `Future` which has already completed (lightningdevkit#2081). * Fixed deserialization of `u16` arrays. This bug may have previously corrupted the historical buckets in a `ProbabilisticScorer`. Users relying on the historical buckets may wish to wipe their scorer on upgrade to remove corrupt data rather than waiting on it to decay (lightningdevkit#2191). * The `process_events_async` task is now `Send` and can thus be polled on a multi-threaded runtime (lightningdevkit#2199). * Fixed a missing macro export causing `impl_writeable_tlv_based_enum{,_upgradable}` calls to not compile (lightningdevkit#2091). * Fixed compilation of `lightning-invoice` with both `no-std` and serde (lightningdevkit#2187) * Fix an issue where the `background-processor` would not wake when a `ChannelMonitorUpdate` completed asynchronously, causing delays (lightningdevkit#2090). * Fix an issue where `process_events_async` would exit immediately (lightningdevkit#2145). * `Router` calls from the `ChannelManager` now call `find_route_with_id` rather than `find_route`, as was intended and described in the API (lightningdevkit#2092). * Ensure `process_events_async` always exits if any sleep future returns true, not just if all sleep futures repeatedly return true (lightningdevkit#2145). * `channel_update` messages no longer set the disable bit unless the peer has been disconnected for some time. This should resolve cases where channels are disabled for extended periods of time (lightningdevkit#2198). * We no longer remove CLN nodes from the network graph for violating the BOLT spec in some cases after failing to pay through them (lightningdevkit#2220). * Fixed a debug assertion which may panic under heavy load (lightningdevkit#2172). * `CounterpartyForceClosed::peer_msg` is now wrapped in UntrustedString (lightningdevkit#2114) * Fixed a potential deadlock in `funding_transaction_generated` (lightningdevkit#2158). Security ======== * Transaction re-broadcasting is now substantially more aggressive, including a new regular rebroadcast feature called on a timer from the `background-processor` or from `ChainMonitor::rebroadcast_pending_claims`. This should substantially increase transaction confirmation reliability without relying on downstream `TransactionBroadcaster` implementations for rebroadcasting (lightningdevkit#2203, lightningdevkit#2205, lightningdevkit#2208). * Implemented the changes from BOLT PRs lightningdevkit#1031, lightningdevkit#1032, and lightningdevkit#1040 which resolve a privacy vulnerability which allows an intermediate node on the path to discover the final destination for a payment (lightningdevkit#2062). In total, this release features 110 files changed, 11928 insertions, 6368 deletions in 215 commits from 21 authors, in alphabetical order: * Advait * Alan Cohen * Alec Chen * Allan Douglas R. de Oliveira * Arik Sosman * Elias Rohrer * Evan Feenstra * Jeffrey Czyz * John Cantrell * Lucas Soriano del Pino * Marc Tyndel * Matt Corallo * Paul Miller * Steven * Steven Williamson * Steven Zhao * Tony Giorgio * Valentine Wallace * Wilmer Paulino * benthecarman * munjesi
This adds all the required infrastructure to send
PaymentMetadata
in HTLCs, largely as a rebase of #1445 (with commit ordering shuffled around so that the new struct is added first - I ended up rewriting that commit as it makes sense to go first, rather than strictly rebasing the existing work).While this does deserialize the new field in the onion, it doesn't actually store it as HTLCs are received and expose it to users.
By switching the payment secret public API parameters to a new struct we also have more space to grow when we add the ability to have custom TLVs in the onion.