-
Notifications
You must be signed in to change notification settings - Fork 26
Fixing bugs & shortcomings in OfferPaymentMetadata.V1 #816
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
thomash-acinq
left a comment
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 improvement
|
Please don't merge this PR immediately, I'd like to take a look at it as well! |
We cannot do that, because we cannot store the actual invoice, otherwise we open the door to trivial DoS (this is explained in the comment on the
Correct, we initially decided to only keep one of the two fields because it's very important to limit the size of this encrypted blob: it needs to be included in the payment onion that the sender creates, which is limited to 1300 bytes. Every byte we use for this encrypted blob cannot be used by the payer to add hops in the payment route or data for routing nodes. This can potentially make payments fail because the payer doesn't have enough bytes left for the route it wants to take, which would be really bad. But I agree that it's a bad UX to silently replace the description by the payer note...to minimize the impact of that change, would it be acceptable if when both a payer note and an offer description are provided, we limit each to 32 bytes (instead of the current 64)? Good job on the flags to mark nullable fields, I think that's a very good idea, we didn't do it in the first version because we wanted to ship quickly, but definitely worth introducing now! Another improvement for the size is to stop using a signature entirely and instead simply encrypt the data: see #719 where I did this for Bolt 12 contacts (which I hope will eventually be accepted in the spec, I'm quite annoyed that we still cannot ship it). Can you change your code to use this encryption scheme instead? If you don't have time in the short term, I can spend some time on this next week and add a commit on top of your work if you prefer. |
fc34bbc to
0273874
Compare
…t-bast did in another branch.
Done in e81d0f9 I copied what you did in #719
Me too. It's a much needed improvement for the UI. |
We move the string truncation helper to `OfferPaymentMetadata` and refactor it to a simpler algorithm. We also make the following nits: - use Kotlin's built-in UTF-8 encoding instead of `ktor` - restore the previous `OfferManager` test that was unnecessarily removed - move truncation unit test to `OfferPaymentMetadataTestsCommon`
We refactor `OfferPaymentMetadata.V2` to use idiomatic Kotlin code and simplify, with the following small changes: - fix a bug in description size encoding (we must use the UTF-8 size, not the string size) and add corresponding unit test - remove unused `minLength`, this only makes sense for v1 where we don't use a `try/catch` - use `bigSize` for quantity (1 byte in almost all cases) - remove unit tests comparing v1 and v2 sizes (they were useful during prototyping to ensure that we didn't introduce a large increase, but they're not useful to continuously run)
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, I've done some refactoring and bug fixing in added commits (see commit messages for details), it's ready to go 👍, I will merge once the CI passes.
There are a few bugs in
OfferPaymentMetadata.V1. For example, say we generate an offer with the description: "Pizza 🍕":The description may end up within
OfferPaymentMetadata.V1as apayerNoter. This is incorrect:It's not a payerNote, and the UI needs to understand this. Further, if the user does add a payerNote, then the original description will be lost. Which may be important information for the user. For example, the original description may have been "Invoice #: 472648"
General idea
Optimizations
There are several optimizations we can perform to shrink the size of the encoded metadata:
quantity_opt). This saves us 8 bytes in the common case.bigSize, which shrinks the size from a fixed 8 bytes to 5 bytes (at least for another ~100 years).amount: MilliSatoshican be stored asbigSize, which shrinks the size from a fixed 8 bytes, to an average of 5 bytes. It only uses more bytes if the payment amount is over ~0.043 BTC, and most payments are under this amount.The end result is that V2 is smaller than V1.
Future-proofing
I'm experimenting in another branch (
card-payment), and I need to create a Bolt12Invoice that expires in 30 seconds. But that's wasn't possible, because therelativeExpirywasn't stored inOfferPaymentMetadata.V1, and the default value was hard-coded. So I fixed that issue.Also in the branch, I'm experimenting with creating an "unsolicited Bolt 12 invoice". That is, a Bolt 12 Invoice that is generated not in response to an InvoiceRequest, but due to an attempted card payment. As such, it does not have a
payerKey. So I've made that field optional in V2.Note: Making it optional takes up no extra bytes.
Alternative implementations
This PR fixes all the issues I have with V1, but it may not be the ideal solution. Ultimately, one of the core issues I see is that, while
LightningOutgoingPaymentstores the fullBolt12Invoice,Bolt12IncomingPaymentonly stores theOfferPaymentMetadata.Perhaps the ideal solution would be:
Bolt12IncomingPaymentstore the fullBolt12InvoiceOfferPaymentMetadatato be simply a signature over a subset of theoffer_*&invoice_*fields. And verify the sig when receiving the payment part(s).However... that's a very big change. Implementing it will take a lot of effort. And we're all busy with other big changes at the moment. So in the meantime, I'm proposing the minor changes in V2.