Skip to content

Commit 45c7724

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 a68fa60 commit 45c7724

File tree

7 files changed

+244
-28
lines changed

7 files changed

+244
-28
lines changed

Cargo.toml

Lines changed: 9 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.112", features = ["max_level_trace", "std"] }
1216
#lightning-invoice = { version = "0.20" }
@@ -46,13 +50,18 @@ chrono = "0.4"
4650
futures = "0.3"
4751
serde_json = { version = "1.0" }
4852
tokio = { version = "1", features = [ "full" ] }
53+
uniffi = { version = "0.21.0", features = ["builtin-bindgen"] }
54+
uniffi_macros = { version = "0.21.0", features = ["builtin-bindgen"] }
4955

5056
[dev-dependencies]
5157
electrsd = { version = "0.22.0", features = ["legacy", "esplora_a33e97e1", "bitcoind_23_0"] }
5258
electrum-client = "0.12.0"
5359
lazy_static = "1.4.0"
5460
once_cell = "1.16.0"
5561

62+
[build-dependencies]
63+
uniffi_build = "0.21.0"
64+
5665
[profile.release]
5766
panic = "abort"
5867

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: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,20 @@ pub enum Error {
1111
FundingTxCreationFailed,
1212
/// A network connection has been closed.
1313
ConnectionFailed,
14+
/// The given address is invalid.
15+
AddressInvalid,
16+
/// The given public key is invalid.
17+
PublicKeyInvalid,
18+
/// The given payment hash is invalid.
19+
PaymentHashInvalid,
1420
/// Payment of the given invoice has already been intiated.
1521
NonUniquePaymentHash,
1622
/// The given invoice is invalid.
1723
InvoiceInvalid,
1824
/// Invoice creation failed.
1925
InvoiceCreationFailed,
26+
/// The given channel ID is invalid.
27+
ChannelIdInvalid,
2028
/// No route for the given target could be found.
2129
RoutingFailed,
2230
/// A given peer info could not be parsed.
@@ -40,13 +48,15 @@ impl fmt::Display for Error {
4048
match *self {
4149
Self::AlreadyRunning => write!(f, "LDKLite is already running."),
4250
Self::NotRunning => write!(f, "LDKLite is not running."),
43-
Self::FundingTxCreationFailed => {
44-
write!(f, "Funding transaction could not be created.")
45-
}
51+
Self::FundingTxCreationFailed => write!(f, "Funding transaction could not be created."),
4652
Self::ConnectionFailed => write!(f, "Network connection closed."),
53+
Self::AddressInvalid => write!(f, "The given address is invalid."),
54+
Self::PublicKeyInvalid => write!(f, "The given public key is invalid."),
55+
Self::PaymentHashInvalid => write!(f, "The given payment hash is invalid."),
4756
Self::NonUniquePaymentHash => write!(f, "An invoice must not get payed twice."),
4857
Self::InvoiceInvalid => write!(f, "The given invoice is invalid."),
4958
Self::InvoiceCreationFailed => write!(f, "Failed to create invoice."),
59+
Self::ChannelIdInvalid => write!(f, "The given channel ID is invalid."),
5060
Self::RoutingFailed => write!(f, "Failed to find route."),
5161
Self::PeerInfoParseFailed => write!(f, "Failed to parse the given peer information."),
5262
Self::ChannelCreationFailed => write!(f, "Failed to create channel."),

src/event.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
2-
hex_utils, ChannelManager, Config, Error, NetworkGraph, PaymentInfo, PaymentInfoStorage,
3-
PaymentStatus, Wallet,
2+
hex_utils, ChannelId, ChannelManager, Config, Error, NetworkGraph, PaymentInfo,
3+
PaymentInfoStorage, PaymentStatus, UserChannelId, Wallet,
44
};
55

66
use crate::logger::{log_error, log_given_level, log_info, log_internal, Logger};
@@ -50,16 +50,16 @@ pub enum Event {
5050
/// A channel is ready to be used.
5151
ChannelReady {
5252
/// The `channel_id` of the channel.
53-
channel_id: [u8; 32],
53+
channel_id: ChannelId,
5454
/// The `user_channel_id` of the channel.
55-
user_channel_id: u128,
55+
user_channel_id: UserChannelId,
5656
},
5757
/// A channel has been closed.
5858
ChannelClosed {
5959
/// The `channel_id` of the channel.
60-
channel_id: [u8; 32],
60+
channel_id: ChannelId,
6161
/// The `user_channel_id` of the channel.
62-
user_channel_id: u128,
62+
user_channel_id: UserChannelId,
6363
},
6464
}
6565

@@ -83,13 +83,13 @@ impl Readable for Event {
8383
Ok(Self::PaymentReceived { payment_hash, amount_msat })
8484
}
8585
3u8 => {
86-
let channel_id: [u8; 32] = Readable::read(reader)?;
87-
let user_channel_id: u128 = Readable::read(reader)?;
86+
let channel_id = ChannelId(Readable::read(reader)?);
87+
let user_channel_id = UserChannelId(Readable::read(reader)?);
8888
Ok(Self::ChannelReady { channel_id, user_channel_id })
8989
}
9090
4u8 => {
91-
let channel_id: [u8; 32] = Readable::read(reader)?;
92-
let user_channel_id: u128 = Readable::read(reader)?;
91+
let channel_id = ChannelId(Readable::read(reader)?);
92+
let user_channel_id = UserChannelId(Readable::read(reader)?);
9393
Ok(Self::ChannelClosed { channel_id, user_channel_id })
9494
}
9595
_ => Err(lightning::ln::msgs::DecodeError::InvalidValue),
@@ -118,14 +118,14 @@ impl Writeable for Event {
118118
}
119119
Self::ChannelReady { channel_id, user_channel_id } => {
120120
3u8.write(writer)?;
121-
channel_id.write(writer)?;
122-
user_channel_id.write(writer)?;
121+
channel_id.0.write(writer)?;
122+
user_channel_id.0.write(writer)?;
123123
Ok(())
124124
}
125125
Self::ChannelClosed { channel_id, user_channel_id } => {
126126
4u8.write(writer)?;
127-
channel_id.write(writer)?;
128-
user_channel_id.write(writer)?;
127+
channel_id.0.write(writer)?;
128+
user_channel_id.0.write(writer)?;
129129
Ok(())
130130
}
131131
}
@@ -559,7 +559,10 @@ where
559559
counterparty_node_id,
560560
);
561561
self.event_queue
562-
.add_event(Event::ChannelReady { channel_id, user_channel_id })
562+
.add_event(Event::ChannelReady {
563+
channel_id: ChannelId(channel_id),
564+
user_channel_id: UserChannelId(user_channel_id),
565+
})
563566
.expect("Failed to push to event queue");
564567
}
565568
LdkEvent::ChannelClosed { channel_id, reason, user_channel_id } => {
@@ -570,7 +573,10 @@ where
570573
reason
571574
);
572575
self.event_queue
573-
.add_event(Event::ChannelClosed { channel_id, user_channel_id })
576+
.add_event(Event::ChannelClosed {
577+
channel_id: ChannelId(channel_id),
578+
user_channel_id: UserChannelId(user_channel_id),
579+
})
574580
.expect("Failed to push to event queue");
575581
}
576582
LdkEvent::DiscardFunding { .. } => {}

src/lib.rs

Lines changed: 114 additions & 9 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)]
@@ -67,7 +66,7 @@ use lightning_transaction_sync::EsploraSyncClient;
6766
use lightning_net_tokio::SocketDescriptor;
6867

6968
use lightning::routing::router::DefaultRouter;
70-
use lightning_invoice::{payment, Currency, Invoice};
69+
use lightning_invoice::{payment, Currency, Invoice, SignedRawInvoice};
7170

7271
use bdk::bitcoin::secp256k1::Secp256k1;
7372
use bdk::blockchain::esplora::EsploraBlockchain;
@@ -77,10 +76,11 @@ use bdk::template::Bip84;
7776
use bitcoin::hashes::sha256::Hash as Sha256;
7877
use bitcoin::hashes::Hash;
7978
use bitcoin::secp256k1::PublicKey;
80-
use bitcoin::BlockHash;
79+
use bitcoin::{Address, BlockHash};
8180

8281
use rand::Rng;
8382

83+
use core::str::FromStr;
8484
use std::collections::HashMap;
8585
use std::convert::{TryFrom, TryInto};
8686
use std::default::Default;
@@ -90,6 +90,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
9090
use std::sync::{Arc, Mutex, RwLock};
9191
use std::time::{Duration, Instant, SystemTime};
9292

93+
uniffi_macros::include_scaffolding!("ldk_lite");
94+
9395
// The used 'stop gap' parameter used by BDK's wallet sync. This seems to configure the threshold
9496
// number of blocks after which BDK stops looking for scripts belonging to the wallet.
9597
const BDK_CLIENT_STOP_GAP: usize = 20;
@@ -197,7 +199,7 @@ impl Builder {
197199
}
198200

199201
/// Builds an [`LdkLite`] instance according to the options previously configured.
200-
pub fn build(&self) -> LdkLite {
202+
pub fn build(&self) -> Arc<LdkLite> {
201203
let config = Arc::new(self.config.clone());
202204

203205
let ldk_data_dir = format!("{}/ldk", &config.storage_dir_path.clone());
@@ -426,7 +428,7 @@ impl Builder {
426428

427429
let running = RwLock::new(None);
428430

429-
LdkLite {
431+
Arc::new(LdkLite {
430432
running,
431433
config,
432434
wallet,
@@ -445,7 +447,7 @@ impl Builder {
445447
inbound_payments,
446448
outbound_payments,
447449
peer_store,
448-
}
450+
})
449451
}
450452
}
451453

@@ -487,7 +489,7 @@ impl LdkLite {
487489
/// Starts the necessary background tasks, such as handling events coming from user input,
488490
/// LDK/BDK, and the peer-to-peer network. After this returns, the [`LdkLite`] instance can be
489491
/// controlled via the provided API methods in a thread-safe manner.
490-
pub fn start(&mut self) -> Result<(), Error> {
492+
pub fn start(&self) -> Result<(), Error> {
491493
// Acquire a run lock and hold it until we're setup.
492494
let mut run_lock = self.running.write().unwrap();
493495
if run_lock.is_some() {
@@ -501,7 +503,7 @@ impl LdkLite {
501503
}
502504

503505
/// Disconnects all peers, stops all running background tasks, and shuts down [`LdkLite`].
504-
pub fn stop(&mut self) -> Result<(), Error> {
506+
pub fn stop(&self) -> Result<(), Error> {
505507
let mut run_lock = self.running.write().unwrap();
506508
if run_lock.is_none() {
507509
return Err(Error::NotRunning);
@@ -695,7 +697,7 @@ impl LdkLite {
695697
}
696698

697699
/// Retrieve a new on-chain/funding address.
698-
pub fn new_funding_address(&mut self) -> Result<bitcoin::Address, Error> {
700+
pub fn new_funding_address(&self) -> Result<Address, Error> {
699701
let funding_address = self.wallet.get_new_address()?;
700702
log_info!(self.logger, "Generated new funding address: {}", funding_address);
701703
Ok(funding_address)
@@ -1086,3 +1088,106 @@ pub(crate) type NetworkGraph = gossip::NetworkGraph<Arc<FilesystemLogger>>;
10861088
pub(crate) type PaymentInfoStorage = Mutex<HashMap<PaymentHash, PaymentInfo>>;
10871089

10881090
pub(crate) type OnionMessenger = SimpleArcOnionMessenger<FilesystemLogger>;
1091+
1092+
impl UniffiCustomTypeConverter for PublicKey {
1093+
type Builtin = String;
1094+
1095+
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
1096+
if let Ok(key) = PublicKey::from_str(&val) {
1097+
return Ok(key);
1098+
}
1099+
1100+
Err(Error::PublicKeyInvalid.into())
1101+
}
1102+
1103+
fn from_custom(obj: Self) -> Self::Builtin {
1104+
obj.to_string()
1105+
}
1106+
}
1107+
1108+
impl UniffiCustomTypeConverter for Address {
1109+
type Builtin = String;
1110+
1111+
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
1112+
if let Ok(addr) = Address::from_str(&val) {
1113+
return Ok(addr);
1114+
}
1115+
1116+
Err(Error::AddressInvalid.into())
1117+
}
1118+
1119+
fn from_custom(obj: Self) -> Self::Builtin {
1120+
obj.to_string()
1121+
}
1122+
}
1123+
1124+
impl UniffiCustomTypeConverter for Invoice {
1125+
type Builtin = String;
1126+
1127+
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
1128+
if let Ok(signed) = val.parse::<SignedRawInvoice>() {
1129+
if let Ok(invoice) = Invoice::from_signed(signed) {
1130+
return Ok(invoice);
1131+
}
1132+
}
1133+
1134+
Err(Error::InvoiceInvalid.into())
1135+
}
1136+
1137+
fn from_custom(obj: Self) -> Self::Builtin {
1138+
obj.to_string()
1139+
}
1140+
}
1141+
1142+
impl UniffiCustomTypeConverter for PaymentHash {
1143+
type Builtin = String;
1144+
1145+
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
1146+
if let Ok(hash) = Sha256::from_str(&val) {
1147+
Ok(PaymentHash(hash.into_inner()))
1148+
} else {
1149+
Err(Error::PaymentHashInvalid.into())
1150+
}
1151+
}
1152+
1153+
fn from_custom(obj: Self) -> Self::Builtin {
1154+
Sha256::from_slice(&obj.0).unwrap().to_string()
1155+
}
1156+
}
1157+
1158+
#[derive(Debug, Clone, PartialEq)]
1159+
pub struct ChannelId([u8; 32]);
1160+
1161+
impl UniffiCustomTypeConverter for ChannelId {
1162+
type Builtin = String;
1163+
1164+
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
1165+
if let Some(hex_vec) = hex_utils::to_vec(&val) {
1166+
if hex_vec.len() == 32 {
1167+
let mut channel_id = [0u8; 32];
1168+
channel_id.copy_from_slice(&hex_vec[..]);
1169+
return Ok(Self(channel_id));
1170+
}
1171+
}
1172+
Err(Error::ChannelIdInvalid.into())
1173+
}
1174+
1175+
fn from_custom(obj: Self) -> Self::Builtin {
1176+
hex_utils::to_string(&obj.0)
1177+
}
1178+
}
1179+
1180+
#[derive(Debug, Clone, PartialEq)]
1181+
pub struct UserChannelId(u128);
1182+
1183+
impl UniffiCustomTypeConverter for UserChannelId {
1184+
type Builtin = String;
1185+
1186+
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
1187+
Ok(UserChannelId(u128::from_str(&val).map_err(|_| Error::ChannelIdInvalid)?))
1188+
}
1189+
1190+
fn from_custom(obj: Self) -> Self::Builtin {
1191+
obj.0.to_string()
1192+
}
1193+
}

0 commit comments

Comments
 (0)