Skip to content

Commit

Permalink
Generate UniFFI scaffolding
Browse files Browse the repository at this point in the history
We generate the scaffolding from an UDL file and include it in `lib.rs`.
Furthermore, we add a bindings generation shell script for convenience.
  • Loading branch information
tnull committed Jan 24, 2023
1 parent e530c86 commit 32d3675
Show file tree
Hide file tree
Showing 9 changed files with 270 additions and 38 deletions.
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ description = "A ready-to-go node implementation based on LDK."

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

[lib]
crate-type = ["staticlib", "cdylib"]
name = "ldk_node"

[dependencies]
#lightning = { version = "0.0.112", features = ["max_level_trace", "std"] }
#lightning-invoice = { version = "0.20" }
Expand Down Expand Up @@ -47,12 +51,17 @@ chrono = "0.4"
futures = "0.3"
serde_json = { version = "1.0" }
tokio = { version = "1", features = [ "full" ] }
uniffi = { version = "0.21.0", features = ["builtin-bindgen"] }
uniffi_macros = { version = "0.21.0", features = ["builtin-bindgen"] }

[dev-dependencies]
electrsd = { version = "0.22.0", features = ["legacy", "esplora_a33e97e1", "bitcoind_23_0"] }
electrum-client = "0.12.0"
once_cell = "1.16.0"

[build-dependencies]
uniffi_build = "0.21.0"

[profile.release]
panic = "abort"

Expand Down
3 changes: 3 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
uniffi_build::generate_scaffolding("uniffi/ldk_node.udl").unwrap();
}
16 changes: 13 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,20 @@ pub enum Error {
FundingTxCreationFailed,
/// A network connection has been closed.
ConnectionFailed,
/// The given address is invalid.
AddressInvalid,
/// The given public key is invalid.
PublicKeyInvalid,
/// The given payment hash is invalid.
PaymentHashInvalid,
/// Payment of the given invoice has already been intiated.
NonUniquePaymentHash,
/// The given invoice is invalid.
InvoiceInvalid,
/// Invoice creation failed.
InvoiceCreationFailed,
/// The given channel ID is invalid.
ChannelIdInvalid,
/// No route for the given target could be found.
RoutingFailed,
/// A given peer info could not be parsed.
Expand All @@ -40,13 +48,15 @@ impl fmt::Display for Error {
match *self {
Self::AlreadyRunning => write!(f, "Node is already running."),
Self::NotRunning => write!(f, "Node is not running."),
Self::FundingTxCreationFailed => {
write!(f, "Funding transaction could not be created.")
}
Self::FundingTxCreationFailed => write!(f, "Funding transaction could not be created."),
Self::ConnectionFailed => write!(f, "Network connection closed."),
Self::AddressInvalid => write!(f, "The given address is invalid."),
Self::PublicKeyInvalid => write!(f, "The given public key is invalid."),
Self::PaymentHashInvalid => write!(f, "The given payment hash is invalid."),
Self::NonUniquePaymentHash => write!(f, "An invoice must not get payed twice."),
Self::InvoiceInvalid => write!(f, "The given invoice is invalid."),
Self::InvoiceCreationFailed => write!(f, "Failed to create invoice."),
Self::ChannelIdInvalid => write!(f, "The given channel ID is invalid."),
Self::RoutingFailed => write!(f, "Failed to find route."),
Self::PeerInfoParseFailed => write!(f, "Failed to parse the given peer information."),
Self::ChannelCreationFailed => write!(f, "Failed to create channel."),
Expand Down
43 changes: 26 additions & 17 deletions src/event.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
hex_utils, ChannelManager, Config, Error, KeysManager, NetworkGraph, PaymentInfo,
PaymentInfoStorage, PaymentStatus, Wallet,
hex_utils, ChannelId, ChannelManager, Config, Error, KeysManager, NetworkGraph, PaymentInfo,
PaymentInfoStorage, PaymentStatus, UserChannelId, Wallet,
};

use crate::logger::{log_error, log_given_level, log_info, log_internal, Logger};
Expand Down Expand Up @@ -50,16 +50,16 @@ pub enum Event {
/// A channel is ready to be used.
ChannelReady {
/// The `channel_id` of the channel.
channel_id: [u8; 32],
channel_id: ChannelId,
/// The `user_channel_id` of the channel.
user_channel_id: u128,
user_channel_id: UserChannelId,
},
/// A channel has been closed.
ChannelClosed {
/// The `channel_id` of the channel.
channel_id: [u8; 32],
channel_id: ChannelId,
/// The `user_channel_id` of the channel.
user_channel_id: u128,
user_channel_id: UserChannelId,
},
}

Expand All @@ -83,13 +83,13 @@ impl Readable for Event {
Ok(Self::PaymentReceived { payment_hash, amount_msat })
}
3u8 => {
let channel_id: [u8; 32] = Readable::read(reader)?;
let user_channel_id: u128 = Readable::read(reader)?;
let channel_id = ChannelId(Readable::read(reader)?);
let user_channel_id = UserChannelId(Readable::read(reader)?);
Ok(Self::ChannelReady { channel_id, user_channel_id })
}
4u8 => {
let channel_id: [u8; 32] = Readable::read(reader)?;
let user_channel_id: u128 = Readable::read(reader)?;
let channel_id = ChannelId(Readable::read(reader)?);
let user_channel_id = UserChannelId(Readable::read(reader)?);
Ok(Self::ChannelClosed { channel_id, user_channel_id })
}
_ => Err(lightning::ln::msgs::DecodeError::InvalidValue),
Expand Down Expand Up @@ -118,14 +118,14 @@ impl Writeable for Event {
}
Self::ChannelReady { channel_id, user_channel_id } => {
3u8.write(writer)?;
channel_id.write(writer)?;
user_channel_id.write(writer)?;
channel_id.0.write(writer)?;
user_channel_id.0.write(writer)?;
Ok(())
}
Self::ChannelClosed { channel_id, user_channel_id } => {
4u8.write(writer)?;
channel_id.write(writer)?;
user_channel_id.write(writer)?;
channel_id.0.write(writer)?;
user_channel_id.0.write(writer)?;
Ok(())
}
}
Expand Down Expand Up @@ -562,7 +562,10 @@ where
counterparty_node_id,
);
self.event_queue
.add_event(Event::ChannelReady { channel_id, user_channel_id })
.add_event(Event::ChannelReady {
channel_id: ChannelId(channel_id),
user_channel_id: UserChannelId(user_channel_id),
})
.expect("Failed to push to event queue");
}
LdkEvent::ChannelClosed { channel_id, reason, user_channel_id } => {
Expand All @@ -573,7 +576,10 @@ where
reason
);
self.event_queue
.add_event(Event::ChannelClosed { channel_id, user_channel_id })
.add_event(Event::ChannelClosed {
channel_id: ChannelId(channel_id),
user_channel_id: UserChannelId(user_channel_id),
})
.expect("Failed to push to event queue");
}
LdkEvent::DiscardFunding { .. } => {}
Expand All @@ -592,7 +598,10 @@ mod tests {
let test_persister = Arc::new(TestPersister::new());
let event_queue = EventQueue::new(Arc::clone(&test_persister));

let expected_event = Event::ChannelReady { channel_id: [23u8; 32], user_channel_id: 2323 };
let expected_event = Event::ChannelReady {
channel_id: ChannelId([23u8; 32]),
user_channel_id: UserChannelId(2323),
};
event_queue.add_event(expected_event.clone()).unwrap();
assert!(test_persister.get_and_clear_pending_persist());

Expand Down
26 changes: 14 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
//! - Wallet and channel states are persisted to disk.
//! - Gossip is retrieved over the P2P network.
#![deny(missing_docs)]
#![deny(broken_intra_doc_links)]
#![deny(private_intra_doc_links)]
#![allow(bare_trait_objects)]
Expand All @@ -35,15 +34,16 @@ mod tests;
mod types;
mod wallet;

pub use error::Error;
pub use error::Error as NodeError;
use error::Error;
pub use event::Event;
use event::{EventHandler, EventQueue};
use peer_store::{PeerInfo, PeerInfoStorage};
use types::{
ChainMonitor, ChannelManager, GossipSync, InvoicePayer, KeysManager, NetworkGraph,
OnionMessenger, PaymentInfoStorage, PeerManager, Router, Scorer,
};
pub use types::{PaymentInfo, PaymentStatus};
pub use types::{ChannelId, PaymentInfo, PaymentStatus, UserChannelId};
use wallet::Wallet;

use logger::{log_error, log_given_level, log_info, log_internal, FilesystemLogger, Logger};
Expand Down Expand Up @@ -76,7 +76,7 @@ use bdk::template::Bip84;
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::Hash;
use bitcoin::secp256k1::PublicKey;
use bitcoin::BlockHash;
use bitcoin::{Address, BlockHash};

use rand::Rng;

Expand All @@ -89,6 +89,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use std::time::{Duration, Instant, SystemTime};

uniffi_macros::include_scaffolding!("ldk_node");

// The used 'stop gap' parameter used by BDK's wallet sync. This seems to configure the threshold
// number of blocks after which BDK stops looking for scripts belonging to the wallet.
const BDK_CLIENT_STOP_GAP: usize = 20;
Expand Down Expand Up @@ -195,8 +197,8 @@ impl Builder {
self
}

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

let ldk_data_dir = format!("{}/ldk", &config.storage_dir_path.clone());
Expand Down Expand Up @@ -410,7 +412,7 @@ impl Builder {

let running = RwLock::new(None);

Node {
Arc::new(Node {
running,
config,
wallet,
Expand All @@ -429,7 +431,7 @@ impl Builder {
inbound_payments,
outbound_payments,
peer_store,
}
})
}
}

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

/// Disconnects all peers, stops all running background tasks, and shuts down [`Node`].
pub fn stop(&mut self) -> Result<(), Error> {
pub fn stop(&self) -> Result<(), Error> {
let mut run_lock = self.running.write().unwrap();
if run_lock.is_none() {
return Err(Error::NotRunning);
Expand Down Expand Up @@ -704,15 +706,15 @@ impl Node {
}

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

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

Expand Down
10 changes: 5 additions & 5 deletions src/tests/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,13 @@ fn rand_config() -> Config {
fn channel_full_cycle() {
println!("== Node A ==");
let config_a = rand_config();
let mut node_a = Builder::from_config(config_a).build();
let node_a = Builder::from_config(config_a).build();
node_a.start().unwrap();
let addr_a = node_a.new_funding_address().unwrap();

println!("\n== Node B ==");
let config_b = rand_config();
let mut node_b = Builder::from_config(config_b).build();
let node_b = Builder::from_config(config_b).build();
node_b.start().unwrap();
let addr_b = node_b.new_funding_address().unwrap();

Expand Down Expand Up @@ -161,10 +161,10 @@ fn channel_full_cycle() {
expect_event!(node_a, ChannelReady);

let channel_id = match node_b.next_event() {
ref e @ Event::ChannelReady { channel_id, .. } => {
ref e @ Event::ChannelReady { ref channel_id, .. } => {
println!("{} got event {:?}", std::stringify!(node_b), e);
node_b.event_handled();
channel_id
channel_id.clone()
}
ref e => {
panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e);
Expand All @@ -180,7 +180,7 @@ fn channel_full_cycle() {
expect_event!(node_a, PaymentSuccessful);
expect_event!(node_b, PaymentReceived);

node_b.close_channel(&channel_id, &node_a.node_id().unwrap()).unwrap();
node_b.close_channel(&channel_id.0, &node_a.node_id().unwrap()).unwrap();
expect_event!(node_a, ChannelClosed);
expect_event!(node_b, ChannelClosed);

Expand Down
Loading

0 comments on commit 32d3675

Please sign in to comment.