Test new, print, and free Config works
This commit is contained in:
parent
43425c8875
commit
8aa18fbf20
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,4 +1,8 @@
|
|||||||
/target
|
target
|
||||||
|
build
|
||||||
|
Cargo.lock
|
||||||
*.h
|
*.h
|
||||||
/main
|
main
|
||||||
/Cargo.lock
|
/local.properties
|
||||||
|
.gradle
|
||||||
|
wallet_db
|
||||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
|||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["staticlib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bdk = { version = "^0.7", features = ["all-keys"] }
|
bdk = { version = "^0.7", features = ["all-keys"] }
|
||||||
|
22
build.gradle
Normal file
22
build.gradle
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
buildscript {
|
||||||
|
ext.kotlin_version = '1.5.10'
|
||||||
|
repositories {
|
||||||
|
//google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
//classpath 'com.android.tools.build:gradle:3.6.4'
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
//google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task clean(type: Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
8
build.sh
8
build.sh
@ -1,3 +1,9 @@
|
|||||||
cargo build
|
cargo build
|
||||||
cargo test --features c-headers -- generate_headers
|
cargo test --features c-headers -- generate_headers
|
||||||
cc main.c -o main -L target/debug -l bdk_ffi -l pthread -l dl -l m
|
cc main.c -o main -L target/debug -l bdk_ffi -l pthread -l dl -l m
|
||||||
|
./main
|
||||||
|
|
||||||
|
# jvm
|
||||||
|
mkdir -p jvm/build/jniLibs/x86_64_linux
|
||||||
|
cp target/debug/libbdk_ffi.so jvm/build/jniLibs/x86_64_linux
|
||||||
|
export LD_LIBRARY_PATH=`pwd`/target/debug
|
||||||
|
21
gradle.properties
Normal file
21
gradle.properties
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Project-wide Gradle settings.
|
||||||
|
# IDE (e.g. Android Studio) users:
|
||||||
|
# Gradle settings configured through the IDE *will override*
|
||||||
|
# any settings specified in this file.
|
||||||
|
# For more details on how to configure your build environment visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
org.gradle.jvmargs=-Xmx1536m
|
||||||
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
|
# org.gradle.parallel=true
|
||||||
|
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||||
|
# Android operating system, and which are packaged with your app's APK
|
||||||
|
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||||
|
android.useAndroidX=true
|
||||||
|
# Automatically convert third-party libraries to use AndroidX
|
||||||
|
android.enableJetifier=true
|
||||||
|
# Kotlin code style for this project: "official" or "obsolete":
|
||||||
|
kotlin.code.style=official
|
40
jvm/build.gradle
Normal file
40
jvm/build.gradle
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.jvm' // version '1.3.71'
|
||||||
|
id 'java-library'
|
||||||
|
id 'maven-publish'
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
systemProperty "java.library.path", file("${buildDir}/jniLibs/x86_64_linux").absolutePath
|
||||||
|
environment "LD_LIBRARY_PATH", file("${buildDir}/jniLibs/x86_64_linux").absolutePath
|
||||||
|
// testLogging {
|
||||||
|
// events "PASSED", "SKIPPED", "FAILED", "STANDARD_OUT", "STANDARD_ERROR"
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
task buildRust(type: Exec) {
|
||||||
|
workingDir '../'
|
||||||
|
commandLine './build.sh'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation platform('org.jetbrains.kotlin:kotlin-bom')
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.10"
|
||||||
|
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.+"
|
||||||
|
implementation "net.java.dev.jna:jna:5.8.0"
|
||||||
|
|
||||||
|
testImplementation 'org.jetbrains.kotlin:kotlin-test'
|
||||||
|
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit'
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
maven(MavenPublication) {
|
||||||
|
groupId = 'org.bitcoindevkit.bdkjni'
|
||||||
|
artifactId = 'bdk-jvm-debug'
|
||||||
|
version = '0.2.1-dev'
|
||||||
|
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
jvm/src/test/java/org/bitcoindevkit/bdkjni/LibTest.kt
Normal file
43
jvm/src/test/java/org/bitcoindevkit/bdkjni/LibTest.kt
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package org.bitcoindevkit.bdkjni
|
||||||
|
|
||||||
|
import com.sun.jna.Native
|
||||||
|
import com.sun.jna.NativeLong
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Library test, which will execute on linux host.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class LibTest {
|
||||||
|
|
||||||
|
private val lib: Lib = Native.load("bdk_ffi", Lib::class.java)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun print_string() {
|
||||||
|
lib.print_string("hello print string")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun concat_print_free_string() {
|
||||||
|
val concat = lib.concat_string("hello", "concat")
|
||||||
|
lib.print_string(concat)
|
||||||
|
lib.free_string(concat)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun print_free_config() {
|
||||||
|
val config = Config_t()
|
||||||
|
config.name = "test"
|
||||||
|
config.count = NativeLong(101)
|
||||||
|
lib.print_config(config)
|
||||||
|
lib.free_config(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun new_print_free_config() {
|
||||||
|
println("Long max value = ${Long.MAX_VALUE}")
|
||||||
|
val config = lib.new_config("test test", NativeLong(Long.MAX_VALUE))
|
||||||
|
lib.print_config(config)
|
||||||
|
lib.free_config(config)
|
||||||
|
}
|
||||||
|
}
|
58
main.c
58
main.c
@ -4,40 +4,52 @@
|
|||||||
|
|
||||||
int main (int argc, char const * const argv[])
|
int main (int argc, char const * const argv[])
|
||||||
{
|
{
|
||||||
|
// test print_string
|
||||||
|
print_string("hello 123");
|
||||||
|
|
||||||
|
// test concat_string
|
||||||
char const * string1 = "string1";
|
char const * string1 = "string1";
|
||||||
char const * string2 = "string2";
|
char const * string2 = "string2";
|
||||||
char * string3 = concat_string(string1, string2);
|
char * string3 = concat_string(string1, string2);
|
||||||
|
|
||||||
print_string(string3);
|
|
||||||
print_string(string3);
|
print_string(string3);
|
||||||
free_string(string3);
|
free_string(string3);
|
||||||
//free_string(string3);
|
// verify free_string after free_string fails
|
||||||
|
////free_string(string3);
|
||||||
//Point_t a = new_point(84,45);
|
|
||||||
//Point_t b = new_point(0,39);
|
|
||||||
//Point_t m = mid_point(a, b);
|
|
||||||
//print_point(m);
|
|
||||||
|
|
||||||
char const * name = "test_wallet";
|
// test print_config with c created config
|
||||||
char const * desc = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)";
|
Config_t config1 = { .name = "test", .count = 101 };
|
||||||
char const * change = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)";
|
print_config(&config1);
|
||||||
|
|
||||||
//printf("wallet name: %s\n", name);
|
// test new_config
|
||||||
//printf("descriptor: %s\n", desc);
|
Config_t * config2 = new_config("test test", 202);
|
||||||
//printf("change descriptor: %s\n", change);
|
print_config(config2);
|
||||||
WalletPtr_t * wallet = new_wallet(name, desc, change);
|
|
||||||
|
|
||||||
sync_wallet(&wallet);
|
// test free_config
|
||||||
sync_wallet(&wallet);
|
free_config(config2);
|
||||||
|
// verify print_config after free_config fails (invalid data)
|
||||||
|
////print_config(config2);
|
||||||
|
// verify free_config after free_config fails (double free detected, core dumped)
|
||||||
|
////free_config(config2);
|
||||||
|
|
||||||
char const * address1 = new_address(&wallet);
|
//char const * name = "test_wallet";
|
||||||
printf("address1: %s\n", address1);
|
//char const * desc = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)";
|
||||||
char const * address2 = new_address(&wallet);
|
//char const * change = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)";
|
||||||
printf("address: %s\n", address2);
|
|
||||||
|
////printf("wallet name: %s\n", name);
|
||||||
|
////printf("descriptor: %s\n", desc);
|
||||||
|
////printf("change descriptor: %s\n", change);
|
||||||
|
//WalletPtr_t * wallet = new_wallet(name, desc, change);
|
||||||
|
|
||||||
|
//sync_wallet(&wallet);
|
||||||
|
//sync_wallet(&wallet);
|
||||||
|
|
||||||
|
//char const * address1 = new_address(&wallet);
|
||||||
|
//printf("address1: %s\n", address1);
|
||||||
|
//char const * address2 = new_address(&wallet);
|
||||||
|
//printf("address: %s\n", address2);
|
||||||
|
|
||||||
//free_wallet(wallet);
|
//free_wallet(wallet);
|
||||||
//sync_wallet(&wallet);
|
////sync_wallet(&wallet);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
3
settings.gradle
Normal file
3
settings.gradle
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
rootProject.name = 'bdk_ffi'
|
||||||
|
|
||||||
|
include 'jvm'
|
174
src/lib.rs
174
src/lib.rs
@ -11,11 +11,17 @@ use bdk::wallet::AddressIndex::New;
|
|||||||
use safer_ffi::char_p::{char_p_ref, char_p_boxed};
|
use safer_ffi::char_p::{char_p_ref, char_p_boxed};
|
||||||
use safer_ffi::boxed::Box;
|
use safer_ffi::boxed::Box;
|
||||||
|
|
||||||
|
#[ffi_export]
|
||||||
|
fn print_string (string: char_p_ref)
|
||||||
|
{
|
||||||
|
println!("{}", string);
|
||||||
|
}
|
||||||
|
|
||||||
/// Concatenate two input UTF-8 (_e.g._, ASCII) strings.
|
/// Concatenate two input UTF-8 (_e.g._, ASCII) strings.
|
||||||
///
|
///
|
||||||
/// \remark The returned string must be freed with `rust_free_string`
|
/// The returned string must be freed with `rust_free_string`
|
||||||
#[ffi_export]
|
#[ffi_export]
|
||||||
fn concat_string<'a>(fst: char_p_ref<'a>, snd: char_p_ref<'a>)
|
fn concat_string(fst: char_p_ref, snd: char_p_ref)
|
||||||
-> char_p_boxed
|
-> char_p_boxed
|
||||||
{
|
{
|
||||||
let fst = fst.to_str(); // : &'_ str
|
let fst = fst.to_str(); // : &'_ str
|
||||||
@ -24,13 +30,7 @@ fn concat_string<'a>(fst: char_p_ref<'a>, snd: char_p_ref<'a>)
|
|||||||
ccat
|
ccat
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ffi_export]
|
/// Frees a Rust-allocated string
|
||||||
fn print_string (string: char_p_ref)
|
|
||||||
{
|
|
||||||
println!("{}", string);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Frees a Rust-allocated string.
|
|
||||||
#[ffi_export]
|
#[ffi_export]
|
||||||
fn free_string (string: char_p_boxed)
|
fn free_string (string: char_p_boxed)
|
||||||
{
|
{
|
||||||
@ -40,105 +40,97 @@ fn free_string (string: char_p_boxed)
|
|||||||
/// A `struct` usable from both Rust and C
|
/// A `struct` usable from both Rust and C
|
||||||
#[derive_ReprC]
|
#[derive_ReprC]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Point {
|
pub struct Config {
|
||||||
x: f64,
|
name: char_p_boxed,
|
||||||
y: f64,
|
count: i64
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Export a Rust function to the C world. */
|
/// Debug print a Point
|
||||||
/// Returns the middle point of `[a, b]`.
|
|
||||||
#[ffi_export]
|
#[ffi_export]
|
||||||
fn mid_point(a: Point, b: Point) -> Point {
|
fn print_config(config: &Config) {
|
||||||
Point {
|
println!("{:?}", config);
|
||||||
x: (a.x + b.x) / 2.,
|
|
||||||
y: (a.y + b.y) / 2.,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pretty-prints a point using Rust's formatting logic.
|
/// Create a new Config
|
||||||
#[ffi_export]
|
#[ffi_export]
|
||||||
fn print_point(point: Point) {
|
fn new_config(name: char_p_ref, count: i64) -> Box<Config> {
|
||||||
println!("{:?}", point);
|
let name = name.to_string().try_into().unwrap();
|
||||||
|
Box::new(Config { name, count })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ffi_export]
|
#[ffi_export]
|
||||||
fn new_point(x: f64, y: f64) -> Point {
|
fn free_config(config: Box<Config>) {
|
||||||
Point { x, y }
|
drop(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
//#[ffi_export]
|
//#[derive_ReprC]
|
||||||
//fn free_point(point: Point) {
|
//#[ReprC::opaque]
|
||||||
// drop(point)
|
//pub struct WalletPtr {
|
||||||
|
// raw: Wallet<ElectrumBlockchain, Tree>,
|
||||||
//}
|
//}
|
||||||
|
|
||||||
#[derive_ReprC]
|
//impl From<Wallet<ElectrumBlockchain, Tree>> for WalletPtr {
|
||||||
#[ReprC::opaque]
|
// fn from(wallet: Wallet<ElectrumBlockchain, Tree>) -> Self {
|
||||||
pub struct WalletPtr {
|
// WalletPtr {
|
||||||
raw: Wallet<ElectrumBlockchain, Tree>,
|
// raw: wallet,
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
impl From<Wallet<ElectrumBlockchain, Tree>> for WalletPtr {
|
//#[ffi_export]
|
||||||
fn from(wallet: Wallet<ElectrumBlockchain, Tree>) -> Self {
|
//fn new_wallet<'a>(
|
||||||
WalletPtr {
|
// name: char_p_ref<'a>,
|
||||||
raw: wallet,
|
// descriptor: char_p_ref<'a>,
|
||||||
}
|
// change_descriptor: Option<char_p_ref<'a>>,
|
||||||
}
|
//) -> Box<WalletPtr> {
|
||||||
}
|
// let name = name.to_string();
|
||||||
|
// let descriptor = descriptor.to_string();
|
||||||
|
// let change_descriptor = change_descriptor.map(|s| s.to_string());
|
||||||
|
//
|
||||||
|
// let database = sled::open("./wallet_db").unwrap();
|
||||||
|
// let tree = database.open_tree(name.clone()).unwrap();
|
||||||
|
//
|
||||||
|
// let descriptor: &str = descriptor.as_str();
|
||||||
|
// let change_descriptor: Option<&str> = change_descriptor.as_deref();
|
||||||
|
//
|
||||||
|
// let electrum_url = "ssl://electrum.blockstream.info:60002";
|
||||||
|
// let client = Client::new(&electrum_url).unwrap();
|
||||||
|
//
|
||||||
|
// let wallet = Wallet::new(
|
||||||
|
// descriptor,
|
||||||
|
// change_descriptor,
|
||||||
|
// Testnet,
|
||||||
|
// tree,
|
||||||
|
// ElectrumBlockchain::from(client),
|
||||||
|
// )
|
||||||
|
// .unwrap();
|
||||||
|
//
|
||||||
|
// Box::new(WalletPtr::from(wallet))
|
||||||
|
//}
|
||||||
|
|
||||||
#[ffi_export]
|
//#[ffi_export]
|
||||||
fn new_wallet<'a>(
|
//fn sync_wallet( wallet: &Box<WalletPtr>) {
|
||||||
name: char_p_ref<'a>,
|
// println!("before sync");
|
||||||
descriptor: char_p_ref<'a>,
|
// let _r = wallet.raw.sync(log_progress(), Some(100));
|
||||||
change_descriptor: Option<char_p_ref<'a>>,
|
// println!("after sync");
|
||||||
) -> Box<WalletPtr> {
|
//}
|
||||||
let name = name.to_string();
|
|
||||||
let descriptor = descriptor.to_string();
|
|
||||||
let change_descriptor = change_descriptor.map(|s| s.to_string());
|
|
||||||
|
|
||||||
let database = sled::open("./wallet_db").unwrap();
|
//#[ffi_export]
|
||||||
let tree = database.open_tree(name.clone()).unwrap();
|
//fn new_address( wallet: &Box<WalletPtr>) -> char_p_boxed {
|
||||||
|
// println!("before new_address");
|
||||||
|
// let new_address = wallet.raw.get_address(New);
|
||||||
|
// println!("after new_address: {:?}", new_address);
|
||||||
|
// let new_address = new_address.unwrap();
|
||||||
|
// let new_address = new_address.to_string();
|
||||||
|
// println!("new address: ${}", new_address);
|
||||||
|
// new_address.try_into().unwrap()
|
||||||
|
//}
|
||||||
|
|
||||||
let descriptor: &str = descriptor.as_str();
|
//#[ffi_export]
|
||||||
let change_descriptor: Option<&str> = change_descriptor.as_deref();
|
//fn free_wallet( wallet: Box<WalletPtr>) {
|
||||||
|
// drop(wallet)
|
||||||
let electrum_url = "ssl://electrum.blockstream.info:60002";
|
//}
|
||||||
let client = Client::new(&electrum_url).unwrap();
|
|
||||||
|
|
||||||
let wallet = Wallet::new(
|
|
||||||
descriptor,
|
|
||||||
change_descriptor,
|
|
||||||
Testnet,
|
|
||||||
tree,
|
|
||||||
ElectrumBlockchain::from(client),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Box::new(WalletPtr::from(wallet))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ffi_export]
|
|
||||||
fn sync_wallet( wallet: &Box<WalletPtr>) {
|
|
||||||
println!("before sync");
|
|
||||||
let _r = wallet.raw.sync(log_progress(), Some(100));
|
|
||||||
println!("after sync");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ffi_export]
|
|
||||||
fn new_address( wallet: &Box<WalletPtr>) -> char_p_boxed {
|
|
||||||
println!("before new_address");
|
|
||||||
let new_address = wallet.raw.get_address(New);
|
|
||||||
println!("after new_address: {:?}", new_address);
|
|
||||||
let new_address = new_address.unwrap();
|
|
||||||
let new_address = new_address.to_string();
|
|
||||||
println!("new address: ${}", new_address);
|
|
||||||
new_address.try_into().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ffi_export]
|
|
||||||
fn free_wallet( wallet: Box<WalletPtr>) {
|
|
||||||
drop(wallet)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The following test function is necessary for the header generation.
|
/// The following test function is necessary for the header generation.
|
||||||
#[::safer_ffi::cfg_headers]
|
#[::safer_ffi::cfg_headers]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user