Skip to content

Commit 8481816

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 303e0ee commit 8481816

File tree

8 files changed

+261
-37
lines changed

8 files changed

+261
-37
lines changed

Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ description = "A ready-to-go node implementation based on LDK."
88

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

11+
[lib]
12+
crate-type = ["staticlib", "cdylib"]
13+
name = "ldk_node"
14+
1115
[dependencies]
1216
#lightning = { version = "0.0.112", features = ["max_level_trace", "std"] }
1317
#lightning-invoice = { version = "0.20" }
@@ -47,12 +51,17 @@ chrono = "0.4"
4751
futures = "0.3"
4852
serde_json = { version = "1.0" }
4953
tokio = { version = "1", features = [ "full" ] }
54+
uniffi = { version = "0.21.0", features = ["builtin-bindgen"] }
55+
uniffi_macros = { version = "0.21.0", features = ["builtin-bindgen"] }
5056

5157
[dev-dependencies]
5258
electrsd = { version = "0.22.0", features = ["legacy", "esplora_a33e97e1", "bitcoind_23_0"] }
5359
electrum-client = "0.12.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_node.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, "Node is already running."),
4250
Self::NotRunning => write!(f, "Node 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: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
2-
hex_utils, ChannelManager, Config, Error, KeysManager, NetworkGraph, PaymentInfo,
3-
PaymentInfoStorage, PaymentStatus, Wallet,
2+
hex_utils, ChannelId, ChannelManager, Config, Error, KeysManager, 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
}
@@ -576,7 +576,10 @@ where
576576
counterparty_node_id,
577577
);
578578
self.event_queue
579-
.add_event(Event::ChannelReady { channel_id, user_channel_id })
579+
.add_event(Event::ChannelReady {
580+
channel_id: ChannelId(channel_id),
581+
user_channel_id: UserChannelId(user_channel_id),
582+
})
580583
.expect("Failed to push to event queue");
581584
}
582585
LdkEvent::ChannelClosed { channel_id, reason, user_channel_id } => {
@@ -587,7 +590,10 @@ where
587590
reason
588591
);
589592
self.event_queue
590-
.add_event(Event::ChannelClosed { channel_id, user_channel_id })
593+
.add_event(Event::ChannelClosed {
594+
channel_id: ChannelId(channel_id),
595+
user_channel_id: UserChannelId(user_channel_id),
596+
})
591597
.expect("Failed to push to event queue");
592598
}
593599
LdkEvent::DiscardFunding { .. } => {}
@@ -606,7 +612,10 @@ mod tests {
606612
let test_persister = Arc::new(TestPersister::new());
607613
let event_queue = EventQueue::new(Arc::clone(&test_persister));
608614

609-
let expected_event = Event::ChannelReady { channel_id: [23u8; 32], user_channel_id: 2323 };
615+
let expected_event = Event::ChannelReady {
616+
channel_id: ChannelId([23u8; 32]),
617+
user_channel_id: UserChannelId(2323),
618+
};
610619
event_queue.add_event(expected_event.clone()).unwrap();
611620
assert!(test_persister.get_and_clear_pending_persist());
612621

src/lib.rs

Lines changed: 118 additions & 12 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)]
@@ -34,7 +33,8 @@ mod peer_store;
3433
mod tests;
3534
mod wallet;
3635

37-
pub use error::Error;
36+
pub use error::Error as NodeError;
37+
use error::Error;
3838
pub use event::Event;
3939
use event::{EventHandler, EventQueue};
4040
use peer_store::{PeerInfo, PeerInfoStorage};
@@ -64,7 +64,7 @@ use lightning_transaction_sync::EsploraSyncClient;
6464
use lightning_net_tokio::SocketDescriptor;
6565

6666
use lightning::routing::router::DefaultRouter;
67-
use lightning_invoice::{payment, Currency, Invoice};
67+
use lightning_invoice::{payment, Currency, Invoice, SignedRawInvoice};
6868

6969
use bdk::bitcoin::secp256k1::Secp256k1;
7070
use bdk::blockchain::esplora::EsploraBlockchain;
@@ -74,10 +74,11 @@ use bdk::template::Bip84;
7474
use bitcoin::hashes::sha256::Hash as Sha256;
7575
use bitcoin::hashes::Hash;
7676
use bitcoin::secp256k1::PublicKey;
77-
use bitcoin::BlockHash;
77+
use bitcoin::{Address, BlockHash};
7878

7979
use rand::Rng;
8080

81+
use core::str::FromStr;
8182
use std::collections::HashMap;
8283
use std::convert::{TryFrom, TryInto};
8384
use std::default::Default;
@@ -87,6 +88,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
8788
use std::sync::{Arc, Mutex, RwLock};
8889
use std::time::{Duration, Instant, SystemTime};
8990

91+
uniffi_macros::include_scaffolding!("ldk_node");
92+
9093
// The used 'stop gap' parameter used by BDK's wallet sync. This seems to configure the threshold
9194
// number of blocks after which BDK stops looking for scripts belonging to the wallet.
9295
const BDK_CLIENT_STOP_GAP: usize = 20;
@@ -193,8 +196,8 @@ impl Builder {
193196
self
194197
}
195198

196-
/// Builds an [`Node`] instance according to the options previously configured.
197-
pub fn build(&self) -> Node {
199+
/// Builds a [`Node`] instance according to the options previously configured.
200+
pub fn build(&self) -> Arc<Node> {
198201
let config = Arc::new(self.config.clone());
199202

200203
let ldk_data_dir = format!("{}/ldk", &config.storage_dir_path.clone());
@@ -427,7 +430,7 @@ impl Builder {
427430

428431
let running = RwLock::new(None);
429432

430-
Node {
433+
Arc::new(Node {
431434
running,
432435
config,
433436
wallet,
@@ -446,7 +449,7 @@ impl Builder {
446449
inbound_payments,
447450
outbound_payments,
448451
peer_store,
449-
}
452+
})
450453
}
451454
}
452455

@@ -488,7 +491,7 @@ impl Node {
488491
/// Starts the necessary background tasks, such as handling events coming from user input,
489492
/// LDK/BDK, and the peer-to-peer network. After this returns, the [`Node`] instance can be
490493
/// controlled via the provided API methods in a thread-safe manner.
491-
pub fn start(&mut self) -> Result<(), Error> {
494+
pub fn start(&self) -> Result<(), Error> {
492495
// Acquire a run lock and hold it until we're setup.
493496
let mut run_lock = self.running.write().unwrap();
494497
if run_lock.is_some() {
@@ -502,7 +505,7 @@ impl Node {
502505
}
503506

504507
/// Disconnects all peers, stops all running background tasks, and shuts down [`Node`].
505-
pub fn stop(&mut self) -> Result<(), Error> {
508+
pub fn stop(&self) -> Result<(), Error> {
506509
let mut run_lock = self.running.write().unwrap();
507510
if run_lock.is_none() {
508511
return Err(Error::NotRunning);
@@ -696,15 +699,15 @@ impl Node {
696699
}
697700

698701
/// Retrieve a new on-chain/funding address.
699-
pub fn new_funding_address(&mut self) -> Result<bitcoin::Address, Error> {
702+
pub fn new_funding_address(&self) -> Result<Address, Error> {
700703
let funding_address = self.wallet.get_new_address()?;
701704
log_info!(self.logger, "Generated new funding address: {}", funding_address);
702705
Ok(funding_address)
703706
}
704707

705708
#[cfg(test)]
706709
/// Retrieve the current on-chain balance.
707-
pub fn on_chain_balance(&mut self) -> Result<bdk::Balance, Error> {
710+
pub fn on_chain_balance(&self) -> Result<bdk::Balance, Error> {
708711
self.wallet.get_balance()
709712
}
710713

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

0 commit comments

Comments
 (0)