-
Notifications
You must be signed in to change notification settings - Fork 402
Asynchronous Bolt12Invoice
payment
#3078
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
Conversation
Codecov ReportAttention: Patch coverage is
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## main #3078 +/- ##
==========================================
+ Coverage 89.82% 90.02% +0.20%
==========================================
Files 119 121 +2
Lines 97987 100303 +2316
Branches 97987 100303 +2316
==========================================
+ Hits 88014 90297 +2283
- Misses 7397 7427 +30
- Partials 2576 2579 +3 ☔ View full report in Codecov by Sentry. |
LGTM (modulo failing fuzz test), but remind me again why they want to examine invoices for outbound payments? |
Sorry for the delay. Wanted to double check with them on the specifics. The gateway's lightning node requests the invoice on the users behalf. The user doesn't trust the gateway so needs to confirm that the amount is expected and that it is paying the right entity (i.e., the containing offer is expected and thus the invoice has the right signature). |
Right, thanks, I guess the user needs to actually transfer the ecash to the gateway (conditional on the payment preimage) but they want to validate the payment_hash/amount pair in the invoice first. |
@jkczyz I think this needs a (assumingly minor) rebase. |
A future InvoiceReceived event will include a Bolt12Invoice. Since Event implements Readable, so must Bolt12Invoice.
A future InvoiceReceived event will include a Responder. Since Event implements Readable, so must Responder.
48aedd0
to
a4fdae2
Compare
Rebased |
/// This event will only be generated if [`UserConfig::manually_handle_bolt12_invoices`] is set. | ||
/// Use [`ChannelManager::send_payment_for_bolt12_invoice`] to pay the invoice or | ||
/// [`ChannelManager::abandon_payment`] to abandon the associated payment. | ||
/// |
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 mention how long the user has to pay the invoice before it'll time out and they'll have to start again (and is that gonna be an issue for fedi)?
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.
Wait, don't we expire the payment based on StaleExpiration
too? As if we'd never received the invoice.
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.
Oh, right. I forgot that that's checked at time of payment.
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.
Ended up reverting those changes and re-writing the send_payment_for_bolt12_invoice
accordingly.
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 you forget to push this?
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 to be there: f2721af
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.
Oh I interpreted "re-writing the send_payment_for_bolt12_invoice
accordingly" comment as you changed it so we don't time out, rather than rewriting the docs.
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.
Hmmm...send_payment_for_bolt12_invoice
docs were changed to clarify when a Bolt12PaymentError::UnexpectedInvoice
can occur, including the timeout scenarios. StaleExpiration
is not explicitly mentioned because it is pub(crate)
. I did remove the invoice-level expiration part since that's really a detail surfaced by Event::PaymentFailed
, which is linked in the send_payment_for_bolt12_invoice
docs.
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, I just read the comment without looking at the code, I had expected a behavior change based on the comment, rather than doc changes. But doc changes are fine too :)
cb6eb2a
to
e56ac73
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.
LGTM, just a few questions and nits.
@@ -325,12 +325,18 @@ impl OnionMessageRecipient { | |||
|
|||
/// The `Responder` struct creates an appropriate [`ResponseInstruction`] | |||
/// for responding to a message. | |||
#[derive(Clone, Debug, Eq, PartialEq)] | |||
pub struct Responder { | |||
/// The path along which a response can be sent. | |||
reply_path: BlindedPath, | |||
path_id: Option<[u8; 32]> |
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'm probably missing something, but isn't path_id
a TLV field in the encrypted_data_tlv
stream? Are we positive it will always fit in 32 bytes?
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 the path_id
from the BlindedPath
that we created for receiving the message. So, currently yes though we never set it. It's only in the Responder
for logging purposes, which given the previous sentence means it's not very useful at the moment. 😛
Though that is a good point considering we are likely going to change it to a Vec
and start using it as part of #3085. I'm wondering how useful logging it really is unless we also log it when creating the blinded path, too.
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, I was wondering if it indeed is variable-length whether we should switch the type now before we actually start to serialize objects? I guess the field is TLV anyways and from a brief look it even might work out, but not entirely sure if WithoutLength
is byte identical with the [u8; 32]
serialization?
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.
@TheBlueMatt Any thoughts on where we should go with this?
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 we don't set it maybe we drop it from our logging (even if we intend to set it later)? Its not really clear to me what users have useful to do with a path_id
?
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 we want to do that we can do that in a followup PR as long as it comes before the next release, I imagine)
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.
It's useful for correlating an onion message to the blinded path it was sent over -- but only if the path_id
of the latter is actually logged, too -- and with any response to that onion message. But seeing that data encoded in the path_id
will be given to the handler in #3085, then any logging responsibility could be moved to the handler instead, if desired, and use handler-specific concepts rather than opaque bytes.
I'm not sure where that leaves Responder
. It would just a wrapper around BlindedPath
with methods for converting to a ResponseInstruction
. Those methods could be moved to BlindedPath
, but that would add an onion_message
module dependency to blinded_path
, which doesn't feel right. Maybe the wrapper is fine to keep?
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.
then any logging responsibility could be moved to the handler instead, if desired, and use handler-specific concepts rather than opaque bytes.
Right, as a user I really want this info to come to me in the form of an offer_id
or a payment_id
. path_id
is yet another token I have to correlate with something I know.
I'm not sure where that leaves Responder. It would just a wrapper around BlindedPath with methods for converting to a ResponseInstruction. Those methods could be moved to BlindedPath, but that would add an onion_message module dependency to blinded_path, which doesn't feel right. Maybe the wrapper is fine to keep?
I'd say its fine to keep the wrapper, its a separate concept. What it has internally doesn't matter too much.
lightning/src/util/config.rs
Outdated
@@ -847,6 +847,16 @@ pub struct UserConfig { | |||
/// | |||
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager | |||
pub accept_mpp_keysend: bool, | |||
/// If this is set to true, the user needs to manually pay [`Bolt12Invoice`]s when received. |
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 tick true
/false
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.
Done in a separate commit throughout this file along with other literal values. Also noticed that some of the doc formatting wasn't carrying over to the rustdocs without adding some newlines.
Looks like CI is very sad :( |
lightning/src/ln/channelmanager.rs
Outdated
/// fails or if the encoded `payment_id` is not recognized. The latter may happen once the | ||
/// payment is no longer tracked because the payment was attempted after: | ||
/// - an invoice for the `payment_id` was already paid, | ||
/// - one timer tick has elapsed since initially requesting the invoice when paying an offer, or |
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 relatively fast, won't this be an issue for fedi where we need to do another network round-trip (maybe to a mobile device) to provide the invoice?
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.
Timer ticks for ChannelManager
should be one minute. And this may actually be up to two timer ticks as implemented. So really at least one full timer tick.
rust-lightning/lightning/src/ln/outbound_payment.rs
Lines 1596 to 1608 in b8cdde8
let is_stale = match expiration { | |
StaleExpiration::AbsoluteTimeout(absolute_expiry) => { | |
*absolute_expiry <= duration_since_epoch | |
}, | |
StaleExpiration::TimerTicks(timer_ticks_remaining) => { | |
if *timer_ticks_remaining > 0 { | |
*timer_ticks_remaining -= 1; | |
false | |
} else { | |
true | |
} | |
}, | |
}; |
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 guess that seemed kinda fast to me, but maybe its fine.
e56ac73
to
5721be9
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.
LGTM
Some users may want to handle a Bolt12Invoice asynchronously, either in a different process or by first performing additional verification before paying the invoice. Add an InvoiceReceived event to facilitate this.
5721be9
to
a3def00
Compare
Went ahead and squashed the fixups. |
a3def00
to
b5ceb27
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.
We can deal with the path_id question in a followup, as long as its in the same release.
BOLT12 invoices are automatically paid once they have been verified. Users may want to manually pay them by first performing additional checks. Add a manually_handle_bolt12_invoices configuration option that when set generates an Event::InvoiceReceived instead of paying the invoice.
UserConfig::manually_handle_bolt12_invoices allows deferring payment of BOLT12 invoices by generating Event::InvoiceReceived. Expose ChannelManager::send_payment_for_bolt12_invoice to allow users to pay the Bolt12Invoice included in the event. While the event contains the PaymentId for reference, that parameter is now removed from the method in favor of extracting the PaymentId from the invoice's payer_metadata.
b5ceb27
to
97c1d65
Compare
@@ -879,6 +890,7 @@ impl Readable for UserConfig { | |||
manually_accept_inbound_channels: Readable::read(reader)?, | |||
accept_intercept_htlcs: Readable::read(reader)?, | |||
accept_mpp_keysend: Readable::read(reader)?, | |||
manually_handle_bolt12_invoices: Readable::read(reader)?, |
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 should add a TLV stream here to read from for new values...eventually. I havent spent a lot of CPU time on the current fuzzer so not any reason to do it now, but we should do it for future changes.
Users such as Fedimint would like to examine a
Bolt12Invoice
before paying it. Add aUserConfig
option for deferring payment of those invoices when received. When set, a newEvent::InvoiceReceived
is generated instead and payment can be made usingChannelManager::send_payment_for_bolt12_invoice
.