From 757113c0028d6602a96136df3385acb9d97087e6 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Thu, 24 Jun 2021 13:49:25 -0700 Subject: [PATCH] Simplify Kotlin Wallet api --- .../org/bitcoindevkit/bdk/AndroidLibTest.kt | 5 +-- bdk-kotlin/jvm/build.gradle | 3 +- .../bdk/{Error.kt => JnaError.kt} | 5 ++- .../org/bitcoindevkit/bdk/JnaException.kt | 3 ++ .../java/org/bitcoindevkit/bdk/LibBase.kt | 2 +- .../main/java/org/bitcoindevkit/bdk/LibJna.kt | 12 +++--- .../java/org/bitcoindevkit/bdk/ResultBase.kt | 37 +++++++++++++++++++ .../org/bitcoindevkit/bdk/StringResult.kt | 32 +++++++--------- .../java/org/bitcoindevkit/bdk/VoidResult.kt | 26 ++++++------- .../main/java/org/bitcoindevkit/bdk/Wallet.kt | 35 +++++++++++------- .../org/bitcoindevkit/bdk/WalletResult.kt | 37 ++++++------------- .../java/org/bitcoindevkit/bdk/JvmLibTest.kt | 8 +--- bdk-kotlin/test-fixtures/build.gradle | 2 +- .../java/org/bitcoindevkit/bdk/LibTest.kt | 30 +++++---------- src/wallet.rs | 5 +-- 15 files changed, 125 insertions(+), 117 deletions(-) rename bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/{Error.kt => JnaError.kt} (94%) create mode 100644 bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/JnaException.kt create mode 100644 bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/ResultBase.kt diff --git a/bdk-kotlin/android/src/androidTest/java/org/bitcoindevkit/bdk/AndroidLibTest.kt b/bdk-kotlin/android/src/androidTest/java/org/bitcoindevkit/bdk/AndroidLibTest.kt index a104f6a..8107e8e 100644 --- a/bdk-kotlin/android/src/androidTest/java/org/bitcoindevkit/bdk/AndroidLibTest.kt +++ b/bdk-kotlin/android/src/androidTest/java/org/bitcoindevkit/bdk/AndroidLibTest.kt @@ -1,9 +1,6 @@ package org.bitcoindevkit.bdk -import android.util.Log import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.sun.jna.Native -import org.junit.* import org.junit.runner.RunWith @@ -16,5 +13,5 @@ import org.junit.Assert.* */ @RunWith(AndroidJUnit4::class) class AndroidLibTest : LibTest() { - + } diff --git a/bdk-kotlin/jvm/build.gradle b/bdk-kotlin/jvm/build.gradle index 9640d69..2330523 100644 --- a/bdk-kotlin/jvm/build.gradle +++ b/bdk-kotlin/jvm/build.gradle @@ -17,8 +17,7 @@ dependencies { api "org.slf4j:slf4j-api:1.7.30" testImplementation "ch.qos.logback:logback-classic:1.2.3" testImplementation "ch.qos.logback:logback-core:1.2.3" - testImplementation 'org.jetbrains.kotlin:kotlin-test-junit' - testImplementation (project(':test-fixtures')) + testImplementation(project(':test-fixtures')) } publishing { diff --git a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/Error.kt b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/JnaError.kt similarity index 94% rename from bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/Error.kt rename to bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/JnaError.kt index aeda367..598e4a5 100644 --- a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/Error.kt +++ b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/JnaError.kt @@ -1,6 +1,6 @@ package org.bitcoindevkit.bdk -enum class Error { +enum class JnaError { InvalidU32Bytes, Generic, ScriptDoesntHaveAddressForm, @@ -37,7 +37,8 @@ enum class Error { Hex, Psbt, Electrum, -// Esplora + + // Esplora // CompactFilters Sled, } \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/JnaException.kt b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/JnaException.kt new file mode 100644 index 0000000..6ce9768 --- /dev/null +++ b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/JnaException.kt @@ -0,0 +1,3 @@ +package org.bitcoindevkit.bdk + +class JnaException internal constructor(val err: JnaError) : Exception() \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/LibBase.kt b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/LibBase.kt index e00eec0..03ebf78 100644 --- a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/LibBase.kt +++ b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/LibBase.kt @@ -3,7 +3,7 @@ package org.bitcoindevkit.bdk import com.sun.jna.Native abstract class LibBase { - + protected val libJna: LibJna get() = Native.load("bdk_ffi", LibJna::class.java) } \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/LibJna.kt b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/LibJna.kt index d186ef5..c1de293 100644 --- a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/LibJna.kt +++ b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/LibJna.kt @@ -1,6 +1,8 @@ package org.bitcoindevkit.bdk -import com.sun.jna.* +import com.sun.jna.Library +import com.sun.jna.Pointer +import com.sun.jna.PointerType interface LibJna : Library { @@ -35,13 +37,13 @@ interface LibJna : Library { // void free_string_result ( // StringResult_t * string_result); fun free_string_result(string_result: StringResult_t) - + // typedef struct WalletRef WalletRef_t; class WalletRef_t : PointerType { constructor() : super() constructor(pointer: Pointer) : super(pointer) } - + // void free_wallet_ref ( // WalletRef_t * wallet_ref); fun free_wallet_ref(wallet_ref: WalletRef_t) @@ -61,11 +63,11 @@ interface LibJna : Library { descriptor: String, changeDescriptor: String? ): WalletResult_t - + // char * get_wallet_err ( // WalletResult_t const * wallet_result); fun get_wallet_err(wallet_result: WalletResult_t): Pointer? - + // WalletRef_t * get_wallet_ok ( // WalletResult_t const * wallet_result); fun get_wallet_ok(wallet_result: WalletResult_t): WalletRef_t? diff --git a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/ResultBase.kt b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/ResultBase.kt new file mode 100644 index 0000000..eb13cc5 --- /dev/null +++ b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/ResultBase.kt @@ -0,0 +1,37 @@ +package org.bitcoindevkit.bdk + +import com.sun.jna.Pointer +import com.sun.jna.PointerType +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +abstract class ResultBase internal constructor(protected val resultT: PT) : + LibBase() { + + protected open val log: Logger = LoggerFactory.getLogger(ResultBase::class.java) + + protected abstract fun err(): Pointer? + + protected abstract fun ok(): RT + + protected abstract fun free(pointer: PT) + + private fun checkErr() { + val errPointer = err() + val err = errPointer?.getString(0) + libJna.free_string(errPointer) + if (err != null) { + throw JnaException(JnaError.valueOf(err)) + } + } + + fun value(): RT { + checkErr() + return ok() + } + + protected fun finalize() { + free(resultT) + log.debug("$resultT freed") + } +} \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/StringResult.kt b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/StringResult.kt index 4809123..b062f36 100644 --- a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/StringResult.kt +++ b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/StringResult.kt @@ -1,32 +1,26 @@ package org.bitcoindevkit.bdk +import com.sun.jna.Pointer import org.slf4j.Logger import org.slf4j.LoggerFactory -class StringResult internal constructor(private val stringResultT: LibJna.StringResult_t) : LibBase() { +class StringResult internal constructor(stringResultT: LibJna.StringResult_t) : + ResultBase(stringResultT) { - private val log: Logger = LoggerFactory.getLogger(StringResult::class.java) + override val log: Logger = LoggerFactory.getLogger(StringResult::class.java) - fun isErr(): Boolean { - return libJna.get_string_err(stringResultT) != null + override fun err(): Pointer? { + return libJna.get_string_err(resultT) } - - fun err(): Error? { - val errPointer = libJna.get_string_err(stringResultT) - val err = errPointer?.getString(0) - libJna.free_string(errPointer) - return err?.let { Error.valueOf(it) } - } - - fun ok(): String? { - val okPointer = libJna.get_string_ok(stringResultT) - val ok = okPointer?.getString(0) + + override fun ok(): String { + val okPointer = libJna.get_string_ok(resultT) + val ok = okPointer!!.getString(0) libJna.free_string(okPointer) return ok } - - protected fun finalize() { - libJna.free_string_result(stringResultT) - log.debug("StringResult_t freed") + + override fun free(pointer: LibJna.StringResult_t) { + libJna.free_string_result(resultT) } } \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/VoidResult.kt b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/VoidResult.kt index dd42517..3f4cb5f 100644 --- a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/VoidResult.kt +++ b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/VoidResult.kt @@ -1,25 +1,23 @@ package org.bitcoindevkit.bdk +import com.sun.jna.Pointer import org.slf4j.Logger import org.slf4j.LoggerFactory -class VoidResult internal constructor(private val voidResultT: LibJna.VoidResult_t) : LibBase() { +class VoidResult internal constructor(voidResultT: LibJna.VoidResult_t) : + ResultBase(voidResultT) { - private val log: Logger = LoggerFactory.getLogger(VoidResult::class.java) + override val log: Logger = LoggerFactory.getLogger(VoidResult::class.java) - fun isErr(): Boolean { - return libJna.get_void_err(voidResultT) != null + override fun err(): Pointer? { + return libJna.get_void_err(resultT) } - - fun err(): Error? { - val errPointer = libJna.get_void_err(voidResultT) - val err = errPointer?.getString(0) - libJna.free_string(errPointer) - return err?.let { Error.valueOf(it) } + + override fun ok() { + // Void } - - protected fun finalize() { - libJna.free_void_result(voidResultT) - log.debug("VoidResult_t freed") + + override fun free(pointer: LibJna.VoidResult_t) { + libJna.free_void_result(resultT) } } \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/Wallet.kt b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/Wallet.kt index 5ae9878..7b62e24 100644 --- a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/Wallet.kt +++ b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/Wallet.kt @@ -3,23 +3,30 @@ package org.bitcoindevkit.bdk import org.slf4j.Logger import org.slf4j.LoggerFactory -class Wallet internal constructor( - private val walletRefT: LibJna.WalletRef_t, +class Wallet constructor( + name: String, + descriptor: String, + changeDescriptor: String?, ) : LibBase() { - - private val log: Logger = LoggerFactory.getLogger(Wallet::class.java) - - fun sync(): VoidResult { - return VoidResult(libJna.sync_wallet(walletRefT.pointer)) - } - - fun getAddress(): StringResult { - return StringResult(libJna.new_address(walletRefT.pointer)) + + val log: Logger = LoggerFactory.getLogger(Wallet::class.java) + + private val walletResult = + WalletResult(libJna.new_wallet_result(name, descriptor, changeDescriptor)) + private val walletRefT = walletResult.value() + + fun sync() { + val voidResult = VoidResult(libJna.sync_wallet(walletRefT.pointer)) + return voidResult.value() } - protected fun finalize() { + fun getAddress(): String { + val stringResult = StringResult(libJna.new_address(walletRefT.pointer)) + return stringResult.value() + } + + protected fun finalize(pointer: LibJna.WalletResult_t) { libJna.free_wallet_ref(walletRefT) - log.debug("WalletRef_t freed") + log.debug("$walletRefT freed") } - } \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/WalletResult.kt b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/WalletResult.kt index 1f882d1..46b7be7 100644 --- a/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/WalletResult.kt +++ b/bdk-kotlin/jvm/src/main/java/org/bitcoindevkit/bdk/WalletResult.kt @@ -1,36 +1,23 @@ package org.bitcoindevkit.bdk +import com.sun.jna.Pointer import org.slf4j.Logger import org.slf4j.LoggerFactory -class WalletResult( - name: String, - descriptor: String, - changeDescriptor: String?, -) : LibBase() { - - private val log: Logger = LoggerFactory.getLogger(WalletResult::class.java) - private val walletResultT = libJna.new_wallet_result(name, descriptor, changeDescriptor) - - fun isErr(): Boolean { - return libJna.get_wallet_err(walletResultT) != null +class WalletResult internal constructor(walletResultT: LibJna.WalletResult_t) : + ResultBase(walletResultT) { + + override val log: Logger = LoggerFactory.getLogger(WalletResult::class.java) + + override fun err(): Pointer? { + return libJna.get_wallet_err(resultT) } - fun err(): Error? { - val errPointer = libJna.get_wallet_err(walletResultT) - val err = errPointer?.getString(0) - libJna.free_string(errPointer) - return err?.let { Error.valueOf(it) } + override fun ok(): LibJna.WalletRef_t { + return libJna.get_wallet_ok(resultT)!! } - fun ok(): Wallet? { - val okWalletRef = libJna.get_wallet_ok(walletResultT) - return if (okWalletRef != null) Wallet(okWalletRef) else null + override fun free(pointer: LibJna.WalletResult_t) { + libJna.free_wallet_result(resultT) } - - protected fun finalize() { - libJna.free_wallet_result(walletResultT) - log.debug("WalletResult_t freed") - } - } \ No newline at end of file diff --git a/bdk-kotlin/jvm/src/test/java/org/bitcoindevkit/bdk/JvmLibTest.kt b/bdk-kotlin/jvm/src/test/java/org/bitcoindevkit/bdk/JvmLibTest.kt index 2ce5b1a..8f97dfd 100644 --- a/bdk-kotlin/jvm/src/test/java/org/bitcoindevkit/bdk/JvmLibTest.kt +++ b/bdk-kotlin/jvm/src/test/java/org/bitcoindevkit/bdk/JvmLibTest.kt @@ -1,15 +1,9 @@ package org.bitcoindevkit.bdk -import com.sun.jna.Native -import org.junit.* -import org.junit.Assert.assertEquals -import kotlin.test.assertNotNull -import kotlin.test.assertNull - /** * Library test, which will execute on linux host. * */ class JvmLibTest : LibTest() { - + } diff --git a/bdk-kotlin/test-fixtures/build.gradle b/bdk-kotlin/test-fixtures/build.gradle index 6c6b4ca..6f80396 100644 --- a/bdk-kotlin/test-fixtures/build.gradle +++ b/bdk-kotlin/test-fixtures/build.gradle @@ -8,7 +8,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "net.java.dev.jna:jna:5.8.0" implementation (project(':jvm')) - implementation 'org.jetbrains.kotlin:kotlin-test-junit' + implementation "junit:junit:4.13.2" //implementation "org.mockito.kotlin:mockito-kotlin:3.2.0" api "org.slf4j:slf4j-api:1.7.30" } diff --git a/bdk-kotlin/test-fixtures/src/main/java/org/bitcoindevkit/bdk/LibTest.kt b/bdk-kotlin/test-fixtures/src/main/java/org/bitcoindevkit/bdk/LibTest.kt index 2628607..70e70ec 100644 --- a/bdk-kotlin/test-fixtures/src/main/java/org/bitcoindevkit/bdk/LibTest.kt +++ b/bdk-kotlin/test-fixtures/src/main/java/org/bitcoindevkit/bdk/LibTest.kt @@ -4,6 +4,7 @@ import org.junit.* import org.junit.Assert.* import org.slf4j.Logger import org.slf4j.LoggerFactory +import javax.management.Descriptor /** * Library test, which will execute on linux host. @@ -21,21 +22,17 @@ abstract class LibTest : LibBase() { @Test fun walletResultError() { - val badWalletResult = WalletResult("bad", "bad", "bad") - assertTrue(badWalletResult.isErr()) - val walletErr = badWalletResult.err() - assertNotNull(walletErr) - log.debug("wallet error $walletErr") - assertEquals(Error.Descriptor, walletErr) - val wallet = badWalletResult.ok() - assertNull(wallet) + val jnaException = assertThrows(JnaException::class.java) { + Wallet("bad", "bad", "bad") + } + assertEquals(jnaException.err, JnaError.Descriptor) } @Test fun walletResultFinalize() { val names = listOf("one", "two", "three") names.map { - val wallet = WalletResult(it, desc, change) + val wallet = Wallet(it, desc, change) assertNotNull(wallet) } System.gc() @@ -44,23 +41,16 @@ abstract class LibTest : LibBase() { @Test fun walletSync() { - val walletResult = WalletResult(name, desc, change) - val wallet = walletResult.ok() + val wallet = Wallet(name, desc, change) assertNotNull(wallet) - val syncResult = wallet!!.sync(); - assertFalse(syncResult.isErr()) - assertNull(syncResult.err()) + wallet.sync() } @Test fun walletNewAddress() { - val walletResult = WalletResult(name, desc, change) - val wallet = walletResult.ok() + val wallet = Wallet(name, desc, change) assertNotNull(wallet) - val addressResult = wallet!!.getAddress() - assertFalse(addressResult.isErr()) - assertNull(addressResult.err()) - val address = addressResult.ok() + val address = wallet.getAddress() assertNotNull(address) log.debug("address created from kotlin: $address") assertEquals(address, "tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e") diff --git a/src/wallet.rs b/src/wallet.rs index cfd72bc..988bede 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -129,13 +129,12 @@ fn get_wallet_ok<'lt>(wallet_result: &'lt WalletResult) -> Option(wallet_ref: &'lt WalletRef<'lt>) -> Box { - let void_result = wallet_ref - .raw.sync(log_progress(), Some(100)); + let void_result = wallet_ref.raw.sync(log_progress(), Some(100)); Box::new(VoidResult { raw: void_result }) }