-
Notifications
You must be signed in to change notification settings - Fork 109
Feature: Add Bolt12 Uniffi Type Wrappers #542
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
base: main
Are you sure you want to change the base?
Feature: Add Bolt12 Uniffi Type Wrappers #542
Conversation
👋 Thanks for assigning @enigbe as a reviewer! |
src/uniffi_conversions.rs
Outdated
match LdkBolt11InvoiceDescription::try_from(self) { | ||
Ok(ldk_description) => ldk_description, | ||
Err(e) => { | ||
panic!("Failed to convert Bolt11InvoiceDescription to LDK type: {:?}", e) |
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 a fan of this myself. We could refactor the Bolt11InvoiceDescription to be a struct that holds the LdkType in an inner
field (similar to what we did to other types) to make this conversion safer. Looking for advice on whether it's worth introducing a breaking change for 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.
Hmm, indeed, if we're going to unify the conversions, it would make sense to align LdkBolt11InvoiceDescription
. Generally, we're still on 0.X, so don't care about breaking API all too much. It's much more important to add features and figure out the best API over time at this point.
But do you think LdkBolt11InvoiceDescription
would even work as expected?
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 would work differently. I was thinking something like this:
pub struct Bolt11InvoiceDescription {
inner: lightning_invoice::Bolt11InvoiceDescription,
}
impl Bolt11InvoiceDescription {
pub fn direct_description(&self) -> Option<String> {
match &self.inner {
lightning_invoice::Bolt11InvoiceDescription::Direct(description) => {
Some(description.to_string())
},
_ => None,
}
}
pub fn hash(&self) -> Option<String> {
match &self.inner {
lightning_invoice::Bolt11InvoiceDescription::Hash(hash) => {
Some(hex_utils::to_string(hash.0.as_ref()))
},
_ => None,
}
}
}
Not ideal, because as you say it works differently, but safe. What do you think?
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.
Mhh, but is something stopping us from splitting this up in UnffiConversionType
and UniffiFallibleConversionType
, where the latter would have a maybe_try_convert(value: &T, error: Error)
method that would return and bubble up that error if conversion fails?
FWIW, we could even have them inherit all the other behavior from UniffiType
, i.e.
trait UniffiConversionType: UniffiType
or similar, no?
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.
Deviated from your suggestion, but think I have something neat - let me know what you think! Thanks for the pointer.
f07aa51
to
e85a185
Compare
e85a185
to
7188bca
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.
Thanks, already looks pretty good! Did a first higher-level pass.
src/uniffi_conversions.rs
Outdated
match LdkBolt11InvoiceDescription::try_from(self) { | ||
Ok(ldk_description) => ldk_description, | ||
Err(e) => { | ||
panic!("Failed to convert Bolt11InvoiceDescription to LDK type: {:?}", e) |
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.
Hmm, indeed, if we're going to unify the conversions, it would make sense to align LdkBolt11InvoiceDescription
. Generally, we're still on 0.X, so don't care about breaking API all too much. It's much more important to add features and figure out the best API over time at this point.
But do you think LdkBolt11InvoiceDescription
would even work as expected?
7188bca
to
2f3bc2e
Compare
2f3bc2e
to
670a885
Compare
src/uniffi_types.rs
Outdated
} | ||
} | ||
|
||
impl std::str::FromStr for Bolt12Invoice { |
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.
Hmm, I think we should wait for the resolution of the discussion over at lightningdevkit/rust-lightning#3800 before we do this and roll our own custom 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.
Hmm, AFAICT the resolution was to use the wire format for now. I'm not super happy about that, but okay.
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.
Mmh, so what does this mean for us? We need to implement Writable and Readable for Bolt12Invoice?
src/uniffi_conversions.rs
Outdated
match LdkBolt11InvoiceDescription::try_from(self) { | ||
Ok(ldk_description) => ldk_description, | ||
Err(e) => { | ||
panic!("Failed to convert Bolt11InvoiceDescription to LDK type: {:?}", e) |
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.
Mhh, but is something stopping us from splitting this up in UnffiConversionType
and UniffiFallibleConversionType
, where the latter would have a maybe_try_convert(value: &T, error: Error)
method that would return and bubble up that error if conversion fails?
FWIW, we could even have them inherit all the other behavior from UniffiType
, i.e.
trait UniffiConversionType: UniffiType
or similar, no?
670a885
to
2894d87
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.
Cool, I like the proposed approach. Very clean!
Just a few comments.
@@ -50,6 +51,20 @@ mod uniffi_impl { | |||
} | |||
} | |||
|
|||
impl UniffiType for Arc<Offer> { |
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.
Why are we implementing this on Arc<Offer>
, not on Offer
? I think we should do the latter if possible.
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.
Thanks for this!
Initially, I implemented these on the Arc
s because that's how they are required to pass the ffi boundary. I looked into it again and now have a solution that Arc-allocates/-extracts the types in the conversion functions (i.e. maybe_convert
, maybe_wrap
etc.) and only does type conversion on the implementation methods. The benefit is that we can use standard traits and remove ffi/conversions.rs
entirely. Downside is that the conversion functions become slightly more complex.
I have implemented these changes on alexanderwiederin@6b5f297 for better comparison.
What do you think?
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 a lot less invasive. However, there seem to be a few cases where we add unnecessary clones
now that could lead to addtional memory usage and heap fragmentation. Can we avoid cloning when not necessary, and also enforce in the types of maybe_convert
etc, that we'd always use Arc::clone(&..)
, ie., that we'd only ever clone the reference, and otherwise would maintain noops or move semantics?
@@ -65,6 +65,20 @@ mod uniffi_impl { | |||
} | |||
} | |||
|
|||
impl UniffiType for Arc<Refund> { |
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.
Same here, can we implement this rather for Refund
directly?
This commit reorganizes the FFI architecture by introducing conversion traits for lightning types. Moves code from uniffi_types.rs to a dedicated ffi module for separation of concerns.
Implement Offer struct in ffi/types.rs to provide a wrapper around LDK's Offer for cross-language bindings. Modified payment handling in bolt12.rs to: - Support both native and FFI-compatible types via type aliasing - Implement conditional compilation for transparent FFI support - Update payment functions to handle wrapped types Added testing to verify that properties are preserved when wrapping/unwrapping between native and FFI types.
Implement Refund struct in ffi/types.rs to provide a wrapper around LDK's Refund for cross-language bindings. Modified payment handling in bolt12.rs to: - Support both native and FFI-compatible types via type aliasing - Implement conditional compilation for transparent FFI support - Update payment functions to handle wrapped types Added testing to verify that properties are preserved when wrapping/unwrapping between native and FFI types.
Implement Bolt12Invoice struct in ffi/types.rs to provide a wrapper around LDK's Bolt12Invoice for cross-language bindings. Modified payment handling in bolt12.rs to: - Support both native and FFI-compatible types via type aliasing - Implement conditional compilation for transparent FFI support - Update payment functions to handle wrapped types Added testing to verify that properties are preserved when wrapping/unwrapping between native and FFI types.
2894d87
to
3126d86
Compare
🔔 1st Reminder Hey @enigbe! This PR has been waiting for your review. |
Second PR for #504.
This PR adds full Offer-, Refund- and Bolt12Invoice- types for the FFI bindings.
Changes:
ldk_node.udl
anduniffi_types.rs
uniffi_conversions.rs
bolt12.rs
andunified_qr.rs
Benefits:
Note:
Appreciate that this PR is big. Happy to break down into smaller parts if preferred.