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

Refactor and modularize payment APIs #270

Merged
merged 7 commits into from
May 15, 2024

Conversation

tnull
Copy link
Collaborator

@tnull tnull commented Mar 5, 2024

Based on #243.
Based on #244.
Based on #266.

Another prefactor to #193, splitting this out to reduce rebase pain, e.g., with #141.

As we're about to introduce a bunch more payment API methods for BOLT12 support, we first clean up and declutter our payment APIs so far.

What previously were individual methods on Node we now move to individual PaymentHandlers:

  • Bolt11PaymentHandler
  • SpontaneousPaymentHandler
  • OnchainPaymentHandler

While we're at it, we slightly remove the API methods to shorten them, allowing to call them like so:

	let invoice = Bolt11Invoice::from_str("INVOICE_STR").unwrap();
	node.bolt11_payment().send(&invoice).unwrap();

Additionally, we move PaymentStore to a sub-module of crate::payment to clean up our top-level docs a bit.

@tnull tnull requested a review from jkczyz March 5, 2024 13:55
@tnull tnull changed the title Refactor payment APIs Refactor and modularize payment APIs Mar 5, 2024
@tnull tnull force-pushed the 2024-03-payment-api-refactor branch 2 times, most recently from accd010 to 9c30bd1 Compare March 5, 2024 14:09
@tnull
Copy link
Collaborator Author

tnull commented Mar 5, 2024

@jkczyz Any thoughts on the naming here? I'm a bit on the fence if we should just drop the Handler suffix, but then again a type like Bolt11Payment would indicate that it represents a single payment, not a handler with which to send and receive such. Previously also had it as a plural, i.e., Bolt11PaymentsHandler, but that sounds strange in my head even though it seems to make more sense?

@tnull tnull force-pushed the 2024-03-payment-api-refactor branch from 9c30bd1 to 2c663c7 Compare March 5, 2024 14:21
@jkczyz
Copy link
Contributor

jkczyz commented Mar 5, 2024

@jkczyz Any thoughts on the naming here? I'm a bit on the fence if we should just drop the Handler suffix, but then again a type like Bolt11Payment would indicate that it represents a single payment, not a handler with which to send and receive such.

How about Bolt11InvoicePayer? I guess that wouldn't work for receiving though.

Might be better to not be specific to protocol, FWIW. Rather just have a Payments struct used for sending any type of payment and for listing/retrieving/removing payments as well.

Previously also had it as a plural, i.e., Bolt11PaymentsHandler, but that sounds strange in my head even though it seems to make more sense?

My rule of thumb is to not use plurals in prefixes. Thus, EventHandler instead of EventsHandler. In LDK, I would have renamed EventsProvider as EventProvider even though the interface is named in terms of events.

@tnull
Copy link
Collaborator Author

tnull commented Mar 5, 2024

How about Bolt11InvoicePayer? I guess that wouldn't work for receiving though.

Hmm, indeed that doesn't work for the receiving part.

Might be better to not be specific to protocol, FWIW. Rather just have a Payments struct used for sending any type of payment and for listing/retrieving/removing payments as well.

I'm not sure: the API surface of covering all possible payment variations is rather large already, we're about to add substantially to it with BOLT12, and we eventually will also need to add, e.g., BOLT12 JIT variations. I think we eventually also want to provide helpers to generate and pay more unified interface (e.g., unified QR code, DNS payment addresses), but I'm not seeing how we can avoid the API getting a bit unwieldy if all variations keep living on a single object?

My rule of thumb is to not use plurals in prefixes. Thus, EventHandler instead of EventsHandler. In LDK, I would have renamed EventsProvider as EventProvider even though the interface is named in terms of events.

Yeah, seems we're on the same page here.

@jkczyz
Copy link
Contributor

jkczyz commented Mar 5, 2024

I'm not sure: the API surface of covering all possible payment variations is rather large already, we're about to add substantially to it with BOLT12, and we eventually will also need to add, e.g., BOLT12 JIT variations. I think we eventually also want to provide helpers to generate and pay more unified interface (e.g., unified QR code, DNS payment addresses), but I'm not seeing how we can avoid the API getting a bit unwieldy if all variations keep living on a single object?

Maybe Bolt11Protocol? Though I'm a bit more inclined to use Bolt11Payment to align with the others. If you have the methods take self by value, then it really would be only one payment. Not sure how nice that works with bindings, however.

Another idea would be to divide by inbound and outbound instead of by protocol / mechanism.

@tnull
Copy link
Collaborator Author

tnull commented Mar 5, 2024

Maybe Bolt11Protocol? Though I'm a bit more inclined to use Bolt11Payment to align with the others. If you have the methods take self by value, then it really would be only one payment. Not sure how nice that works with bindings, however.

You mean the Node::X_payment methods? No, for one we of course can't consume Node, but in bindings we can only return Arcs and never use self/&mut self. I'll however see to store/cache the corresponding Arcs in Node itself to reduce the number of clones on each call. I might also explore whether we can return a reference rather than an Arc in Rust, although I'm not entirely sure if that makes much of a difference.

@jkczyz
Copy link
Contributor

jkczyz commented Mar 5, 2024

You mean the Node::X_payment methods? No, for one we of course can't consume Node, but in bindings we can only return Arcs and never use self/&mut self. I'll however see to store/cache the corresponding Arcs in Node itself to reduce the number of clones on each call. I might also explore whether we can return a reference rather than an Arc in Rust, although I'm not entirely sure if that makes much of a difference.

Not the methods on Node but rather the methods on Bolt11Payment. But, right, I didn't notice that bolt11_payment returns an Arc. Why can't it return Bolt11Payment by value? Shouldn't need a reference if they are to be used per-payment.

@tnull tnull force-pushed the 2024-03-payment-api-refactor branch 2 times, most recently from ce13e42 to 966d982 Compare March 7, 2024 12:10
@tnull
Copy link
Collaborator Author

tnull commented Mar 7, 2024

Not the methods on Node but rather the methods on Bolt11Payment. But, right, I didn't notice that bolt11_payment returns an Arc. Why can't it return Bolt11Payment by value? Shouldn't need a reference if they are to be used per-payment.

So self or &mut self methods are generally impossible to expose in bindings as they require interior mutability. That said, we can return Bolt11PaymentHandler by value, I now added fixup commits that switch the interface to theArced versions based on the uniffi feature.

I also included fixups to rename the PaymentHandlers to Payments, even though I'm still a bit on the fence regarding naming. At least these variants are more succinct.

@tnull tnull force-pushed the 2024-03-payment-api-refactor branch 2 times, most recently from 605e637 to 3eb14c8 Compare March 7, 2024 12:54
@tnull tnull mentioned this pull request Mar 7, 2024
@tnull tnull force-pushed the 2024-03-payment-api-refactor branch from 3eb14c8 to 6536516 Compare March 8, 2024 07:59
@tnull
Copy link
Collaborator Author

tnull commented Mar 8, 2024

Rebased to resolve minor conflicts.

@tnull
Copy link
Collaborator Author

tnull commented Mar 8, 2024

Now added two commits introducing a PaymentKind to PaymentStore and creating a separate kind for Bolt11Jit, which can hold the lsp_fee_limits as they are only required in this kind.

@tnull tnull force-pushed the 2024-03-payment-api-refactor branch 7 times, most recently from f198172 to 4884b82 Compare March 11, 2024 14:38
@tnull tnull force-pushed the 2024-03-payment-api-refactor branch 4 times, most recently from 54e94c2 to c798308 Compare March 12, 2024 12:17
@tnull tnull force-pushed the 2024-03-payment-api-refactor branch from c798308 to 28476cb Compare April 25, 2024 18:43
@tnull
Copy link
Collaborator Author

tnull commented Apr 25, 2024

Rebased on main.

@tnull tnull force-pushed the 2024-03-payment-api-refactor branch 3 times, most recently from f79d486 to 5b56978 Compare May 13, 2024 17:03
Copy link
Contributor

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No major concerns left.

src/payment/bolt11.rs Outdated Show resolved Hide resolved
@@ -82,6 +137,73 @@ impl_writeable_tlv_based_enum!(PaymentStatus,
(4, Failed) => {};
);

/// Represents the kind of a payment.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PaymentKind {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we name this PaymentPurpose for a closer mapping to LDK?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, tbh, I find the 'Purpose' part a bit of a misnomer? And, given this is not actually the same object, shadowing the name might be misleading?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No strong opinion. Though I wonder if "kind" is just another way of saying "type". I'm a little more inclined with using the latter, but happy to defer to you here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I think I also started out with PaymentType but then discovered that it would result in a shorthand type (e.g., as the field name in PaymentDetails where we omit the payment_ prefix), which of course doesn't work as type is a keyword. Rather than entering r#type territory, I just omitted the issue alltogether by switching to PaymentKind. So, generally I agree PaymentType seems a bit more natural, but that would mean we'd need to rename the PaymentDetails fields, and it's probably not worth?

src/payment/bolt11.rs Outdated Show resolved Hide resolved
src/payment/payment_store.rs Outdated Show resolved Hide resolved
src/payment/payment_store.rs Outdated Show resolved Hide resolved
@tnull tnull force-pushed the 2024-03-payment-api-refactor branch from 5b56978 to 07acb44 Compare May 14, 2024 07:21
Copy link
Contributor

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Please squash

tnull added 4 commits May 15, 2024 15:09
.. which declutters our top-level docs a bit.
.. as we changed quite a bit and moved required fields, we add a test
here that adds the old `PaymentDetails` as a test struct and ensures
we're able to parse them just fine
@tnull tnull force-pushed the 2024-03-payment-api-refactor branch from 07acb44 to 1fab656 Compare May 15, 2024 13:09
@tnull
Copy link
Collaborator Author

tnull commented May 15, 2024

LGTM. Please squash

Squashed without further changes.

@tnull tnull merged commit b7c4862 into lightningdevkit:main May 15, 2024
13 checks passed
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