diff --git a/src/blockchain.rs b/src/blockchain.rs new file mode 100644 index 0000000..b3ecd8b --- /dev/null +++ b/src/blockchain.rs @@ -0,0 +1,104 @@ +use ::safer_ffi::prelude::*; +use bdk::blockchain::{AnyBlockchainConfig, ElectrumBlockchainConfig}; +use safer_ffi::boxed::Box; +use safer_ffi::char_p::char_p_ref; + +#[derive_ReprC] +#[ReprC::opaque] +#[derive(Debug)] +pub struct BlockchainConfig { + pub raw: AnyBlockchainConfig, +} + +#[ffi_export] +fn new_electrum_config( + url: char_p_ref, + socks5: Option, + retry: i16, + timeout: i16, +) -> Box { + let url = url.to_string(); + let socks5 = socks5.map(|s| s.to_string()); + let retry = short_to_u8(retry); + let timeout = short_to_optional_u8(timeout); + + let electrum_config = AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig { + url, + socks5, + retry, + timeout, + }); + Box::new(BlockchainConfig { + raw: electrum_config, + }) +} + +#[ffi_export] +fn free_blockchain_config(blockchain_config: Box) { + drop(blockchain_config); +} + +// TODO compact_filter rocksdb not compiling on android, switch to sqlite? +//#[derive_ReprC] +//#[repr(C)] +//#[derive(Debug)] +//pub struct BitcoinPeerConfig { +// pub address: char_p_boxed, +// pub socks5: Option, +// pub socks5_credentials: Option>>, +//} +// +//impl From<&BitcoinPeerConfig> for BdkBitcoinPeerConfig { +// fn from(config: &BitcoinPeerConfig) -> Self { +// let address = config.address.to_string(); +// let socks5 = config.socks5.as_ref().map(|p| p.to_string()); +// let socks5_credentials = config +// .socks5_credentials.as_ref() +// .map(|c| (c._0.to_string(), c._1.to_string())); +// +// BdkBitcoinPeerConfig { +// address, +// socks5: socks5, +// socks5_credentials: socks5_credentials, +// } +// } +//} +// +// +//#[ffi_export] +//fn new_compact_filters_config<'lt>( +// peers: c_slice::Ref<'lt, BitcoinPeerConfig>, +// network: char_p_ref, +// storage_dir: char_p_ref, +// skip_blocks: usize, +//) -> Box { +// let peers = peers.iter().map(|p| p.into()).collect(); +// let network = Network::from_str(network.to_str()).unwrap(); +// let storage_dir = storage_dir.to_string(); +// let skip_blocks = Some(skip_blocks); +// let cf_config = AnyBlockchainConfig::CompactFilters(CompactFiltersBlockchainConfig { +// peers, +// network, +// storage_dir, +// skip_blocks, +// }); +// Box::new(BlockchainConfig { raw: cf_config }) +//} + +// utility functions + +fn short_to_optional_u8(short: i16) -> Option { + if short < 0 { + None + } else { + Some(short_to_u8(short)) + } +} + +fn short_to_u8(short: i16) -> u8 { + if short < 0 { + u8::MIN + } else { + u8::try_from(short).unwrap_or(u8::MAX) + } +} diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..76dc333 --- /dev/null +++ b/src/database.rs @@ -0,0 +1,32 @@ +use ::safer_ffi::prelude::*; +use bdk::database::any::SledDbConfiguration; +use bdk::database::AnyDatabaseConfig; +use safer_ffi::boxed::Box; +use safer_ffi::char_p::char_p_ref; + +#[derive_ReprC] +#[ReprC::opaque] +#[derive(Debug)] +pub struct DatabaseConfig { + pub raw: AnyDatabaseConfig, +} + +#[ffi_export] +fn new_memory_config() -> Box { + let memory_config = AnyDatabaseConfig::Memory(()); + Box::new(DatabaseConfig { raw: memory_config }) +} + +#[ffi_export] +fn new_sled_config(path: char_p_ref, tree_name: char_p_ref) -> Box { + let path = path.to_string(); + let tree_name = tree_name.to_string(); + + let sled_config = AnyDatabaseConfig::Sled(SledDbConfiguration { path, tree_name }); + Box::new(DatabaseConfig { raw: sled_config }) +} + +#[ffi_export] +fn free_database_config(database_config: Box) { + drop(database_config); +} diff --git a/src/error.rs b/src/error.rs index 3aa6d82..6af73f0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -38,8 +38,8 @@ pub fn get_name(error: &bdk::Error) -> String { Error::Hex(_) => "Hex", Error::Psbt(_) => "Psbt", Error::Electrum(_) => "Electrum", - // Error::Esplora(_) => {} - // Error::CompactFilters(_) => {} + // Error::Esplora(_) => "Esplora", + // Error::CompactFilters(_) => "CompactFilters", Error::Sled(_) => "Sled", } .to_string() diff --git a/src/lib.rs b/src/lib.rs index 3c75153..72e9910 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,7 @@ #![deny(unsafe_code)] /* No `unsafe` needed! */ +mod blockchain; +mod database; mod error; mod wallet; diff --git a/src/wallet.rs b/src/wallet.rs index 988bede..93ea73c 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -10,6 +10,8 @@ use bdk::wallet::AddressIndex::New; use bdk::{Error, Wallet}; use safer_ffi::boxed::Box; use safer_ffi::char_p::{char_p_boxed, char_p_ref}; +use crate::blockchain::BlockchainConfig; +use crate::database::DatabaseConfig; #[derive_ReprC] #[ReprC::opaque] @@ -79,34 +81,30 @@ pub struct WalletResult { #[ffi_export] fn new_wallet_result( - name: char_p_ref, descriptor: char_p_ref, change_descriptor: Option, + blockchain_config: &BlockchainConfig, + database_config: &DatabaseConfig, ) -> Box { - let name = name.to_string(); + let descriptor = descriptor.to_string(); let change_descriptor = change_descriptor.map(|s| s.to_string()); - let wallet_result = new_wallet(name, descriptor, change_descriptor); + let bc_config = &blockchain_config.raw; + let db_config = &database_config.raw; + let wallet_result = new_wallet(descriptor, change_descriptor, bc_config, db_config); Box::new(WalletResult { raw: wallet_result }) } fn new_wallet( - _name: String, descriptor: String, change_descriptor: Option, + blockchain_config: &AnyBlockchainConfig, + database_config: &AnyDatabaseConfig, ) -> Result, Error> { let network = Testnet; - let electrum_config = AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig { - url: "ssl://electrum.blockstream.info:60002".to_string(), - socks5: None, - retry: 5, - timeout: None, - }); - let blockchain_config = electrum_config; - let client = AnyBlockchain::from_config(&blockchain_config)?; - let database_config = AnyDatabaseConfig::Memory(()); - let database = AnyDatabase::from_config(&database_config)?; + let client = AnyBlockchain::from_config(blockchain_config)?; + let database = AnyDatabase::from_config(database_config)?; let descriptor: &str = descriptor.as_str(); let change_descriptor: Option<&str> = change_descriptor.as_deref(); diff --git a/test.sh b/test.sh index f6f86d5..03855c5 100755 --- a/test.sh +++ b/test.sh @@ -6,9 +6,9 @@ cargo test --features c-headers -- generate_headers # cc export LD_LIBRARY_PATH=`pwd`/target/debug -#valgrind --leak-check=full cc/bdk_ffi_test +#valgrind --leak-check=full --show-leak-kinds=all cc/bdk_ffi_test cc/bdk_ffi_test -# bdk-kotlin +## bdk-kotlin (cd bdk-kotlin && gradle test) (cd bdk-kotlin && gradle :android:connectedDebugAndroidTest)