diff --git a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/FfiResult.kt b/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/FfiResult.kt deleted file mode 100644 index 3755617..0000000 --- a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/FfiResult.kt +++ /dev/null @@ -1,15 +0,0 @@ -package org.bitcoindevkit.bdk - -import com.sun.jna.Pointer -import com.sun.jna.Structure - -abstract class FfiResult : Structure { - constructor() : super() - constructor(pointer: Pointer) : super(pointer) - - @JvmField - var ok: Pointer? = null - - @JvmField - var err: Pointer? = null -} \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/LibJna.kt b/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/LibJna.kt index bfb5383..41789c5 100644 --- a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/LibJna.kt +++ b/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/LibJna.kt @@ -6,15 +6,21 @@ interface LibJna : Library { // typedef struct { // - // char * * ok; + // char * ok; // - // char * * err; + // char * err; // - // } FfiResult_char_ptr_t; - open class FfiResult_char_ptr_t : FfiResult() { + //} FfiResult_char_ptr_t; + open class FfiResult_char_ptr_t : Structure() { class ByValue : FfiResult_char_ptr_t(), Structure.ByValue class ByReference : FfiResult_char_ptr_t(), Structure.ByReference + @JvmField + var ok: String = "" + + @JvmField + var err: String = "" + override fun getFieldOrder() = listOf("ok", "err") } @@ -24,21 +30,27 @@ interface LibJna : Library { // typedef struct { // - // void * ok; + // int32_t ok; // - // char * * err; + // char * err; // - // } FfiResult_void_t; - open class FfiResult_void_t : FfiResult() { - class ByValue : FfiResult_void_t(), Structure.ByValue - class ByReference : FfiResult_void_t(), Structure.ByReference + //} FfiResult_int32_t; + open class FfiResult_int32_t : Structure() { + class ByValue : FfiResult_int32_t(), Structure.ByValue + class ByReference : FfiResult_int32_t(), Structure.ByReference + @JvmField + var ok: Int = 0 + + @JvmField + var err: String = "" + override fun getFieldOrder() = listOf("ok", "err") } - // void free_void_result ( - // FfiResult_void_t void_result); - fun free_void_result(void_result: FfiResult_void_t.ByValue) + // void free_int_result ( + // FfiResult_int32_t int_result); + fun free_int_result(void_result: FfiResult_int32_t.ByValue) // void free_string ( // char * string); @@ -82,17 +94,23 @@ interface LibJna : Library { // // OpaqueWallet_t * ok; // - // char * * err; + // char * err; // - // } FfiResult_OpaqueWallet_t; - open class FfiResult_OpaqueWallet_t : FfiResult() { - class ByValue : FfiResult_OpaqueWallet_t(), Structure.ByValue - class ByReference : FfiResult_OpaqueWallet_t(), Structure.ByReference + // } FfiResult_OpaqueWallet_ptr_t; + open class FfiResult_OpaqueWallet_ptr_t : Structure() { + class ByValue : FfiResult_OpaqueWallet_ptr_t(), Structure.ByValue + class ByReference : FfiResult_OpaqueWallet_ptr_t(), Structure.ByReference + @JvmField + var ok: OpaqueWallet_t = OpaqueWallet_t() + + @JvmField + var err: String = "" + override fun getFieldOrder() = listOf("ok", "err") } - // FfiResult_OpaqueWallet_t new_wallet_result ( + // FfiResult_OpaqueWallet_ptr_t new_wallet_result ( // char const * descriptor, // char const * change_descriptor, // BlockchainConfig_t const * blockchain_config, @@ -102,11 +120,11 @@ interface LibJna : Library { changeDescriptor: String?, blockchainConfig: BlockchainConfig_t, databaseConfig: DatabaseConfig_t, - ): FfiResult_OpaqueWallet_t.ByValue + ): FfiResult_OpaqueWallet_ptr_t.ByValue // void free_wallet_result ( - // FfiResult_OpaqueWallet_t wallet_result); - fun free_wallet_result(wallet_result: FfiResult_OpaqueWallet_t.ByValue) + // FfiResult_OpaqueWallet_ptr_t wallet_result); + fun free_wallet_result(wallet_result: FfiResult_OpaqueWallet_ptr_t.ByValue) // typedef struct { // @@ -155,19 +173,10 @@ interface LibJna : Library { // uint16_t keychain; // // } LocalUtxo_t; - open class LocalUtxo_t : Structure { - constructor() : super() - constructor(pointer: Pointer) : super(pointer) - - class ByValue : LocalUtxo_t, Structure.ByValue { - constructor() : super() - constructor(pointer: Pointer) : super(pointer) - } - - class ByReference : LocalUtxo_t, Structure.ByReference { - constructor() : super() - constructor(pointer: Pointer) : super(pointer) - } + open class LocalUtxo_t : Structure() { + + class ByValue : LocalUtxo_t(), Structure.ByValue + class ByReference : LocalUtxo_t(), Structure.ByReference @JvmField var outpoint: OutPoint_t? = null @@ -190,19 +199,10 @@ interface LibJna : Library { // size_t cap; // // } Vec_LocalUtxo_t; - open class Vec_LocalUtxo_t : Structure { - constructor() : super() - constructor(pointer: Pointer) : super(pointer) - - class ByReference : Vec_LocalUtxo_t, Structure.ByReference { - constructor() : super() - constructor(pointer: Pointer) : super(pointer) - } - - class ByValue : Vec_LocalUtxo_t, Structure.ByValue { - constructor() : super() - constructor(pointer: Pointer) : super(pointer) - } + open class Vec_LocalUtxo_t : Structure() { + + class ByReference : Vec_LocalUtxo_t(), Structure.ByReference + class ByValue : Vec_LocalUtxo_t(), Structure.ByValue @JvmField var ptr: LocalUtxo_t.ByReference? = null @@ -220,9 +220,9 @@ interface LibJna : Library { // // Vec_LocalUtxo_t ok; // - // char * * err; + // char * err; // - // } FfiResultVec_LocalUtxo_t; + // } FfiResult_Vec_LocalUtxo_t; open class FfiResultVec_LocalUtxo_t : Structure() { class ByValue : FfiResultVec_LocalUtxo_t(), Structure.ByValue @@ -232,18 +232,18 @@ interface LibJna : Library { var ok: Vec_LocalUtxo_t = Vec_LocalUtxo_t() @JvmField - var err: Pointer? = null + var err: String = "" override fun getFieldOrder() = listOf("ok", "err") } // void free_unspent_result ( - // FfiResultVec_LocalUtxo_t unspent_result); + // FfiResult_Vec_LocalUtxo_t unspent_result); fun free_unspent_result(unspent_result: FfiResultVec_LocalUtxo_t.ByValue) - // FfiResult_void_t sync_wallet ( + // FfiResult_int32_t sync_wallet ( // OpaqueWallet_t const * opaque_wallet); - fun sync_wallet(opaque_wallet: OpaqueWallet_t): FfiResult_void_t.ByValue + fun sync_wallet(opaque_wallet: OpaqueWallet_t): FfiResult_int32_t.ByValue // FfiResult_char_ptr_t new_address ( // OpaqueWallet_t const * opaque_wallet); diff --git a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/types/Result.kt b/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/types/Result.kt deleted file mode 100644 index 1208930..0000000 --- a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/types/Result.kt +++ /dev/null @@ -1,41 +0,0 @@ -package org.bitcoindevkit.bdk.types - -import com.sun.jna.Pointer -import org.bitcoindevkit.bdk.FfiResult -import org.bitcoindevkit.bdk.JnaError -import org.bitcoindevkit.bdk.JnaException -import org.bitcoindevkit.bdk.LibBase -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -abstract class Result(private val ffiResult: T): LibBase() { - - protected open val log: Logger = LoggerFactory.getLogger(Result::class.java) - - protected abstract fun getOkValue(pointer: Pointer): RT - - protected abstract fun freeResult(ffiResult: T) - - fun value(): RT { - val err = ffiResult.err - val ok = ffiResult.ok - when { - err != null -> { - val errString = err.getPointer(0).getString(0) - log.error("JnaError: $errString") - throw JnaException(JnaError.valueOf(errString)) - } - ok != null -> { - return getOkValue(ok) - } - else -> { - throw JnaException(JnaError.Generic) - } - } - } - - protected fun finalize() { - freeResult(ffiResult) - log.debug("$ffiResult freed") - } -} \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/types/StringResult.kt b/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/types/StringResult.kt index 5489fcf..2b5b35e 100644 --- a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/types/StringResult.kt +++ b/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/types/StringResult.kt @@ -1,16 +1,33 @@ package org.bitcoindevkit.bdk.types -import com.sun.jna.Pointer +import org.bitcoindevkit.bdk.JnaError +import org.bitcoindevkit.bdk.JnaException +import org.bitcoindevkit.bdk.LibBase import org.bitcoindevkit.bdk.LibJna +import org.slf4j.Logger +import org.slf4j.LoggerFactory -class StringResult constructor(stringResultPtr: LibJna.FfiResult_char_ptr_t.ByValue) : - Result(stringResultPtr) { +class StringResult constructor(private val ffiResultCharPtrT: LibJna.FfiResult_char_ptr_t.ByValue) : + LibBase() { - override fun getOkValue(pointer: Pointer): String { - return pointer.getPointer(0).getString(0) + private val log: Logger = LoggerFactory.getLogger(StringResult::class.java) + + fun value(): String { + val err = ffiResultCharPtrT.err + val ok = ffiResultCharPtrT.ok + when { + err.isNotEmpty() -> { + log.error("JnaError: $err") + throw JnaException(JnaError.valueOf(err)) + } + else -> { + return ok + } + } } - override fun freeResult(ffiResult: LibJna.FfiResult_char_ptr_t.ByValue) { - libJna.free_string_result(ffiResult) + protected fun finalize() { + libJna.free_string_result(ffiResultCharPtrT) + log.debug("$ffiResultCharPtrT freed") } } \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/types/VoidResult.kt b/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/types/VoidResult.kt index 36eb799..e3a79af 100644 --- a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/types/VoidResult.kt +++ b/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/types/VoidResult.kt @@ -1,16 +1,33 @@ package org.bitcoindevkit.bdk.types -import com.sun.jna.Pointer +import org.bitcoindevkit.bdk.JnaError +import org.bitcoindevkit.bdk.JnaException +import org.bitcoindevkit.bdk.LibBase import org.bitcoindevkit.bdk.LibJna +import org.slf4j.Logger +import org.slf4j.LoggerFactory -class VoidResult constructor(voidResultPtr: LibJna.FfiResult_void_t.ByValue) : - Result(voidResultPtr) { +class VoidResult constructor(private val ffiResultInt32T: LibJna.FfiResult_int32_t.ByValue) : + LibBase() { - override fun getOkValue(pointer: Pointer) { - // No value + private val log: Logger = LoggerFactory.getLogger(VoidResult::class.java) + + fun value(): Unit { + val err = ffiResultInt32T.err + //val ok = ffiResultInt32T.ok + when { + err.isNotEmpty() -> { + log.error("JnaError: $err") + throw JnaException(JnaError.valueOf(err)) + } + else -> { + return + } + } } - override fun freeResult(ffiResult: LibJna.FfiResult_void_t.ByValue) { - libJna.free_void_result(ffiResult) + protected fun finalize() { + libJna.free_int_result(ffiResultInt32T) + log.debug("$ffiResultInt32T freed") } } \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/wallet/VecLocalUtxoResult.kt b/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/wallet/VecLocalUtxoResult.kt index ec52e8e..86564ef 100644 --- a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/wallet/VecLocalUtxoResult.kt +++ b/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/wallet/VecLocalUtxoResult.kt @@ -7,19 +7,18 @@ import org.bitcoindevkit.bdk.LibJna import org.slf4j.Logger import org.slf4j.LoggerFactory -class VecLocalUtxoResult(private val ffiResult: LibJna.FfiResultVec_LocalUtxo_t.ByValue) : +class VecLocalUtxoResult(private val ffiResultVecLocalUtxoT: LibJna.FfiResultVec_LocalUtxo_t.ByValue) : LibBase() { - protected open val log: Logger = LoggerFactory.getLogger(VecLocalUtxoResult::class.java) + private val log: Logger = LoggerFactory.getLogger(VecLocalUtxoResult::class.java) fun value(): Array { - val err = ffiResult.err - val ok = ffiResult.ok + val err = ffiResultVecLocalUtxoT.err + val ok = ffiResultVecLocalUtxoT.ok when { - err != null -> { - val errString = err.getPointer(0).getString(0) - log.error("JnaError: $errString") - throw JnaException(JnaError.valueOf(errString)) + err .isNotEmpty() -> { + log.error("JnaError: $err") + throw JnaException(JnaError.valueOf(err)) } else -> { val first = ok.ptr!! @@ -29,7 +28,7 @@ class VecLocalUtxoResult(private val ffiResult: LibJna.FfiResultVec_LocalUtxo_t. } protected fun finalize() { - libJna.free_unspent_result(ffiResult) - log.debug("$ffiResult freed") + libJna.free_unspent_result(ffiResultVecLocalUtxoT) + log.debug("$ffiResultVecLocalUtxoT freed") } } \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/wallet/WalletResult.kt b/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/wallet/WalletResult.kt index 5082df9..52592ae 100644 --- a/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/wallet/WalletResult.kt +++ b/bdk-kotlin/jvm/src/main/kotlin/org/bitcoindevkit/bdk/wallet/WalletResult.kt @@ -1,17 +1,33 @@ package org.bitcoindevkit.bdk.wallet -import com.sun.jna.Pointer +import org.bitcoindevkit.bdk.JnaError +import org.bitcoindevkit.bdk.JnaException +import org.bitcoindevkit.bdk.LibBase import org.bitcoindevkit.bdk.LibJna -import org.bitcoindevkit.bdk.types.Result +import org.slf4j.Logger +import org.slf4j.LoggerFactory -class WalletResult constructor(walletResultPtr: LibJna.FfiResult_OpaqueWallet_t.ByValue) : - Result(walletResultPtr) { +class WalletResult constructor(private val ffiResultOpaqueWalletPtrT: LibJna.FfiResult_OpaqueWallet_ptr_t.ByValue) : + LibBase() { - override fun getOkValue(pointer: Pointer): LibJna.OpaqueWallet_t { - return LibJna.OpaqueWallet_t(pointer) + private val log: Logger = LoggerFactory.getLogger(WalletResult::class.java) + + fun value(): LibJna.OpaqueWallet_t { + val err = ffiResultOpaqueWalletPtrT.err + val ok = ffiResultOpaqueWalletPtrT.ok + when { + err.isNotEmpty() -> { + log.error("JnaError: $err") + throw JnaException(JnaError.valueOf(err)) + } + else -> { + return ok + } + } } - override fun freeResult(ffiResult: LibJna.FfiResult_OpaqueWallet_t.ByValue) { - libJna.free_wallet_result(ffiResult) + protected fun finalize() { + libJna.free_wallet_result(ffiResultOpaqueWalletPtrT) + log.debug("$ffiResultOpaqueWalletPtrT freed") } } \ No newline at end of file diff --git a/cc/bdk_ffi.h b/cc/bdk_ffi.h index b3c3dad..452f0a1 100644 --- a/cc/bdk_ffi.h +++ b/cc/bdk_ffi.h @@ -14,21 +14,8 @@ extern "C" { #endif - -#include -#include - typedef struct BlockchainConfig BlockchainConfig_t; -BlockchainConfig_t * new_electrum_config ( - char const * url, - char const * socks5, - int16_t retry, - int16_t timeout); - -void free_blockchain_config ( - BlockchainConfig_t * blockchain_config); - typedef struct DatabaseConfig DatabaseConfig_t; typedef struct OpaqueWallet OpaqueWallet_t; @@ -37,35 +24,39 @@ typedef struct { OpaqueWallet_t * ok; - char * * err; + char * err; -} FfiResult_OpaqueWallet_t; +} FfiResult_OpaqueWallet_ptr_t; -FfiResult_OpaqueWallet_t new_wallet_result ( +FfiResult_OpaqueWallet_ptr_t new_wallet_result ( char const * descriptor, char const * change_descriptor, BlockchainConfig_t const * blockchain_config, DatabaseConfig_t const * database_config); void free_wallet_result ( - FfiResult_OpaqueWallet_t wallet_result); + FfiResult_OpaqueWallet_ptr_t wallet_result); + + +#include +#include typedef struct { - void * ok; + int32_t ok; - char * * err; + char * err; -} FfiResult_void_t; +} FfiResult_int32_t; -FfiResult_void_t sync_wallet ( +FfiResult_int32_t sync_wallet ( OpaqueWallet_t const * opaque_wallet); typedef struct { - char * * ok; + char * ok; - char * * err; + char * err; } FfiResult_char_ptr_t; @@ -115,15 +106,24 @@ typedef struct { Vec_LocalUtxo_t ok; - char * * err; + char * err; -} FfiResultVec_LocalUtxo_t; +} FfiResult_Vec_LocalUtxo_t; -FfiResultVec_LocalUtxo_t list_unspent ( +FfiResult_Vec_LocalUtxo_t list_unspent ( OpaqueWallet_t const * opaque_wallet); void free_unspent_result ( - FfiResultVec_LocalUtxo_t unspent_result); + FfiResult_Vec_LocalUtxo_t unspent_result); + +BlockchainConfig_t * new_electrum_config ( + char const * url, + char const * socks5, + int16_t retry, + int16_t timeout); + +void free_blockchain_config ( + BlockchainConfig_t * blockchain_config); DatabaseConfig_t * new_memory_config (void); @@ -137,8 +137,8 @@ void free_database_config ( void free_string_result ( FfiResult_char_ptr_t string_result); -void free_void_result ( - FfiResult_void_t void_result); +void free_int_result ( + FfiResult_int32_t int_result); /** \brief * Free a Rust-allocated string diff --git a/cc/bdk_ffi_test.c b/cc/bdk_ffi_test.c index 8ea5590..ce8df5f 100644 --- a/cc/bdk_ffi_test.c +++ b/cc/bdk_ffi_test.c @@ -13,14 +13,14 @@ int main (int argc, char const * const argv[]) DatabaseConfig_t *db_config = new_memory_config(); // new wallet with bad descriptor - FfiResult_OpaqueWallet_t wallet_result = new_wallet_result("bad","bad",bc_config,db_config); - assert(wallet_result.err != NULL); + FfiResult_OpaqueWallet_ptr_t wallet_result = new_wallet_result("bad","bad",bc_config,db_config); + assert(strlen(wallet_result.err) > 0); assert(wallet_result.ok == NULL); free_blockchain_config(bc_config); free_database_config(db_config); - char *wallet_err = *wallet_result.err; + char *wallet_err = wallet_result.err; assert(wallet_err != NULL); assert( 0 == strcmp(wallet_err,"Descriptor") ); // printf("wallet err: %s\n", wallet_err); @@ -37,8 +37,9 @@ int main (int argc, char const * const argv[]) DatabaseConfig_t *db_config = new_memory_config(); // new wallet - FfiResult_OpaqueWallet_t wallet_result = new_wallet_result(desc,change,bc_config,db_config); - assert(wallet_result.err == NULL); + FfiResult_OpaqueWallet_ptr_t wallet_result = new_wallet_result(desc,change,bc_config,db_config); + // printf("wallet_result.err = %ld\n", strlen(wallet_result.err)); + assert(strlen(wallet_result.err) == 0); assert(wallet_result.ok != NULL); free_blockchain_config(bc_config); @@ -46,35 +47,35 @@ int main (int argc, char const * const argv[]) OpaqueWallet_t *wallet = wallet_result.ok; - // test sync wallet - FfiResult_void_t sync_result = sync_wallet(wallet); - assert(sync_result.ok != NULL); - assert(sync_result.err == NULL); - free_void_result(sync_result); + // sync wallet + FfiResult_int32_t sync_result = sync_wallet(wallet); + assert(sync_result.ok == 0); + assert(strlen(sync_result.err) == 0); + free_int_result(sync_result); - // test new address - FfiResult_char_ptr_t address_result1 = new_address(wallet); - assert(address_result1.ok != NULL); - assert(address_result1.err == NULL); - // printf("address1 = %s\n", *address_result1.ok); - assert( 0 == strcmp(*address_result1.ok,"tb1qgkhp034fyxeta00h0nne9tzfm0vsxq4prduzxp")); - free_string_result(address_result1); + // new address + FfiResult_char_ptr_t address1_result = new_address(wallet); + assert(address1_result.ok != NULL); + assert(strlen(address1_result.err) == 0); + // printf("address1 = %s\n", *address1_result.ok); + assert( 0 == strcmp(address1_result.ok,"tb1qgkhp034fyxeta00h0nne9tzfm0vsxq4prduzxp")); + free_string_result(address1_result); - FfiResult_char_ptr_t address_result2 = new_address(wallet); - assert(address_result2.ok != NULL); - assert(address_result2.err == NULL); - // printf("address2 = %s\n", *address_result2.ok); - assert( 0 == strcmp(*address_result2.ok,"tb1qd6u9q327sru2ljvwzdtfrdg36sapax7udz97wf")); - free_string_result(address_result2); + FfiResult_char_ptr_t address2_result = new_address(wallet); + assert(address2_result.ok != NULL); + assert(strlen(address2_result.err) == 0); + // printf("address2 = %s\n", *address2_result.ok); + assert( 0 == strcmp(address2_result.ok,"tb1qd6u9q327sru2ljvwzdtfrdg36sapax7udz97wf")); + free_string_result(address2_result); - // test free_wallet + // free_wallet free_wallet_result(wallet_result); // verify free_wallet after free_wallet fails (core dumped) //// free_wallet_result(wallet_result); // verify sync_wallet after free_wallet fails (core dumped) - //// FfiResult_void_t sync_result2 = sync_wallet(wallet); + //// FfiResult_int32_t sync_result2 = sync_wallet(wallet); } // test get unspent utxos @@ -86,8 +87,8 @@ int main (int argc, char const * const argv[]) DatabaseConfig_t *db_config = new_memory_config(); // new wallet - FfiResult_OpaqueWallet_t wallet_result = new_wallet_result(desc,change,bc_config,db_config); - assert(wallet_result.err == NULL); + FfiResult_OpaqueWallet_ptr_t wallet_result = new_wallet_result(desc,change,bc_config,db_config); + assert(strlen(wallet_result.err) == 0); assert(wallet_result.ok != NULL); free_blockchain_config(bc_config); @@ -95,16 +96,16 @@ int main (int argc, char const * const argv[]) OpaqueWallet_t *wallet = wallet_result.ok; - // test sync wallet - FfiResult_void_t sync_result = sync_wallet(wallet); - assert(sync_result.ok != NULL); - assert(sync_result.err == NULL); - free_void_result(sync_result); + // sync wallet + FfiResult_int32_t sync_result = sync_wallet(wallet); + assert(sync_result.ok == 0); + assert(strlen(sync_result.err) == 0); + free_int_result(sync_result); // list unspent - FfiResultVec_LocalUtxo_t unspent_result = list_unspent(wallet); + FfiResult_Vec_LocalUtxo_t unspent_result = list_unspent(wallet); assert(unspent_result.ok.len == 7); - assert(unspent_result.err == NULL); + assert(strlen(unspent_result.err) == 0); LocalUtxo_t * unspent_ptr = unspent_result.ok.ptr; for (int i = 0; i < unspent_result.ok.len; i++) { @@ -123,6 +124,41 @@ int main (int argc, char const * const argv[]) free_unspent_result(unspent_result); free_wallet_result(wallet_result); } + + // test balance + /*{ + char const *desc = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)"; + char const *change = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"; + + BlockchainConfig_t *bc_config = new_electrum_config("ssl://electrum.blockstream.info:60002", NULL, 5, 30); + DatabaseConfig_t *db_config = new_memory_config(); + + // new wallet + FfiResult_OpaqueWallet_ptr_t wallet_result = new_wallet_result(desc,change,bc_config,db_config); + assert(wallet_result.err == NULL); + assert(wallet_result.ok != NULL); + + free_blockchain_config(bc_config); + free_database_config(db_config); + + OpaqueWallet_t *wallet = wallet_result.ok; + + // sync wallet + FfiResult_int32_t sync_result = sync_wallet(wallet); + assert(sync_result.ok == 0); + assert(sync_result.err == NULL); + free_int_result(sync_result); + + // get balance + FfiResultT_uint64_t balance_result = balance(wallet); + assert(balance_result.err == NULL); + printf("balance = %lu\n", balance_result.ok); + assert(balance_result.ok > 0); + + // free balance and wallet results + free_u64_result(balance_result); + free_wallet_result(wallet_result); + }*/ return EXIT_SUCCESS; } diff --git a/src/types.rs b/src/types.rs index 079e9cd..1b2254f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -5,15 +5,8 @@ use safer_ffi::char_p::char_p_boxed; #[repr(C)] #[derive(Debug)] pub struct FfiResult { - pub ok: Option>, - pub err: Option>, -} - -#[derive_ReprC] -#[repr(C)] -pub struct FfiResultVec { - pub ok: repr_c::Vec, - pub err: Option>, + pub ok: T, + pub err: char_p_boxed, } #[ffi_export] @@ -22,8 +15,8 @@ fn free_string_result(string_result: FfiResult) { } #[ffi_export] -fn free_void_result(void_result: FfiResult<()>) { - drop(void_result) +fn free_int_result(int_result: FfiResult) { + drop(int_result) } // TODO do we need this? remove? diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 300d4c0..b6b1a1a 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -13,7 +13,8 @@ use blockchain::BlockchainConfig; use database::DatabaseConfig; use crate::error::get_name; -use crate::types::{FfiResult, FfiResultVec}; +use crate::types::FfiResult; +use std::ffi::CString; mod blockchain; mod database; @@ -32,7 +33,7 @@ fn new_wallet_result( change_descriptor: Option, blockchain_config: &BlockchainConfig, database_config: &DatabaseConfig, -) -> FfiResult { +) -> FfiResult>> { let descriptor = descriptor.to_string(); let change_descriptor = change_descriptor.map(|s| s.to_string()); let bc_config = &blockchain_config.raw; @@ -42,11 +43,11 @@ fn new_wallet_result( match wallet_result { Ok(w) => FfiResult { ok: Some(Box::new(OpaqueWallet { raw: w })), - err: None, + err: char_p_boxed::from(CString::default()), }, Err(e) => FfiResult { ok: None, - err: Some(Box::new(char_p_boxed::try_from(get_name(&e)).unwrap())), + err: char_p_boxed::try_from(get_name(&e)).unwrap(), }, } } @@ -69,23 +70,23 @@ fn new_wallet( } #[ffi_export] -fn free_wallet_result(wallet_result: FfiResult) { +fn free_wallet_result(wallet_result: FfiResult>>) { drop(wallet_result); } // wallet operations #[ffi_export] -fn sync_wallet(opaque_wallet: &OpaqueWallet) -> FfiResult<()> { - let void_result = opaque_wallet.raw.sync(log_progress(), Some(100)); - match void_result { - Ok(v) => FfiResult { - ok: Some(Box::new(v)), - err: None, +fn sync_wallet(opaque_wallet: &OpaqueWallet) -> FfiResult { + let int_result = opaque_wallet.raw.sync(log_progress(), Some(100)); + match int_result { + Ok(_v) => FfiResult { + ok: 0, + err: char_p_boxed::from(CString::default()), }, Err(e) => FfiResult { - ok: None, - err: Some(Box::new(char_p_boxed::try_from(get_name(&e)).unwrap())), + ok: -1, + err: char_p_boxed::try_from(get_name(&e)).unwrap(), }, } } @@ -96,37 +97,37 @@ fn new_address(opaque_wallet: &OpaqueWallet) -> FfiResult { let string_result = new_address.map(|a| a.to_string()); match string_result { Ok(a) => FfiResult { - ok: Some(Box::new(char_p_boxed::try_from(a).unwrap())), - err: None, + ok: char_p_boxed::try_from(a).unwrap(), + err: char_p_boxed::from(CString::default()), }, Err(e) => FfiResult { - ok: None, - err: Some(Box::new(char_p_boxed::try_from(get_name(&e)).unwrap())), + ok: char_p_boxed::from(CString::default()), + err: char_p_boxed::try_from(get_name(&e)).unwrap(), }, } } #[ffi_export] -fn list_unspent(opaque_wallet: &OpaqueWallet) -> FfiResultVec { +fn list_unspent(opaque_wallet: &OpaqueWallet) -> FfiResult> { let unspent_result = opaque_wallet.raw.list_unspent(); match unspent_result { - Ok(v) => FfiResultVec { + Ok(v) => FfiResult { ok: { let ve: Vec = v.iter().map(|lu| LocalUtxo::from(lu)).collect(); repr_c::Vec::from(ve) }, - err: None, + err: char_p_boxed::from(CString::default()), }, - Err(e) => FfiResultVec { + Err(e) => FfiResult { ok: repr_c::Vec::EMPTY, - err: Some(Box::new(char_p_boxed::try_from(get_name(&e)).unwrap())), + err: char_p_boxed::try_from(get_name(&e)).unwrap(), }, } } #[ffi_export] -fn free_unspent_result(unspent_result: FfiResultVec) { +fn free_unspent_result(unspent_result: FfiResult>) { drop(unspent_result) } diff --git a/test.sh b/test.sh index 99a3ac8..c5a23fc 100755 --- a/test.sh +++ b/test.sh @@ -6,8 +6,8 @@ cargo test --features c-headers -- generate_headers # cc export LD_LIBRARY_PATH=`pwd`/target/debug -valgrind --leak-check=full --show-leak-kinds=all cc/bdk_ffi_test -#cc/bdk_ffi_test +#valgrind --leak-check=full --show-leak-kinds=all cc/bdk_ffi_test +cc/bdk_ffi_test # bdk-kotlin (cd bdk-kotlin && gradle test)