Skip to content

Commit 2f8b6f4

Browse files
committed
Generate UniFFI scaffolding
We generate the scaffolding from an UDL file and include it in `lib.rs`. Furthermore, we add a bindings generation shell script for convenience.
1 parent e82b5f7 commit 2f8b6f4

File tree

7 files changed

+193
-35
lines changed

7 files changed

+193
-35
lines changed

Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ edition = "2018"
77

88
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
99

10+
[lib]
11+
crate-type = ["staticlib", "cdylib"]
12+
name = "ldk_lite"
13+
1014
[dependencies]
1115
lightning = { version = "0.0.110", features = ["max_level_trace", "std"] }
1216
lightning-invoice = { version = "0.18" }
@@ -24,7 +28,11 @@ chrono = "0.4"
2428
futures = "0.3"
2529
serde_json = { version = "1.0" }
2630
tokio = { version = "1", features = [ "io-util", "macros", "rt", "rt-multi-thread", "sync", "net", "time" ] }
31+
uniffi = { version = "0.20.0", features = ["builtin-bindgen"] }
32+
uniffi_macros = { version = "0.20.0", features = ["builtin-bindgen"] }
2733

34+
[build-dependencies]
35+
uniffi_build = "0.20.0"
2836

2937
[profile.release]
3038
panic = "abort"

build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
uniffi_build::generate_scaffolding("uniffi/ldk_lite.udl").unwrap();
3+
}

src/error.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ pub enum Error {
1212
FundingTxCreationFailed,
1313
/// A network connection has been closed.
1414
ConnectionFailed,
15+
/// The given address is invalid.
16+
AddressInvalid,
17+
/// The given public key is invalid.
18+
PublicKeyInvalid,
19+
/// The given payment hash is invalid.
20+
PaymentHashInvalid,
1521
/// Payment of the given invoice has already been intiated.
1622
NonUniquePaymentHash,
1723
/// The given invoice is invalid.
@@ -41,10 +47,11 @@ impl fmt::Display for Error {
4147
match *self {
4248
Self::AlreadyRunning => write!(f, "LDKLite is already running."),
4349
Self::NotRunning => write!(f, "LDKLite is not running."),
44-
Self::FundingTxCreationFailed => {
45-
write!(f, "Funding transaction could not be created.")
46-
}
50+
Self::FundingTxCreationFailed => write!(f, "Funding transaction could not be created."),
4751
Self::ConnectionFailed => write!(f, "Network connection closed."),
52+
Self::AddressInvalid => write!(f, "The given address is invalid."),
53+
Self::PublicKeyInvalid => write!(f, "The given public key is invalid."),
54+
Self::PaymentHashInvalid => write!(f, "The given payment hash is invalid."),
4855
Self::NonUniquePaymentHash => write!(f, "An invoice must not get payed twice."),
4956
Self::InvoiceInvalid => write!(f, "The given invoice is invalid."),
5057
Self::InvoiceCreationFailed => write!(f, "Failed to create invoice."),

src/event.rs

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ pub enum Event {
5050
// TODO: Implement after a corresponding LDK event is added.
5151
//ChannelOpened {
5252
//},
53-
/// A channel has been closed.
54-
ChannelClosed {
55-
/// The channel_id of the channel which has been closed.
56-
channel_id: [u8; 32],
57-
},
53+
///// A channel has been closed.
54+
//ChannelClosed {
55+
// /// The channel_id of the channel which has been closed.
56+
// channel_id: [u8; 32],
57+
//},
5858
// TODO: Implement on-chain events when better integrating with BDK wallet sync.
5959
//OnChainPaymentSent {
6060
//},
@@ -83,10 +83,10 @@ impl Readable for Event {
8383
//3u8 => {
8484
// TODO ChannelOpened
8585
//}
86-
4u8 => {
87-
let channel_id: [u8; 32] = Readable::read(reader)?;
88-
Ok(Self::ChannelClosed { channel_id })
89-
}
86+
//4u8 => {
87+
// let channel_id: [u8; 32] = Readable::read(reader)?;
88+
// Ok(Self::ChannelClosed { channel_id })
89+
//}
9090
//5u8 => {
9191
// TODO OnChainPaymentSent
9292
//}
@@ -116,15 +116,14 @@ impl Writeable for Event {
116116
payment_hash.write(writer)?;
117117
amount_msat.write(writer)?;
118118
Ok(())
119-
}
120-
//Self::ChannelOpened { .. } => {
121-
//TODO
122-
//}
123-
Self::ChannelClosed { channel_id } => {
124-
4u8.write(writer)?;
125-
channel_id.write(writer)?;
126-
Ok(())
127-
} //Self::OnChainPaymentSent { .. } => {
119+
} //Self::ChannelOpened { .. } => {
120+
//TODO
121+
//}
122+
//Self::ChannelClosed { channel_id } => {
123+
// 4u8.write(writer)?;
124+
// channel_id.write(writer)?;
125+
// Ok(())
126+
//} //Self::OnChainPaymentSent { .. } => {
128127
//TODO
129128
//}
130129
//Self::OnChainPaymentReceived { .. } => {
@@ -485,9 +484,9 @@ impl LdkEventHandler for EventHandler {
485484
hex_utils::to_string(channel_id),
486485
reason
487486
);
488-
self.event_queue
489-
.add_event(Event::ChannelClosed { channel_id: *channel_id })
490-
.unwrap();
487+
//self.event_queue
488+
// .add_event(Event::ChannelClosed { channel_id: *channel_id })
489+
// .unwrap();
491490
}
492491
LdkEvent::DiscardFunding { .. } => {}
493492
}

src/lib.rs

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
//! - Wallet and channel states are persisted to disk.
1818
//! - Gossip is retrieved over the P2P network.
1919
20-
#![deny(missing_docs)]
2120
#![deny(broken_intra_doc_links)]
2221
#![deny(private_intra_doc_links)]
2322
#![allow(bare_trait_objects)]
@@ -62,7 +61,7 @@ use lightning_persister::FilesystemPersister;
6261
use lightning_net_tokio::SocketDescriptor;
6362

6463
use lightning_invoice::utils::DefaultRouter;
65-
use lightning_invoice::{payment, Currency, Invoice};
64+
use lightning_invoice::{payment, Currency, Invoice, SignedRawInvoice};
6665

6766
use bdk::bitcoin::secp256k1::Secp256k1;
6867
use bdk::blockchain::esplora::EsploraBlockchain;
@@ -72,10 +71,11 @@ use bdk::template::Bip84;
7271
use bitcoin::hashes::sha256::Hash as Sha256;
7372
use bitcoin::hashes::Hash;
7473
use bitcoin::secp256k1::PublicKey;
75-
use bitcoin::BlockHash;
74+
use bitcoin::{Address, BlockHash};
7675

7776
use rand::Rng;
7877

78+
use core::str::FromStr;
7979
use std::collections::HashMap;
8080
use std::convert::TryFrom;
8181
use std::fs;
@@ -84,6 +84,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
8484
use std::sync::{Arc, Mutex, RwLock};
8585
use std::time::{Duration, Instant, SystemTime};
8686

87+
uniffi_macros::include_scaffolding!("ldk_lite");
88+
8789
// The used 'stop gap' parameter used by BDK's wallet sync. This seems to configure the threshold
8890
// number of blocks after which BDK stops looking for scripts belonging to the wallet.
8991
const BDK_CLIENT_STOP_GAP: usize = 20;
@@ -184,7 +186,7 @@ impl Builder {
184186
}
185187

186188
/// Builds an [`LdkLite`] instance according to the options previously configured.
187-
pub fn build(&self) -> LdkLite {
189+
pub fn build(&self) -> Arc<LdkLite> {
188190
let config = Arc::new(self.config.clone());
189191

190192
let ldk_data_dir = format!("{}/ldk", &config.storage_dir_path.clone());
@@ -397,7 +399,7 @@ impl Builder {
397399

398400
let running = RwLock::new(None);
399401

400-
LdkLite {
402+
Arc::new(LdkLite {
401403
running,
402404
config,
403405
chain_access,
@@ -414,7 +416,7 @@ impl Builder {
414416
inbound_payments,
415417
outbound_payments,
416418
peer_store,
417-
}
419+
})
418420
}
419421
}
420422

@@ -453,7 +455,7 @@ impl LdkLite {
453455
/// Starts the necessary background tasks, such as handling events coming from user input,
454456
/// LDK/BDK, and the peer-to-peer network. After this returns, the [`LdkLite`] instance can be
455457
/// controlled via the provided API methods in a thread-safe manner.
456-
pub fn start(&mut self) -> Result<(), Error> {
458+
pub fn start(&self) -> Result<(), Error> {
457459
// Acquire a run lock and hold it until we're setup.
458460
let mut run_lock = self.running.write().unwrap();
459461
if run_lock.is_some() {
@@ -467,7 +469,7 @@ impl LdkLite {
467469
}
468470

469471
/// Disconnects all peers, stops all running background tasks, and shuts down [`LdkLite`].
470-
pub fn stop(&mut self) -> Result<(), Error> {
472+
pub fn stop(&self) -> Result<(), Error> {
471473
let mut run_lock = self.running.write().unwrap();
472474
if run_lock.is_none() {
473475
return Err(Error::NotRunning);
@@ -638,7 +640,7 @@ impl LdkLite {
638640
}
639641

640642
/// Retrieve a new on-chain/funding address.
641-
pub fn new_funding_address(&mut self) -> Result<bitcoin::Address, Error> {
643+
pub fn new_funding_address(&self) -> Result<Address, Error> {
642644
if self.running.read().unwrap().is_none() {
643645
return Err(Error::NotRunning);
644646
}
@@ -1006,5 +1008,68 @@ pub(crate) type NetworkGraph = gossip::NetworkGraph<Arc<FilesystemLogger>>;
10061008

10071009
pub(crate) type PaymentInfoStorage = Mutex<HashMap<PaymentHash, PaymentInfo>>;
10081010

1009-
#[cfg(test)]
1010-
mod tests {}
1011+
impl UniffiCustomTypeConverter for PublicKey {
1012+
type Builtin = String;
1013+
1014+
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
1015+
if let Ok(key) = PublicKey::from_str(&val) {
1016+
return Ok(key);
1017+
}
1018+
1019+
Err(Error::PublicKeyInvalid.into())
1020+
}
1021+
1022+
fn from_custom(obj: Self) -> Self::Builtin {
1023+
obj.to_string()
1024+
}
1025+
}
1026+
1027+
impl UniffiCustomTypeConverter for Address {
1028+
type Builtin = String;
1029+
1030+
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
1031+
if let Ok(addr) = Address::from_str(&val) {
1032+
return Ok(addr);
1033+
}
1034+
1035+
Err(Error::AddressInvalid.into())
1036+
}
1037+
1038+
fn from_custom(obj: Self) -> Self::Builtin {
1039+
obj.to_string()
1040+
}
1041+
}
1042+
1043+
impl UniffiCustomTypeConverter for Invoice {
1044+
type Builtin = String;
1045+
1046+
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
1047+
if let Ok(signed) = val.parse::<SignedRawInvoice>() {
1048+
if let Ok(invoice) = Invoice::from_signed(signed) {
1049+
return Ok(invoice);
1050+
}
1051+
}
1052+
1053+
Err(Error::InvoiceInvalid.into())
1054+
}
1055+
1056+
fn from_custom(obj: Self) -> Self::Builtin {
1057+
obj.to_string()
1058+
}
1059+
}
1060+
1061+
impl UniffiCustomTypeConverter for PaymentHash {
1062+
type Builtin = String;
1063+
1064+
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
1065+
if let Ok(hash) = Sha256::from_str(&val) {
1066+
Ok(PaymentHash(hash.into_inner()))
1067+
} else {
1068+
Err(Error::PaymentHashInvalid.into())
1069+
}
1070+
}
1071+
1072+
fn from_custom(obj: Self) -> Self::Builtin {
1073+
Sha256::from_slice(&obj.0).unwrap().to_string()
1074+
}
1075+
}

uniffi/ldk_lite.udl

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
namespace ldk_lite {
2+
};
3+
4+
interface Builder {
5+
constructor();
6+
LdkLite build();
7+
};
8+
9+
interface LdkLite {
10+
[Throws=Error]
11+
void start();
12+
[Throws=Error]
13+
void stop();
14+
Event next_event();
15+
void event_handled();
16+
[Throws=Error]
17+
PublicKey my_node_id();
18+
[Throws=Error]
19+
Address new_funding_address();
20+
[Throws=Error]
21+
void connect_open_channel([ByRef]string node_pubkey_and_address, u64 channel_amount_sats, boolean announce_channel);
22+
[Throws=Error]
23+
PaymentHash send_payment(Invoice invoice);
24+
[Throws=Error]
25+
PaymentHash send_spontaneous_payment(u64 amount_msat, [ByRef]string node_id);
26+
[Throws=Error]
27+
Invoice receive_payment(u64? amount_msat, [ByRef]string description, u32 expiry_secs);
28+
// TODO: payment_info()
29+
};
30+
31+
[Error]
32+
enum Error {
33+
"AlreadyRunning",
34+
"NotRunning",
35+
"FundingTxCreationFailed",
36+
"ConnectionFailed",
37+
"AddressInvalid",
38+
"PublicKeyInvalid",
39+
"PaymentHashInvalid",
40+
"NonUniquePaymentHash",
41+
"InvoiceInvalid",
42+
"InvoiceCreationFailed",
43+
"RoutingFailed",
44+
"PeerInfoParseFailed",
45+
"ChannelCreationFailed",
46+
"ChannelClosingFailed",
47+
"PersistenceFailed",
48+
"WalletOperationFailed",
49+
"WalletSigningFailed",
50+
"ChainAccessFailed",
51+
};
52+
53+
[Enum]
54+
interface Event {
55+
PaymentSuccessful( PaymentHash payment_hash );
56+
PaymentFailed( PaymentHash payment_hash );
57+
PaymentReceived( PaymentHash payment_hash, u64 amount_msat);
58+
// TODO: ChannelClosed
59+
};
60+
61+
[Custom]
62+
typedef string PublicKey;
63+
64+
[Custom]
65+
typedef string Address;
66+
67+
[Custom]
68+
typedef string Invoice;
69+
70+
[Custom]
71+
typedef string PaymentHash;
72+

uniffi_bindgen_generate.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/bash
2+
uniffi-bindgen generate uniffi/ldk_lite.udl --language swift
3+
uniffi-bindgen generate uniffi/ldk_lite.udl --language python
4+
uniffi-bindgen generate uniffi/ldk_lite.udl --language kotlin

0 commit comments

Comments
 (0)