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 Dec 13, 2022
1 parent a68fa60 commit 45c7724
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 28 deletions.
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ edition = "2018"

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

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

[dependencies]
#lightning = { version = "0.0.112", features = ["max_level_trace", "std"] }
#lightning-invoice = { version = "0.20" }
Expand Down Expand Up @@ -46,13 +50,18 @@ 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"
lazy_static = "1.4.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_lite.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, "LDKLite is already running."),
Self::NotRunning => write!(f, "LDKLite 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
38 changes: 22 additions & 16 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, NetworkGraph, PaymentInfo, PaymentInfoStorage,
PaymentStatus, Wallet,
hex_utils, ChannelId, ChannelManager, Config, Error, 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 @@ -559,7 +559,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 @@ -570,7 +573,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 Down
123 changes: 114 additions & 9 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 Down Expand Up @@ -67,7 +66,7 @@ use lightning_transaction_sync::EsploraSyncClient;
use lightning_net_tokio::SocketDescriptor;

use lightning::routing::router::DefaultRouter;
use lightning_invoice::{payment, Currency, Invoice};
use lightning_invoice::{payment, Currency, Invoice, SignedRawInvoice};

use bdk::bitcoin::secp256k1::Secp256k1;
use bdk::blockchain::esplora::EsploraBlockchain;
Expand All @@ -77,10 +76,11 @@ 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;

use core::str::FromStr;
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto};
use std::default::Default;
Expand All @@ -90,6 +90,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use std::time::{Duration, Instant, SystemTime};

uniffi_macros::include_scaffolding!("ldk_lite");

// 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 @@ -197,7 +199,7 @@ impl Builder {
}

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

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

let running = RwLock::new(None);

LdkLite {
Arc::new(LdkLite {
running,
config,
wallet,
Expand All @@ -445,7 +447,7 @@ impl Builder {
inbound_payments,
outbound_payments,
peer_store,
}
})
}
}

Expand Down Expand Up @@ -487,7 +489,7 @@ impl LdkLite {
/// 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 [`LdkLite`] 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 @@ -501,7 +503,7 @@ impl LdkLite {
}

/// Disconnects all peers, stops all running background tasks, and shuts down [`LdkLite`].
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 @@ -695,7 +697,7 @@ impl LdkLite {
}

/// 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)
Expand Down Expand Up @@ -1086,3 +1088,106 @@ pub(crate) type NetworkGraph = gossip::NetworkGraph<Arc<FilesystemLogger>>;
pub(crate) type PaymentInfoStorage = Mutex<HashMap<PaymentHash, PaymentInfo>>;

pub(crate) type OnionMessenger = SimpleArcOnionMessenger<FilesystemLogger>;

impl UniffiCustomTypeConverter for PublicKey {
type Builtin = String;

fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
if let Ok(key) = PublicKey::from_str(&val) {
return Ok(key);
}

Err(Error::PublicKeyInvalid.into())
}

fn from_custom(obj: Self) -> Self::Builtin {
obj.to_string()
}
}

impl UniffiCustomTypeConverter for Address {
type Builtin = String;

fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
if let Ok(addr) = Address::from_str(&val) {
return Ok(addr);
}

Err(Error::AddressInvalid.into())
}

fn from_custom(obj: Self) -> Self::Builtin {
obj.to_string()
}
}

impl UniffiCustomTypeConverter for Invoice {
type Builtin = String;

fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
if let Ok(signed) = val.parse::<SignedRawInvoice>() {
if let Ok(invoice) = Invoice::from_signed(signed) {
return Ok(invoice);
}
}

Err(Error::InvoiceInvalid.into())
}

fn from_custom(obj: Self) -> Self::Builtin {
obj.to_string()
}
}

impl UniffiCustomTypeConverter for PaymentHash {
type Builtin = String;

fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
if let Ok(hash) = Sha256::from_str(&val) {
Ok(PaymentHash(hash.into_inner()))
} else {
Err(Error::PaymentHashInvalid.into())
}
}

fn from_custom(obj: Self) -> Self::Builtin {
Sha256::from_slice(&obj.0).unwrap().to_string()
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct ChannelId([u8; 32]);

impl UniffiCustomTypeConverter for ChannelId {
type Builtin = String;

fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
if let Some(hex_vec) = hex_utils::to_vec(&val) {
if hex_vec.len() == 32 {
let mut channel_id = [0u8; 32];
channel_id.copy_from_slice(&hex_vec[..]);
return Ok(Self(channel_id));
}
}
Err(Error::ChannelIdInvalid.into())
}

fn from_custom(obj: Self) -> Self::Builtin {
hex_utils::to_string(&obj.0)
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct UserChannelId(u128);

impl UniffiCustomTypeConverter for UserChannelId {
type Builtin = String;

fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
Ok(UserChannelId(u128::from_str(&val).map_err(|_| Error::ChannelIdInvalid)?))
}

fn from_custom(obj: Self) -> Self::Builtin {
obj.0.to_string()
}
}
Loading

0 comments on commit 45c7724

Please sign in to comment.