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
Add offer manager #2566
Add offer manager #2566
Conversation
d3dc04b
to
fee48ff
Compare
558ebaf
to
bcf72e0
Compare
4cc0fc0
to
e915059
Compare
0c19ff8
to
4250061
Compare
Because offers are a very generic mechanism, handling them can require interacting with an inventory system (do we actually have the quantity that the payer is requesting) or other such systems which do not have their place inside eclair. For this reason offer handlers must be implemented as plugins that communicate with the offer manager. On startup, the offer handlers must register their offers with the offer manager, the offer manager will then forward the invoice requests and blinded payments to the relevant offer handler for approval.
4250061
to
4db3e31
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.
Concept ACK on the architecture, this is going in the right direction.
eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqlitePaymentsDb.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/payment/receive/MultiPartHandler.scala
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/payment/receive/MultiPartHandler.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/offer/OfferManager.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/offer/OfferManager.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/offer/OfferManager.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/offer/OfferManager.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/offer/OfferManager.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/test/scala/fr/acinq/eclair/integration/OfferIntegrationSpec.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/payment/receive/MultiPartHandler.scala
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqlitePaymentsDb.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/message/OnionMessages.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/payment/offer/OfferManager.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/payment/offer/OfferManager.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/payment/offer/OfferManager.scala
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/payment/offer/OfferManager.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/payment/offer/OfferManager.scala
Outdated
Show resolved
Hide resolved
- remove unnecessary `Try` - rename `GetIncomingPaymentActor` commands - restore standard -> blinded failure check
…s on OnionMessages.scala
Codecov Report
📣 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 @@ Coverage Diff @@
## master #2566 +/- ##
==========================================
+ Coverage 85.50% 85.72% +0.22%
==========================================
Files 211 212 +1
Lines 16827 16992 +165
Branches 725 714 -11
==========================================
+ Hits 14388 14567 +179
+ Misses 2439 2425 -14
|
Dummy is usually used for test or invalid data, whereas here we're just storing a minimal version of the Bolt 12 invoice, so we rename it MinimalBolt12Invoice. We also add an explicit constructor for it that forces callers to provide the data we expect to store. Note that we remove the `features` field: using `nodeParams.features` could be incorrect if the invoice_request's features don't include some of our node's optional features. This is unused now anyway, but more future-proof this way.
This commit refactors the offer manager without any meaningful change in the business logic itself: - move types to a separate file to isolate codec details - make plugin data optional - add debug logs in failure cases - let plugin specify the `invoice_error` message - avoid repeated calls to `Behaviors.setup`
- split OfferManager tests - add more tests to the OfferManager - remove test duplication in MultiPartHandlerSpec - refactor BlindedPaymentSpec
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 mostly good, I've done some refactoring to improve readability and tests in #2618 and then we should be good to go.
Thank you for the refactoring. It looks very nice now. |
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 🚀 ⚡
Because offers are a very generic mechanism, handling them can require interacting with an inventory system (do we actually have the quantity that the payer is requesting) or other such systems which do not have their place inside eclair. For this reason offer handlers must be implemented as plugins that communicate with the offer manager. On startup, the offer handlers must register their offers with the offer manager, the offer manager will then forward the invoice requests and blinded payments to the relevant offer handler for approval.
Because offer invoices can be requested by any node, we do not store them in DB when they are created (which could be a DoS vector) but only when they are paid. To do that, we store some metadata about the invoice (offer id, preimage, payer id, created at, quantity, amount, features and extra data from the offer handler) in the pathId of the blinded route to use for the payment. This data is encrypted and signed by us so that it can't be forged by the payer. By default, this is not enough to fully reconstruct the invoice, so what is eventually stored in the DB once the payment succeeds does not exactly match the invoice that was sent to the payer, if that's a requirement for some use case, all of it can be put in the extra data passed by the offer handler.