Add kotlin BlockchainConfig and DatabaseConfig
This commit is contained in:
parent
757113c002
commit
1249a4c491
@ -0,0 +1,25 @@
|
||||
package org.bitcoindevkit.bdk
|
||||
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
abstract class BlockchainConfig() : LibBase() {
|
||||
private val log: Logger = LoggerFactory.getLogger(BlockchainConfig::class.java)
|
||||
abstract val blockchainConfigT: LibJna.BlockchainConfig_t
|
||||
|
||||
protected fun finalize() {
|
||||
libJna.free_blockchain_config(blockchainConfigT)
|
||||
log.debug("$blockchainConfigT freed")
|
||||
}
|
||||
}
|
||||
|
||||
class ElectrumConfig(
|
||||
url: String,
|
||||
socks5: String?,
|
||||
retry: Short,
|
||||
timeout: Short
|
||||
) : BlockchainConfig() {
|
||||
|
||||
private val log: Logger = LoggerFactory.getLogger(ElectrumConfig::class.java)
|
||||
override val blockchainConfigT = libJna.new_electrum_config(url, socks5, retry, timeout)
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.bitcoindevkit.bdk
|
||||
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
abstract class DatabaseConfig() : LibBase() {
|
||||
private val log: Logger = LoggerFactory.getLogger(DatabaseConfig::class.java)
|
||||
abstract val databaseConfigT: LibJna.DatabaseConfig_t
|
||||
|
||||
protected fun finalize() {
|
||||
libJna.free_database_config(databaseConfigT)
|
||||
log.debug("$databaseConfigT freed")
|
||||
}
|
||||
}
|
||||
|
||||
class MemoryConfig() : DatabaseConfig() {
|
||||
|
||||
private val log: Logger = LoggerFactory.getLogger(MemoryConfig::class.java)
|
||||
override val databaseConfigT = libJna.new_memory_config()
|
||||
}
|
||||
|
||||
class SledConfig(path: String, treeName:String) : DatabaseConfig() {
|
||||
|
||||
private val log: Logger = LoggerFactory.getLogger(SledConfig::class.java)
|
||||
override val databaseConfigT = libJna.new_sled_config(path, treeName)
|
||||
}
|
@ -48,6 +48,18 @@ interface LibJna : Library {
|
||||
// WalletRef_t * wallet_ref);
|
||||
fun free_wallet_ref(wallet_ref: WalletRef_t)
|
||||
|
||||
// typedef struct BlockchainConfig BlockchainConfig_t;
|
||||
class BlockchainConfig_t : PointerType {
|
||||
constructor() : super()
|
||||
constructor(pointer: Pointer) : super(pointer)
|
||||
}
|
||||
|
||||
// typedef struct DatabaseConfig DatabaseConfig_t;
|
||||
class DatabaseConfig_t : PointerType {
|
||||
constructor() : super()
|
||||
constructor(pointer: Pointer) : super(pointer)
|
||||
}
|
||||
|
||||
// typedef struct WalletResult WalletResult_t;
|
||||
class WalletResult_t : PointerType {
|
||||
constructor() : super()
|
||||
@ -55,13 +67,15 @@ interface LibJna : Library {
|
||||
}
|
||||
|
||||
// WalletResult_t * new_wallet_result (
|
||||
// char const * name,
|
||||
// char const * descriptor,
|
||||
// char const * change_descriptor);
|
||||
// char const * change_descriptor,
|
||||
// BlockchainConfig_t const * blockchain_config,
|
||||
// DatabaseConfig_t const * database_config);
|
||||
fun new_wallet_result(
|
||||
name: String,
|
||||
descriptor: String,
|
||||
changeDescriptor: String?
|
||||
changeDescriptor: String?,
|
||||
blockchainConfig: BlockchainConfig_t,
|
||||
databaseConfig: DatabaseConfig_t,
|
||||
): WalletResult_t
|
||||
|
||||
// char * get_wallet_err (
|
||||
@ -87,4 +101,32 @@ interface LibJna : Library {
|
||||
// void free_string (
|
||||
// char * string);
|
||||
fun free_string(string: Pointer?)
|
||||
|
||||
// BlockchainConfig_t * new_electrum_config (
|
||||
// char const * url,
|
||||
// char const * socks5,
|
||||
// int16_t retry,
|
||||
// int16_t timeout);
|
||||
fun new_electrum_config(
|
||||
url: String,
|
||||
socks5: String?,
|
||||
retry: Short,
|
||||
timeout: Short
|
||||
): BlockchainConfig_t
|
||||
|
||||
// void free_blockchain_config (
|
||||
// BlockchainConfig_t * blockchain_config);
|
||||
fun free_blockchain_config( blockchain_config: BlockchainConfig_t)
|
||||
|
||||
// DatabaseConfig_t * new_memory_config (void);
|
||||
fun new_memory_config(): DatabaseConfig_t
|
||||
|
||||
// DatabaseConfig_t * new_sled_config (
|
||||
// char const * path,
|
||||
// char const * tree_name);
|
||||
fun new_sled_config(path: String, tree_name: String): DatabaseConfig_t
|
||||
|
||||
// void free_database_config (
|
||||
// DatabaseConfig_t * database_config);
|
||||
fun free_database_config( database_config: DatabaseConfig_t)
|
||||
}
|
||||
|
@ -4,15 +4,16 @@ import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
class Wallet constructor(
|
||||
name: String,
|
||||
descriptor: String,
|
||||
changeDescriptor: String?,
|
||||
blockchainConfig: BlockchainConfig,
|
||||
databaseConfig: DatabaseConfig,
|
||||
) : LibBase() {
|
||||
|
||||
val log: Logger = LoggerFactory.getLogger(Wallet::class.java)
|
||||
|
||||
private val walletResult =
|
||||
WalletResult(libJna.new_wallet_result(name, descriptor, changeDescriptor))
|
||||
WalletResult(libJna.new_wallet_result(descriptor, changeDescriptor, blockchainConfig.blockchainConfigT, databaseConfig.databaseConfigT))
|
||||
private val walletRefT = walletResult.value()
|
||||
|
||||
fun sync() {
|
||||
|
@ -22,17 +22,21 @@ abstract class LibTest : LibBase() {
|
||||
|
||||
@Test
|
||||
fun walletResultError() {
|
||||
val blockchainConfig = ElectrumConfig("ssl://electrum.blockstream.info:60002", null, 5, 30)
|
||||
val databaseConfig = MemoryConfig()
|
||||
val jnaException = assertThrows(JnaException::class.java) {
|
||||
Wallet("bad", "bad", "bad")
|
||||
Wallet("bad", "bad", blockchainConfig, databaseConfig)
|
||||
}
|
||||
assertEquals(jnaException.err, JnaError.Descriptor)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun walletResultFinalize() {
|
||||
val blockchainConfig = ElectrumConfig("ssl://electrum.blockstream.info:60002", null, 5, 30)
|
||||
val databaseConfig = MemoryConfig()
|
||||
val names = listOf("one", "two", "three")
|
||||
names.map {
|
||||
val wallet = Wallet(it, desc, change)
|
||||
val wallet = Wallet(desc, change, blockchainConfig, databaseConfig)
|
||||
assertNotNull(wallet)
|
||||
}
|
||||
System.gc()
|
||||
@ -41,14 +45,18 @@ abstract class LibTest : LibBase() {
|
||||
|
||||
@Test
|
||||
fun walletSync() {
|
||||
val wallet = Wallet(name, desc, change)
|
||||
val blockchainConfig = ElectrumConfig("ssl://electrum.blockstream.info:60002", null, 5, 30)
|
||||
val databaseConfig = MemoryConfig()
|
||||
val wallet = Wallet(desc, change, blockchainConfig, databaseConfig)
|
||||
assertNotNull(wallet)
|
||||
wallet.sync()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun walletNewAddress() {
|
||||
val wallet = Wallet(name, desc, change)
|
||||
val blockchainConfig = ElectrumConfig("ssl://electrum.blockstream.info:60002", null, 5, 30)
|
||||
val databaseConfig = MemoryConfig()
|
||||
val wallet = Wallet(desc, change, blockchainConfig, databaseConfig)
|
||||
assertNotNull(wallet)
|
||||
val address = wallet.getAddress()
|
||||
assertNotNull(address)
|
||||
|
@ -8,8 +8,14 @@ int main (int argc, char const * const argv[])
|
||||
{
|
||||
// test new wallet error
|
||||
{
|
||||
WalletResult_t *wallet_result = new_wallet_result("bad", "bad", NULL);
|
||||
BlockchainConfig_t *bc_config = new_electrum_config("ssl://electrum.blockstream.info:60002", NULL, 5, 30);
|
||||
//DatabaseConfig_t *db_config = new_sled_config("/home/steve/.bdk", "test_wallet");
|
||||
DatabaseConfig_t *db_config = new_memory_config();
|
||||
|
||||
WalletResult_t *wallet_result = new_wallet_result("bad", "bad", bc_config, db_config);
|
||||
assert(wallet_result != NULL);
|
||||
free_blockchain_config(bc_config);
|
||||
free_database_config(db_config);
|
||||
char *wallet_err = get_wallet_err(wallet_result);
|
||||
assert(wallet_err != NULL);
|
||||
assert( 0 == strcmp(wallet_err,"Descriptor") );
|
||||
@ -18,16 +24,22 @@ int main (int argc, char const * const argv[])
|
||||
assert(wallet_ref == NULL);
|
||||
free_string(wallet_err);
|
||||
free_wallet_result(wallet_result);
|
||||
|
||||
}
|
||||
|
||||
// test new wallet
|
||||
{
|
||||
char const *name = "test_wallet";
|
||||
char const *desc = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)";
|
||||
char const *change = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)";
|
||||
|
||||
WalletResult_t *wallet_result = new_wallet_result(name, desc, change);
|
||||
BlockchainConfig_t *bc_config = new_electrum_config("ssl://electrum.blockstream.info:60002", NULL, 5, 30);
|
||||
//DatabaseConfig_t *db_config = new_sled_config("/home/steve/.bdk", "test_wallet");
|
||||
DatabaseConfig_t *db_config = new_memory_config();
|
||||
|
||||
WalletResult_t *wallet_result = new_wallet_result(desc, change, bc_config, db_config);
|
||||
assert(wallet_result != NULL);
|
||||
free_blockchain_config(bc_config);
|
||||
free_database_config(db_config);
|
||||
char *wallet_err = get_wallet_err(wallet_result);
|
||||
assert(wallet_err == NULL);
|
||||
WalletRef_t *wallet_ref = get_wallet_ok(wallet_result);
|
||||
@ -65,6 +77,7 @@ int main (int argc, char const * const argv[])
|
||||
|
||||
// verify sync_wallet after free_wallet fails (core dumped)
|
||||
////VoidResult_t sync_result2 = sync_wallet(wallet_result);
|
||||
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
104
src/blockchain.rs
Normal file
104
src/blockchain.rs
Normal file
@ -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<char_p_ref>,
|
||||
retry: i16,
|
||||
timeout: i16,
|
||||
) -> Box<BlockchainConfig> {
|
||||
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<BlockchainConfig>) {
|
||||
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<char_p_boxed>,
|
||||
// pub socks5_credentials: Option<Box<Tuple2<char_p_boxed, char_p_boxed>>>,
|
||||
//}
|
||||
//
|
||||
//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<BlockchainConfig> {
|
||||
// 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<u8> {
|
||||
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)
|
||||
}
|
||||
}
|
32
src/database.rs
Normal file
32
src/database.rs
Normal file
@ -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<DatabaseConfig> {
|
||||
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<DatabaseConfig> {
|
||||
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<DatabaseConfig>) {
|
||||
drop(database_config);
|
||||
}
|
@ -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()
|
||||
|
@ -1,5 +1,7 @@
|
||||
#![deny(unsafe_code)] /* No `unsafe` needed! */
|
||||
|
||||
mod blockchain;
|
||||
mod database;
|
||||
mod error;
|
||||
mod wallet;
|
||||
|
||||
|
@ -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<char_p_ref>,
|
||||
blockchain_config: &BlockchainConfig,
|
||||
database_config: &DatabaseConfig,
|
||||
) -> Box<WalletResult> {
|
||||
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<String>,
|
||||
blockchain_config: &AnyBlockchainConfig,
|
||||
database_config: &AnyDatabaseConfig,
|
||||
) -> Result<Wallet<AnyBlockchain, AnyDatabase>, 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();
|
||||
|
4
test.sh
4
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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user