*** ./temp-without-docs/org/bitcoindevkit/bdk.kt 2022-03-15 22:56:50.000000000 -0400 --- ./android/src/main/kotlin/org/bitcoindevkit/bdk.kt 2022-03-15 23:00:28.000000000 -0400 *************** *** 1,181 **** --- 1,194 ---- // This file was autogenerated by some hot garbage in the `uniffi` crate. // Trust me, you don't want to mess with it! @file:Suppress("NAME_SHADOWING") package org.bitcoindevkit; // Common helper code. // // Ideally this would live in a separate .kt file where it can be unittested etc // in isolation, and perhaps even published as a re-useable package. // // However, it's important that the detils of how this helper code works (e.g. the // way that different builtin types are passed across the FFI) exactly match what's // expected by the Rust code on the other side of the interface. In practice right // now that means coming from the exact some version of `uniffi` that was used to // compile the Rust component. The easiest way to ensure this is to bundle the Kotlin // helpers directly inline like we're doing here. import com.sun.jna.Library import com.sun.jna.Native import com.sun.jna.Pointer import com.sun.jna.Structure import com.sun.jna.ptr.ByReference import java.nio.ByteBuffer import java.nio.ByteOrder import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.locks.ReentrantLock import kotlin.concurrent.withLock // The Rust Buffer and 3 templated methods (alloc, free, reserve). // This is a helper for safely working with byte buffers returned from the Rust code. // A rust-owned buffer is represented by its capacity, its current length, and a // pointer to the underlying data. + + /** + * @suppress + */ @Structure.FieldOrder("capacity", "len", "data") open class RustBuffer : Structure() { @JvmField var capacity: Int = 0 @JvmField var len: Int = 0 @JvmField var data: Pointer? = null class ByValue : RustBuffer(), Structure.ByValue class ByReference : RustBuffer(), Structure.ByReference companion object { internal fun alloc(size: Int = 0) = rustCall() { status -> _UniFFILib.INSTANCE.ffi_bdk_6983_rustbuffer_alloc(size, status).also { if(it.data == null) { throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") } } } internal fun free(buf: RustBuffer.ByValue) = rustCall() { status -> _UniFFILib.INSTANCE.ffi_bdk_6983_rustbuffer_free(buf, status) } internal fun reserve(buf: RustBuffer.ByValue, additional: Int) = rustCall() { status -> _UniFFILib.INSTANCE.ffi_bdk_6983_rustbuffer_reserve(buf, additional, status) } } @Suppress("TooGenericExceptionThrown") fun asByteBuffer() = this.data?.getByteBuffer(0, this.len.toLong())?.also { it.order(ByteOrder.BIG_ENDIAN) } } /** * The equivalent of the `*mut RustBuffer` type. * Required for callbacks taking in an out pointer. * * Size is the sum of all values in the struct. */ + /** + * @suppress + */ class RustBufferByReference : ByReference(16) { /** * Set the pointed-to `RustBuffer` to the given value. */ fun setValue(value: RustBuffer.ByValue) { // NOTE: The offsets are as they are in the C-like struct. val pointer = getPointer() pointer.setInt(0, value.capacity) pointer.setInt(4, value.len) pointer.setPointer(8, value.data) } } // This is a helper for safely passing byte references into the rust code. // It's not actually used at the moment, because there aren't many things that you // can take a direct pointer to in the JVM, and if we're going to copy something // then we might as well copy it into a `RustBuffer`. But it's here for API // completeness. + /** + * @suppress + */ @Structure.FieldOrder("len", "data") open class ForeignBytes : Structure() { @JvmField var len: Int = 0 @JvmField var data: Pointer? = null class ByValue : ForeignBytes(), Structure.ByValue } // A helper for structured writing of data into a `RustBuffer`. // This is very similar to `java.nio.ByteBuffer` but it knows how to grow // the underlying `RustBuffer` on demand. // // TODO: we should benchmark writing things into a `RustBuffer` versus building // up a bytearray and then copying it across. + /** + * @suppress + */ class RustBufferBuilder() { var rbuf = RustBuffer.ByValue() var bbuf: ByteBuffer? = null init { val rbuf = RustBuffer.alloc(16) // Totally arbitrary initial size rbuf.writeField("len", 0) this.setRustBuffer(rbuf) } internal fun setRustBuffer(rbuf: RustBuffer.ByValue) { this.rbuf = rbuf this.bbuf = this.rbuf.data?.getByteBuffer(0, this.rbuf.capacity.toLong())?.also { it.order(ByteOrder.BIG_ENDIAN) it.position(rbuf.len) } } fun finalize() : RustBuffer.ByValue { val rbuf = this.rbuf // Ensure that the JVM-level field is written through to native memory // before turning the buffer, in case its recipient uses it in a context // JNA doesn't apply its automatic synchronization logic. rbuf.writeField("len", this.bbuf!!.position()) this.setRustBuffer(RustBuffer.ByValue()) return rbuf } fun discard() { if(this.rbuf.data != null) { // Free the current `RustBuffer` RustBuffer.free(this.rbuf) // Replace it with an empty RustBuffer. this.setRustBuffer(RustBuffer.ByValue()) } } internal fun reserve(size: Int, write: (ByteBuffer) -> Unit) { // TODO: this will perform two checks to ensure we're not overflowing the buffer: // one here where we check if it needs to grow, and another when we call a write // method on the ByteBuffer. It might be cheaper to use exception-driven control-flow // here, trying the write and growing if it throws a `BufferOverflowException`. // Benchmarking needed. if (this.bbuf!!.position() + size > this.rbuf.capacity) { rbuf.writeField("len", this.bbuf!!.position()) this.setRustBuffer(RustBuffer.reserve(this.rbuf, size)) } write(this.bbuf!!) } fun putByte(v: Byte) { this.reserve(1) { bbuf -> bbuf.put(v) } } fun putShort(v: Short) { this.reserve(2) { bbuf -> bbuf.putShort(v) } } fun putInt(v: Int) { this.reserve(4) { bbuf -> bbuf.putInt(v) } } fun putLong(v: Long) { this.reserve(8) { bbuf -> *************** *** 216,934 **** } } internal fun lowerIntoRustBuffer(v: T, writeItem: (T, RustBufferBuilder) -> Unit): RustBuffer.ByValue { // TODO: maybe we can calculate some sort of initial size hint? val buf = RustBufferBuilder() try { writeItem(v, buf) return buf.finalize() } catch (e: Throwable) { buf.discard() throw e } } // A handful of classes and functions to support the generated data structures. // This would be a good candidate for isolating in its own ffi-support lib. // Error runtime. @Structure.FieldOrder("code", "error_buf") internal open class RustCallStatus : Structure() { @JvmField var code: Int = 0 @JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() fun isSuccess(): Boolean { return code == 0 } fun isError(): Boolean { return code == 1 } fun isPanic(): Boolean { return code == 2 } } class InternalException(message: String) : Exception(message) // Each top-level error class has a companion object that can lift the error from the call status's rust buffer interface CallStatusErrorHandler { fun lift(error_buf: RustBuffer.ByValue): E; } // Helpers for calling Rust // In practice we usually need to be synchronized to call this safely, so it doesn't // synchronize itself // Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err private inline fun rustCallWithError(errorHandler: CallStatusErrorHandler, callback: (RustCallStatus) -> U): U { var status = RustCallStatus(); val return_value = callback(status) if (status.isSuccess()) { return return_value } else if (status.isError()) { throw errorHandler.lift(status.error_buf) } else if (status.isPanic()) { // when the rust code sees a panic, it tries to construct a rustbuffer // with the message. but if that code panics, then it just sends back // an empty buffer. if (status.error_buf.len > 0) { throw InternalException(String.lift(status.error_buf)) } else { throw InternalException("Rust panic") } } else { throw InternalException("Unknown rust call status: $status.code") } } // CallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR object NullCallStatusErrorHandler: CallStatusErrorHandler { override fun lift(error_buf: RustBuffer.ByValue): InternalException { RustBuffer.free(error_buf) return InternalException("Unexpected CALL_ERROR") } } // Call a rust function that returns a plain value private inline fun rustCall(callback: (RustCallStatus) -> U): U { return rustCallWithError(NullCallStatusErrorHandler, callback); } // Contains loading, initialization code, // and the FFI Function declarations in a com.sun.jna.Library. @Synchronized private fun findLibraryName(componentName: String): String { val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") if (libOverride != null) { return libOverride } return "bdkffi" } private inline fun loadIndirect( componentName: String ): Lib { return Native.load(findLibraryName(componentName), Lib::class.java) } // A JNA Library to expose the extern-C FFI definitions. // This is an implementation detail which will be called internally by the public API. internal interface _UniFFILib : Library { companion object { internal val INSTANCE: _UniFFILib by lazy { loadIndirect<_UniFFILib>(componentName = "bdk") .also { lib: _UniFFILib -> FfiConverterCallbackInterfaceBdkProgress.register(lib) } } } fun ffi_bdk_6983_Wallet_object_free(ptr: Pointer, uniffi_out_err: RustCallStatus ): Unit fun bdk_6983_Wallet_new(descriptor: RustBuffer.ByValue,change_descriptor: RustBuffer.ByValue,network: RustBuffer.ByValue,database_config: RustBuffer.ByValue,blockchain_config: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): Pointer fun bdk_6983_Wallet_get_new_address(ptr: Pointer, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun bdk_6983_Wallet_get_last_unused_address(ptr: Pointer, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun bdk_6983_Wallet_get_balance(ptr: Pointer, uniffi_out_err: RustCallStatus ): Long fun bdk_6983_Wallet_sign(ptr: Pointer,psbt: Pointer, uniffi_out_err: RustCallStatus ): Unit fun bdk_6983_Wallet_get_transactions(ptr: Pointer, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun bdk_6983_Wallet_get_network(ptr: Pointer, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun bdk_6983_Wallet_sync(ptr: Pointer,progress_update: Long,max_address_param: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): Unit fun bdk_6983_Wallet_broadcast(ptr: Pointer,psbt: Pointer, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun ffi_bdk_6983_PartiallySignedBitcoinTransaction_object_free(ptr: Pointer, uniffi_out_err: RustCallStatus ): Unit fun bdk_6983_PartiallySignedBitcoinTransaction_new(wallet: Pointer,recipient: RustBuffer.ByValue,amount: Long,fee_rate: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): Pointer fun bdk_6983_PartiallySignedBitcoinTransaction_deserialize(psbt_base64: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): Pointer fun bdk_6983_PartiallySignedBitcoinTransaction_serialize(ptr: Pointer, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun ffi_bdk_6983_BdkProgress_init_callback(callback_stub: ForeignCallback, uniffi_out_err: RustCallStatus ): Unit fun bdk_6983_generate_extended_key(network: RustBuffer.ByValue,word_count: RustBuffer.ByValue,password: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun bdk_6983_restore_extended_key(network: RustBuffer.ByValue,mnemonic: RustBuffer.ByValue,password: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun ffi_bdk_6983_rustbuffer_alloc(size: Int, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun ffi_bdk_6983_rustbuffer_from_bytes(bytes: ForeignBytes.ByValue, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun ffi_bdk_6983_rustbuffer_free(buf: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): Unit fun ffi_bdk_6983_rustbuffer_reserve(buf: RustBuffer.ByValue,additional: Int, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue } // Public interface members begin here. // Interface implemented by anything that can contain an object reference. // // Such types expose a `destroy()` method that must be called to cleanly // dispose of the contained objects. Failure to call this method may result // in memory leaks. // // The easiest way to ensure this method is called is to use the `.use` // helper method to execute a block and destroy the object at the end. interface Disposable { fun destroy() companion object { fun destroy(vararg args: Any?) { args.filterIsInstance() .forEach(Disposable::destroy) } } } inline fun T.use(block: (T) -> R) = try { block(this) } finally { try { // N.B. our implementation is on the nullable type `Disposable?`. this?.destroy() } catch (e: Throwable) { // swallow } } // The base class for all UniFFI Object types. // // This class provides core operations for working with the Rust `Arc` pointer to // the live Rust struct on the other side of the FFI. // // There's some subtlety here, because we have to be careful not to operate on a Rust // struct after it has been dropped, and because we must expose a public API for freeing // the Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: // // * Each `FFIObject` instance holds an opaque pointer to the underlying Rust struct. // Method calls need to read this pointer from the object's state and pass it in to // the Rust FFI. // // * When an `FFIObject` is no longer needed, its pointer should be passed to a // special destructor function provided by the Rust FFI, which will drop the // underlying Rust struct. // // * Given an `FFIObject` instance, calling code is expected to call the special // `destroy` method in order to free it after use, either by calling it explicitly // or by using a higher-level helper like the `use` method. Failing to do so will // leak the underlying Rust struct. // // * We can't assume that calling code will do the right thing, and must be prepared // to handle Kotlin method calls executing concurrently with or even after a call to // `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. // // * We must never allow Rust code to operate on the underlying Rust struct after // the destructor has been called, and must never call the destructor more than once. // Doing so may trigger memory unsafety. // // If we try to implement this with mutual exclusion on access to the pointer, there is the // possibility of a race between a method call and a concurrent call to `destroy`: // // * Thread A starts a method call, reads the value of the pointer, but is interrupted // before it can pass the pointer over the FFI to Rust. // * Thread B calls `destroy` and frees the underlying Rust struct. // * Thread A resumes, passing the already-read pointer value to Rust and triggering // a use-after-free. // // One possible solution would be to use a `ReadWriteLock`, with each method call taking // a read lock (and thus allowed to run concurrently) and the special `destroy` method // taking a write lock (and thus blocking on live method calls). However, we aim not to // generate methods with any hidden blocking semantics, and a `destroy` method that might // block if called incorrectly seems to meet that bar. // // So, we achieve our goals by giving each `FFIObject` an associated `AtomicLong` counter to track // the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` // has been called. These are updated according to the following rules: // // * The initial value of the counter is 1, indicating a live object with no in-flight calls. // The initial value for the flag is false. // // * At the start of each method call, we atomically check the counter. // If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. // If it is nonzero them we atomically increment it by 1 and proceed with the method call. // // * At the end of each method call, we atomically decrement and check the counter. // If it has reached zero then we destroy the underlying Rust struct. // // * When `destroy` is called, we atomically flip the flag from false to true. // If the flag was already true we silently fail. // Otherwise we atomically decrement and check the counter. // If it has reached zero then we destroy the underlying Rust struct. // // Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, // and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. // // The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been // called *and* all in-flight method calls have completed, avoiding violating any of the expectations // of the underlying Rust code. // // In the future we may be able to replace some of this with automatic finalization logic, such as using // the new "Cleaner" functionaility in Java 9. The above scheme has been designed to work even if `destroy` is // invoked by garbage-collection machinery rather than by calling code (which by the way, it's apparently also // possible for the JVM to finalize an object while there is an in-flight call to one of its methods [1], // so there would still be some complexity here). // // Sigh...all of this for want of a robust finalization mechanism. // // [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 // abstract class FFIObject( protected val pointer: Pointer ): Disposable, AutoCloseable { private val wasDestroyed = AtomicBoolean(false) private val callCounter = AtomicLong(1) open protected fun freeRustArcPtr() { // To be overridden in subclasses. } override fun destroy() { // Only allow a single call to this method. // TODO: maybe we should log a warning if called more than once? if (this.wasDestroyed.compareAndSet(false, true)) { // This decrement always matches the initial count of 1 given at creation time. if (this.callCounter.decrementAndGet() == 0L) { this.freeRustArcPtr() } } } @Synchronized override fun close() { this.destroy() } internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { // Check and increment the call counter, to keep the object alive. // This needs a compare-and-set retry loop in case of concurrent updates. do { val c = this.callCounter.get() if (c == 0L) { throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") } if (c == Long.MAX_VALUE) { throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") } } while (! this.callCounter.compareAndSet(c, c + 1L)) // Now we can safely do the method call without the pointer being freed concurrently. try { return block(this.pointer) } finally { // This decrement aways matches the increment we performed above. if (this.callCounter.decrementAndGet() == 0L) { this.freeRustArcPtr() } } } } internal typealias Handle = Long internal class ConcurrentHandleMap( private val leftMap: MutableMap = mutableMapOf(), private val rightMap: MutableMap = mutableMapOf() ) { private val lock = java.util.concurrent.locks.ReentrantLock() private val currentHandle = AtomicLong(0L) private val stride = 1L fun insert(obj: T): Handle = lock.withLock { rightMap[obj] ?: currentHandle.getAndAdd(stride) .also { handle -> leftMap[handle] = obj rightMap[obj] = handle } } fun get(handle: Handle) = lock.withLock { leftMap[handle] } fun delete(handle: Handle) { this.remove(handle) } fun remove(handle: Handle): T? = lock.withLock { leftMap.remove(handle)?.let { obj -> rightMap.remove(obj) obj } } } interface ForeignCallback : com.sun.jna.Callback { public fun invoke(handle: Handle, method: Int, args: RustBuffer.ByValue, outBuf: RustBufferByReference): Int } // Magic number for the Rust proxy to call using the same mechanism as every other method, // to free the callback once it's dropped by Rust. internal const val IDX_CALLBACK_FREE = 0 internal abstract class FfiConverterCallbackInterface( protected val foreignCallback: ForeignCallback ) { val handleMap = ConcurrentHandleMap() // Registers the foreign callback with the Rust side. // This method is generated for each callback interface. abstract fun register(lib: _UniFFILib) fun drop(handle: Handle): RustBuffer.ByValue { return handleMap.remove(handle).let { RustBuffer.ByValue() } } fun lift(n: Handle) = handleMap.get(n) fun read(buf: ByteBuffer) = lift(buf.getLong()) fun lower(v: CallbackInterface) = handleMap.insert(v).also { assert(handleMap.get(it) === v) { "Handle map is not returning the object we just placed there. This is a bug in the HandleMap." } } fun write(v: CallbackInterface, buf: RustBufferBuilder) = buf.putLong(lower(v)) } enum class Network { BITCOIN,TESTNET,SIGNET,REGTEST; companion object { internal fun lift(rbuf: RustBuffer.ByValue): Network { return liftFromRustBuffer(rbuf) { buf -> Network.read(buf) } } internal fun read(buf: ByteBuffer) = try { values()[buf.getInt() - 1] } catch (e: IndexOutOfBoundsException) { throw RuntimeException("invalid enum value, something is very wrong!!", e) } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { buf.putInt(this.ordinal + 1) } } sealed class DatabaseConfig { object Memory : DatabaseConfig() data class Sled( val config: SledDbConfiguration ) : DatabaseConfig() data class Sqlite( val config: SqliteDbConfiguration ) : DatabaseConfig() - companion object { internal fun lift(rbuf: RustBuffer.ByValue): DatabaseConfig { return liftFromRustBuffer(rbuf) { buf -> DatabaseConfig.read(buf) } } internal fun read(buf: ByteBuffer): DatabaseConfig { return when(buf.getInt()) { 1 -> DatabaseConfig.Memory 2 -> DatabaseConfig.Sled( SledDbConfiguration.read(buf) ) 3 -> DatabaseConfig.Sqlite( SqliteDbConfiguration.read(buf) ) else -> throw RuntimeException("invalid enum value, something is very wrong!!") } } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { when(this) { is DatabaseConfig.Memory -> { buf.putInt(1) } is DatabaseConfig.Sled -> { buf.putInt(2) this.config.write(buf) } is DatabaseConfig.Sqlite -> { buf.putInt(3) this.config.write(buf) } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } sealed class Transaction { data class Unconfirmed( val details: TransactionDetails ) : Transaction() data class Confirmed( val details: TransactionDetails, val confirmation: BlockTime ) : Transaction() companion object { internal fun lift(rbuf: RustBuffer.ByValue): Transaction { return liftFromRustBuffer(rbuf) { buf -> Transaction.read(buf) } } internal fun read(buf: ByteBuffer): Transaction { return when(buf.getInt()) { 1 -> Transaction.Unconfirmed( TransactionDetails.read(buf) ) 2 -> Transaction.Confirmed( TransactionDetails.read(buf), BlockTime.read(buf) ) else -> throw RuntimeException("invalid enum value, something is very wrong!!") } } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { when(this) { is Transaction.Unconfirmed -> { buf.putInt(1) this.details.write(buf) } is Transaction.Confirmed -> { buf.putInt(2) this.details.write(buf) this.confirmation.write(buf) } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } sealed class BlockchainConfig { data class Electrum( val config: ElectrumConfig ) : BlockchainConfig() data class Esplora( val config: EsploraConfig ) : BlockchainConfig() companion object { internal fun lift(rbuf: RustBuffer.ByValue): BlockchainConfig { return liftFromRustBuffer(rbuf) { buf -> BlockchainConfig.read(buf) } } internal fun read(buf: ByteBuffer): BlockchainConfig { return when(buf.getInt()) { 1 -> BlockchainConfig.Electrum( ElectrumConfig.read(buf) ) 2 -> BlockchainConfig.Esplora( EsploraConfig.read(buf) ) else -> throw RuntimeException("invalid enum value, something is very wrong!!") } } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { when(this) { is BlockchainConfig.Electrum -> { buf.putInt(1) this.config.write(buf) } is BlockchainConfig.Esplora -> { buf.putInt(2) this.config.write(buf) } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } enum class WordCount { WORDS12,WORDS15,WORDS18,WORDS21,WORDS24; companion object { internal fun lift(rbuf: RustBuffer.ByValue): WordCount { return liftFromRustBuffer(rbuf) { buf -> WordCount.read(buf) } } internal fun read(buf: ByteBuffer) = try { values()[buf.getInt() - 1] } catch (e: IndexOutOfBoundsException) { throw RuntimeException("invalid enum value, something is very wrong!!", e) } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { buf.putInt(this.ordinal + 1) } } @Throws(BdkException::class) fun generateExtendedKey(network: Network, wordCount: WordCount, password: String? ): ExtendedKeyInfo { val _retval = rustCallWithError(BdkException) { status -> _UniFFILib.INSTANCE.bdk_6983_generate_extended_key(network.lower(), wordCount.lower(), lowerOptionalString(password) ,status) } return ExtendedKeyInfo.lift(_retval) } @Throws(BdkException::class) fun restoreExtendedKey(network: Network, mnemonic: String, password: String? ): ExtendedKeyInfo { val _retval = rustCallWithError(BdkException) { status -> _UniFFILib.INSTANCE.bdk_6983_restore_extended_key(network.lower(), mnemonic.lower(), lowerOptionalString(password) ,status) } return ExtendedKeyInfo.lift(_retval) } public interface WalletInterface { fun getNewAddress(): String fun getLastUnusedAddress(): String @Throws(BdkException::class) fun getBalance(): ULong @Throws(BdkException::class) fun sign(psbt: PartiallySignedBitcoinTransaction ) @Throws(BdkException::class) fun getTransactions(): List fun getNetwork(): Network @Throws(BdkException::class) fun sync(progressUpdate: BdkProgress, maxAddressParam: UInt? ) @Throws(BdkException::class) fun broadcast(psbt: PartiallySignedBitcoinTransaction ): Transaction } --- 229,980 ---- } } internal fun lowerIntoRustBuffer(v: T, writeItem: (T, RustBufferBuilder) -> Unit): RustBuffer.ByValue { // TODO: maybe we can calculate some sort of initial size hint? val buf = RustBufferBuilder() try { writeItem(v, buf) return buf.finalize() } catch (e: Throwable) { buf.discard() throw e } } // A handful of classes and functions to support the generated data structures. // This would be a good candidate for isolating in its own ffi-support lib. // Error runtime. @Structure.FieldOrder("code", "error_buf") internal open class RustCallStatus : Structure() { @JvmField var code: Int = 0 @JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() fun isSuccess(): Boolean { return code == 0 } fun isError(): Boolean { return code == 1 } fun isPanic(): Boolean { return code == 2 } } class InternalException(message: String) : Exception(message) // Each top-level error class has a companion object that can lift the error from the call status's rust buffer interface CallStatusErrorHandler { fun lift(error_buf: RustBuffer.ByValue): E; } // Helpers for calling Rust // In practice we usually need to be synchronized to call this safely, so it doesn't // synchronize itself // Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err private inline fun rustCallWithError(errorHandler: CallStatusErrorHandler, callback: (RustCallStatus) -> U): U { var status = RustCallStatus(); val return_value = callback(status) if (status.isSuccess()) { return return_value } else if (status.isError()) { throw errorHandler.lift(status.error_buf) } else if (status.isPanic()) { // when the rust code sees a panic, it tries to construct a rustbuffer // with the message. but if that code panics, then it just sends back // an empty buffer. if (status.error_buf.len > 0) { throw InternalException(String.lift(status.error_buf)) } else { throw InternalException("Rust panic") } } else { throw InternalException("Unknown rust call status: $status.code") } } // CallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR + /** + * @suppress + */ object NullCallStatusErrorHandler: CallStatusErrorHandler { override fun lift(error_buf: RustBuffer.ByValue): InternalException { RustBuffer.free(error_buf) return InternalException("Unexpected CALL_ERROR") } } // Call a rust function that returns a plain value private inline fun rustCall(callback: (RustCallStatus) -> U): U { return rustCallWithError(NullCallStatusErrorHandler, callback); } // Contains loading, initialization code, // and the FFI Function declarations in a com.sun.jna.Library. @Synchronized private fun findLibraryName(componentName: String): String { val libOverride = System.getProperty("uniffi.component.$componentName.libraryOverride") if (libOverride != null) { return libOverride } return "bdkffi" } private inline fun loadIndirect( componentName: String ): Lib { return Native.load(findLibraryName(componentName), Lib::class.java) } // A JNA Library to expose the extern-C FFI definitions. // This is an implementation detail which will be called internally by the public API. internal interface _UniFFILib : Library { companion object { internal val INSTANCE: _UniFFILib by lazy { loadIndirect<_UniFFILib>(componentName = "bdk") .also { lib: _UniFFILib -> FfiConverterCallbackInterfaceBdkProgress.register(lib) } } } fun ffi_bdk_6983_Wallet_object_free(ptr: Pointer, uniffi_out_err: RustCallStatus ): Unit fun bdk_6983_Wallet_new(descriptor: RustBuffer.ByValue,change_descriptor: RustBuffer.ByValue,network: RustBuffer.ByValue,database_config: RustBuffer.ByValue,blockchain_config: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): Pointer fun bdk_6983_Wallet_get_new_address(ptr: Pointer, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun bdk_6983_Wallet_get_last_unused_address(ptr: Pointer, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun bdk_6983_Wallet_get_balance(ptr: Pointer, uniffi_out_err: RustCallStatus ): Long fun bdk_6983_Wallet_sign(ptr: Pointer,psbt: Pointer, uniffi_out_err: RustCallStatus ): Unit fun bdk_6983_Wallet_get_transactions(ptr: Pointer, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun bdk_6983_Wallet_get_network(ptr: Pointer, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun bdk_6983_Wallet_sync(ptr: Pointer,progress_update: Long,max_address_param: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): Unit fun bdk_6983_Wallet_broadcast(ptr: Pointer,psbt: Pointer, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun ffi_bdk_6983_PartiallySignedBitcoinTransaction_object_free(ptr: Pointer, uniffi_out_err: RustCallStatus ): Unit fun bdk_6983_PartiallySignedBitcoinTransaction_new(wallet: Pointer,recipient: RustBuffer.ByValue,amount: Long,fee_rate: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): Pointer fun bdk_6983_PartiallySignedBitcoinTransaction_deserialize(psbt_base64: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): Pointer fun bdk_6983_PartiallySignedBitcoinTransaction_serialize(ptr: Pointer, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun ffi_bdk_6983_BdkProgress_init_callback(callback_stub: ForeignCallback, uniffi_out_err: RustCallStatus ): Unit fun bdk_6983_generate_extended_key(network: RustBuffer.ByValue,word_count: RustBuffer.ByValue,password: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun bdk_6983_restore_extended_key(network: RustBuffer.ByValue,mnemonic: RustBuffer.ByValue,password: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun ffi_bdk_6983_rustbuffer_alloc(size: Int, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun ffi_bdk_6983_rustbuffer_from_bytes(bytes: ForeignBytes.ByValue, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue fun ffi_bdk_6983_rustbuffer_free(buf: RustBuffer.ByValue, uniffi_out_err: RustCallStatus ): Unit fun ffi_bdk_6983_rustbuffer_reserve(buf: RustBuffer.ByValue,additional: Int, uniffi_out_err: RustCallStatus ): RustBuffer.ByValue } // Public interface members begin here. // Interface implemented by anything that can contain an object reference. // // Such types expose a `destroy()` method that must be called to cleanly // dispose of the contained objects. Failure to call this method may result // in memory leaks. // // The easiest way to ensure this method is called is to use the `.use` // helper method to execute a block and destroy the object at the end. + /** + * @suppress + */ interface Disposable { fun destroy() companion object { fun destroy(vararg args: Any?) { args.filterIsInstance() .forEach(Disposable::destroy) } } } + /** + * @suppress + */ inline fun T.use(block: (T) -> R) = try { block(this) } finally { try { // N.B. our implementation is on the nullable type `Disposable?`. this?.destroy() } catch (e: Throwable) { // swallow } } // The base class for all UniFFI Object types. // // This class provides core operations for working with the Rust `Arc` pointer to // the live Rust struct on the other side of the FFI. // // There's some subtlety here, because we have to be careful not to operate on a Rust // struct after it has been dropped, and because we must expose a public API for freeing // the Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: // // * Each `FFIObject` instance holds an opaque pointer to the underlying Rust struct. // Method calls need to read this pointer from the object's state and pass it in to // the Rust FFI. // // * When an `FFIObject` is no longer needed, its pointer should be passed to a // special destructor function provided by the Rust FFI, which will drop the // underlying Rust struct. // // * Given an `FFIObject` instance, calling code is expected to call the special // `destroy` method in order to free it after use, either by calling it explicitly // or by using a higher-level helper like the `use` method. Failing to do so will // leak the underlying Rust struct. // // * We can't assume that calling code will do the right thing, and must be prepared // to handle Kotlin method calls executing concurrently with or even after a call to // `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. // // * We must never allow Rust code to operate on the underlying Rust struct after // the destructor has been called, and must never call the destructor more than once. // Doing so may trigger memory unsafety. // // If we try to implement this with mutual exclusion on access to the pointer, there is the // possibility of a race between a method call and a concurrent call to `destroy`: // // * Thread A starts a method call, reads the value of the pointer, but is interrupted // before it can pass the pointer over the FFI to Rust. // * Thread B calls `destroy` and frees the underlying Rust struct. // * Thread A resumes, passing the already-read pointer value to Rust and triggering // a use-after-free. // // One possible solution would be to use a `ReadWriteLock`, with each method call taking // a read lock (and thus allowed to run concurrently) and the special `destroy` method // taking a write lock (and thus blocking on live method calls). However, we aim not to // generate methods with any hidden blocking semantics, and a `destroy` method that might // block if called incorrectly seems to meet that bar. // // So, we achieve our goals by giving each `FFIObject` an associated `AtomicLong` counter to track // the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` // has been called. These are updated according to the following rules: // // * The initial value of the counter is 1, indicating a live object with no in-flight calls. // The initial value for the flag is false. // // * At the start of each method call, we atomically check the counter. // If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. // If it is nonzero them we atomically increment it by 1 and proceed with the method call. // // * At the end of each method call, we atomically decrement and check the counter. // If it has reached zero then we destroy the underlying Rust struct. // // * When `destroy` is called, we atomically flip the flag from false to true. // If the flag was already true we silently fail. // Otherwise we atomically decrement and check the counter. // If it has reached zero then we destroy the underlying Rust struct. // // Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, // and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. // // The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been // called *and* all in-flight method calls have completed, avoiding violating any of the expectations // of the underlying Rust code. // // In the future we may be able to replace some of this with automatic finalization logic, such as using // the new "Cleaner" functionaility in Java 9. The above scheme has been designed to work even if `destroy` is // invoked by garbage-collection machinery rather than by calling code (which by the way, it's apparently also // possible for the JVM to finalize an object while there is an in-flight call to one of its methods [1], // so there would still be some complexity here). // // Sigh...all of this for want of a robust finalization mechanism. // // [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 // + /** + * @suppress + */ abstract class FFIObject( protected val pointer: Pointer ): Disposable, AutoCloseable { private val wasDestroyed = AtomicBoolean(false) private val callCounter = AtomicLong(1) open protected fun freeRustArcPtr() { // To be overridden in subclasses. } override fun destroy() { // Only allow a single call to this method. // TODO: maybe we should log a warning if called more than once? if (this.wasDestroyed.compareAndSet(false, true)) { // This decrement always matches the initial count of 1 given at creation time. if (this.callCounter.decrementAndGet() == 0L) { this.freeRustArcPtr() } } } @Synchronized override fun close() { this.destroy() } internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { // Check and increment the call counter, to keep the object alive. // This needs a compare-and-set retry loop in case of concurrent updates. do { val c = this.callCounter.get() if (c == 0L) { throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") } if (c == Long.MAX_VALUE) { throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") } } while (! this.callCounter.compareAndSet(c, c + 1L)) // Now we can safely do the method call without the pointer being freed concurrently. try { return block(this.pointer) } finally { // This decrement aways matches the increment we performed above. if (this.callCounter.decrementAndGet() == 0L) { this.freeRustArcPtr() } } } } internal typealias Handle = Long internal class ConcurrentHandleMap( private val leftMap: MutableMap = mutableMapOf(), private val rightMap: MutableMap = mutableMapOf() ) { private val lock = java.util.concurrent.locks.ReentrantLock() private val currentHandle = AtomicLong(0L) private val stride = 1L fun insert(obj: T): Handle = lock.withLock { rightMap[obj] ?: currentHandle.getAndAdd(stride) .also { handle -> leftMap[handle] = obj rightMap[obj] = handle } } fun get(handle: Handle) = lock.withLock { leftMap[handle] } fun delete(handle: Handle) { this.remove(handle) } fun remove(handle: Handle): T? = lock.withLock { leftMap.remove(handle)?.let { obj -> rightMap.remove(obj) obj } } } + /** + * @suppress + */ interface ForeignCallback : com.sun.jna.Callback { public fun invoke(handle: Handle, method: Int, args: RustBuffer.ByValue, outBuf: RustBufferByReference): Int } // Magic number for the Rust proxy to call using the same mechanism as every other method, // to free the callback once it's dropped by Rust. internal const val IDX_CALLBACK_FREE = 0 internal abstract class FfiConverterCallbackInterface( protected val foreignCallback: ForeignCallback ) { val handleMap = ConcurrentHandleMap() // Registers the foreign callback with the Rust side. // This method is generated for each callback interface. abstract fun register(lib: _UniFFILib) fun drop(handle: Handle): RustBuffer.ByValue { return handleMap.remove(handle).let { RustBuffer.ByValue() } } fun lift(n: Handle) = handleMap.get(n) fun read(buf: ByteBuffer) = lift(buf.getLong()) fun lower(v: CallbackInterface) = handleMap.insert(v).also { assert(handleMap.get(it) === v) { "Handle map is not returning the object we just placed there. This is a bug in the HandleMap." } } fun write(v: CallbackInterface, buf: RustBufferBuilder) = buf.putLong(lower(v)) } enum class Network { BITCOIN,TESTNET,SIGNET,REGTEST; + /** + * @suppress + */ companion object { internal fun lift(rbuf: RustBuffer.ByValue): Network { return liftFromRustBuffer(rbuf) { buf -> Network.read(buf) } } internal fun read(buf: ByteBuffer) = try { values()[buf.getInt() - 1] } catch (e: IndexOutOfBoundsException) { throw RuntimeException("invalid enum value, something is very wrong!!", e) } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { buf.putInt(this.ordinal + 1) } } sealed class DatabaseConfig { object Memory : DatabaseConfig() data class Sled( val config: SledDbConfiguration ) : DatabaseConfig() data class Sqlite( val config: SqliteDbConfiguration ) : DatabaseConfig() + + /** + * @suppress + */ companion object { internal fun lift(rbuf: RustBuffer.ByValue): DatabaseConfig { return liftFromRustBuffer(rbuf) { buf -> DatabaseConfig.read(buf) } } internal fun read(buf: ByteBuffer): DatabaseConfig { return when(buf.getInt()) { 1 -> DatabaseConfig.Memory 2 -> DatabaseConfig.Sled( SledDbConfiguration.read(buf) ) 3 -> DatabaseConfig.Sqlite( SqliteDbConfiguration.read(buf) ) else -> throw RuntimeException("invalid enum value, something is very wrong!!") } } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { when(this) { is DatabaseConfig.Memory -> { buf.putInt(1) } is DatabaseConfig.Sled -> { buf.putInt(2) this.config.write(buf) } is DatabaseConfig.Sqlite -> { buf.putInt(3) this.config.write(buf) } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } sealed class Transaction { data class Unconfirmed( val details: TransactionDetails ) : Transaction() data class Confirmed( val details: TransactionDetails, val confirmation: BlockTime ) : Transaction() + /** + * @suppress + */ companion object { internal fun lift(rbuf: RustBuffer.ByValue): Transaction { return liftFromRustBuffer(rbuf) { buf -> Transaction.read(buf) } } internal fun read(buf: ByteBuffer): Transaction { return when(buf.getInt()) { 1 -> Transaction.Unconfirmed( TransactionDetails.read(buf) ) 2 -> Transaction.Confirmed( TransactionDetails.read(buf), BlockTime.read(buf) ) else -> throw RuntimeException("invalid enum value, something is very wrong!!") } } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { when(this) { is Transaction.Unconfirmed -> { buf.putInt(1) this.details.write(buf) } is Transaction.Confirmed -> { buf.putInt(2) this.details.write(buf) this.confirmation.write(buf) } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } + /** + * Sealed class that can be of either blockchain configuration defined by the library. + */ sealed class BlockchainConfig { data class Electrum( val config: ElectrumConfig ) : BlockchainConfig() data class Esplora( val config: EsploraConfig ) : BlockchainConfig() + /** + * @suppress + */ companion object { internal fun lift(rbuf: RustBuffer.ByValue): BlockchainConfig { return liftFromRustBuffer(rbuf) { buf -> BlockchainConfig.read(buf) } } internal fun read(buf: ByteBuffer): BlockchainConfig { return when(buf.getInt()) { 1 -> BlockchainConfig.Electrum( ElectrumConfig.read(buf) ) 2 -> BlockchainConfig.Esplora( EsploraConfig.read(buf) ) else -> throw RuntimeException("invalid enum value, something is very wrong!!") } } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { when(this) { is BlockchainConfig.Electrum -> { buf.putInt(1) this.config.write(buf) } is BlockchainConfig.Esplora -> { buf.putInt(2) this.config.write(buf) } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } enum class WordCount { WORDS12,WORDS15,WORDS18,WORDS21,WORDS24; + /** + * @suppress + */ companion object { internal fun lift(rbuf: RustBuffer.ByValue): WordCount { return liftFromRustBuffer(rbuf) { buf -> WordCount.read(buf) } } internal fun read(buf: ByteBuffer) = try { values()[buf.getInt() - 1] } catch (e: IndexOutOfBoundsException) { throw RuntimeException("invalid enum value, something is very wrong!!", e) } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { buf.putInt(this.ordinal + 1) } } @Throws(BdkException::class) fun generateExtendedKey(network: Network, wordCount: WordCount, password: String? ): ExtendedKeyInfo { val _retval = rustCallWithError(BdkException) { status -> _UniFFILib.INSTANCE.bdk_6983_generate_extended_key(network.lower(), wordCount.lower(), lowerOptionalString(password) ,status) } return ExtendedKeyInfo.lift(_retval) } @Throws(BdkException::class) fun restoreExtendedKey(network: Network, mnemonic: String, password: String? ): ExtendedKeyInfo { val _retval = rustCallWithError(BdkException) { status -> _UniFFILib.INSTANCE.bdk_6983_restore_extended_key(network.lower(), mnemonic.lower(), lowerOptionalString(password) ,status) } return ExtendedKeyInfo.lift(_retval) } public interface WalletInterface { fun getNewAddress(): String fun getLastUnusedAddress(): String @Throws(BdkException::class) fun getBalance(): ULong @Throws(BdkException::class) fun sign(psbt: PartiallySignedBitcoinTransaction ) @Throws(BdkException::class) fun getTransactions(): List fun getNetwork(): Network @Throws(BdkException::class) fun sync(progressUpdate: BdkProgress, maxAddressParam: UInt? ) @Throws(BdkException::class) fun broadcast(psbt: PartiallySignedBitcoinTransaction ): Transaction } *************** *** 1034,1418 **** --- 1080,1491 ---- } }.let { Transaction.lift(it) } companion object { internal fun lift(ptr: Pointer): Wallet { return Wallet(ptr) } internal fun read(buf: ByteBuffer): Wallet { // The Rust code always writes pointers as 8 bytes, and will // fail to compile if they don't fit. return Wallet.lift(Pointer(buf.getLong())) } } } public interface PartiallySignedBitcoinTransactionInterface { fun serialize(): String } class PartiallySignedBitcoinTransaction( pointer: Pointer ) : FFIObject(pointer), PartiallySignedBitcoinTransactionInterface { constructor(wallet: Wallet, recipient: String, amount: ULong, feeRate: Float? ) : this( rustCallWithError(BdkException) { status -> _UniFFILib.INSTANCE.bdk_6983_PartiallySignedBitcoinTransaction_new(wallet.lower(), recipient.lower(), amount.lower(), lowerOptionalFloat(feeRate) ,status) }) /** * Disconnect the object from the underlying Rust object. * * It can be called more than once, but once called, interacting with the object * causes an `IllegalStateException`. * * Clients **must** call this method once done with the object, or cause a memory leak. */ override protected fun freeRustArcPtr() { rustCall() { status -> _UniFFILib.INSTANCE.ffi_bdk_6983_PartiallySignedBitcoinTransaction_object_free(this.pointer, status) } } internal fun lower(): Pointer = callWithPointer { it } internal fun write(buf: RustBufferBuilder) { // The Rust code always expects pointers written as 8 bytes, // and will fail to compile if they don't fit. buf.putLong(Pointer.nativeValue(this.lower())) } override fun serialize(): String = callWithPointer { rustCall() { status -> _UniFFILib.INSTANCE.bdk_6983_PartiallySignedBitcoinTransaction_serialize(it, status) } }.let { String.lift(it) } + /** + * @suppress + */ companion object { internal fun lift(ptr: Pointer): PartiallySignedBitcoinTransaction { return PartiallySignedBitcoinTransaction(ptr) } internal fun read(buf: ByteBuffer): PartiallySignedBitcoinTransaction { // The Rust code always writes pointers as 8 bytes, and will // fail to compile if they don't fit. return PartiallySignedBitcoinTransaction.lift(Pointer(buf.getLong())) } fun deserialize(psbtBase64: String ): PartiallySignedBitcoinTransaction = PartiallySignedBitcoinTransaction( rustCallWithError(BdkException) { status -> _UniFFILib.INSTANCE.bdk_6983_PartiallySignedBitcoinTransaction_deserialize(psbtBase64.lower() ,status) }) } } data class SledDbConfiguration ( var path: String, var treeName: String ) { companion object { internal fun lift(rbuf: RustBuffer.ByValue): SledDbConfiguration { return liftFromRustBuffer(rbuf) { buf -> SledDbConfiguration.read(buf) } } internal fun read(buf: ByteBuffer): SledDbConfiguration { return SledDbConfiguration( String.read(buf), String.read(buf) ) } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { this.path.write(buf) this.treeName.write(buf) } } data class SqliteDbConfiguration ( var path: String ) { companion object { internal fun lift(rbuf: RustBuffer.ByValue): SqliteDbConfiguration { return liftFromRustBuffer(rbuf) { buf -> SqliteDbConfiguration.read(buf) } } internal fun read(buf: ByteBuffer): SqliteDbConfiguration { return SqliteDbConfiguration( String.read(buf) ) } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { this.path.write(buf) } } data class TransactionDetails ( var fees: ULong?, var received: ULong, var sent: ULong, var txid: String ) { companion object { internal fun lift(rbuf: RustBuffer.ByValue): TransactionDetails { return liftFromRustBuffer(rbuf) { buf -> TransactionDetails.read(buf) } } internal fun read(buf: ByteBuffer): TransactionDetails { return TransactionDetails( readOptionalULong(buf), ULong.read(buf), ULong.read(buf), String.read(buf) ) } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { writeOptionalULong(this.fees, buf) this.received.write(buf) this.sent.write(buf) this.txid.write(buf) } } + /** + * Block height and timestamp of a block + */ data class BlockTime ( var height: UInt, var timestamp: ULong ) { + /** + * @suppress + */ companion object { internal fun lift(rbuf: RustBuffer.ByValue): BlockTime { return liftFromRustBuffer(rbuf) { buf -> BlockTime.read(buf) } } internal fun read(buf: ByteBuffer): BlockTime { return BlockTime( UInt.read(buf), ULong.read(buf) ) } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { this.height.write(buf) this.timestamp.write(buf) } } + /** + * Configuration for an ElectrumBlockchain + * + * @property url URL of the Electrum server (such as ElectrumX, Esplora, BWT). May start with `ssl://` or `tcp://` and include a port, `e.g. ssl://electrum.blockstream.info:60002` + * @property socks5 URL of the socks5 proxy server or a Tor service + * @property retry Request retry count + * @property timeout Request timeout in seconds + * @property stopGap Stop searching addresses for transactions after finding an unused gap of this length + */ data class ElectrumConfig ( var url: String, var socks5: String?, var retry: UByte, var timeout: UByte?, var stopGap: ULong ) { + /** + * @suppress + */ companion object { internal fun lift(rbuf: RustBuffer.ByValue): ElectrumConfig { return liftFromRustBuffer(rbuf) { buf -> ElectrumConfig.read(buf) } } internal fun read(buf: ByteBuffer): ElectrumConfig { return ElectrumConfig( String.read(buf), readOptionalString(buf), UByte.read(buf), readOptionalUByte(buf), ULong.read(buf) ) } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { this.url.write(buf) writeOptionalString(this.socks5, buf) this.retry.write(buf) writeOptionalUByte(this.timeout, buf) this.stopGap.write(buf) } } data class EsploraConfig ( var baseUrl: String, var proxy: String?, var timeoutRead: ULong, var timeoutWrite: ULong, var stopGap: ULong ) { + /** + * @suppress + */ companion object { internal fun lift(rbuf: RustBuffer.ByValue): EsploraConfig { return liftFromRustBuffer(rbuf) { buf -> EsploraConfig.read(buf) } } internal fun read(buf: ByteBuffer): EsploraConfig { return EsploraConfig( String.read(buf), readOptionalString(buf), ULong.read(buf), ULong.read(buf), ULong.read(buf) ) } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { this.baseUrl.write(buf) writeOptionalString(this.proxy, buf) this.timeoutRead.write(buf) this.timeoutWrite.write(buf) this.stopGap.write(buf) } } data class ExtendedKeyInfo ( var mnemonic: String, var xprv: String, var fingerprint: String ) { + /** + * @suppress + */ companion object { internal fun lift(rbuf: RustBuffer.ByValue): ExtendedKeyInfo { return liftFromRustBuffer(rbuf) { buf -> ExtendedKeyInfo.read(buf) } } internal fun read(buf: ByteBuffer): ExtendedKeyInfo { return ExtendedKeyInfo( String.read(buf), String.read(buf), String.read(buf) ) } } internal fun lower(): RustBuffer.ByValue { return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) } internal fun write(buf: RustBufferBuilder) { this.mnemonic.write(buf) this.xprv.write(buf) this.fingerprint.write(buf) } } sealed class BdkException(message: String): Exception(message) { // Each variant is a nested class // Flat enums carries a string error message, so no special implementation is necessary. class InvalidU32Bytes(message: String) : BdkException(message) class Generic(message: String) : BdkException(message) class ScriptDoesntHaveAddressForm(message: String) : BdkException(message) class NoRecipients(message: String) : BdkException(message) class NoUtxosSelected(message: String) : BdkException(message) class OutputBelowDustLimit(message: String) : BdkException(message) class InsufficientFunds(message: String) : BdkException(message) class BnBTotalTriesExceeded(message: String) : BdkException(message) class BnBNoExactMatch(message: String) : BdkException(message) class UnknownUtxo(message: String) : BdkException(message) class TransactionNotFound(message: String) : BdkException(message) class TransactionConfirmed(message: String) : BdkException(message) class IrreplaceableTransaction(message: String) : BdkException(message) class FeeRateTooLow(message: String) : BdkException(message) class FeeTooLow(message: String) : BdkException(message) class FeeRateUnavailable(message: String) : BdkException(message) class MissingKeyOrigin(message: String) : BdkException(message) class Key(message: String) : BdkException(message) class ChecksumMismatch(message: String) : BdkException(message) class SpendingPolicyRequired(message: String) : BdkException(message) class InvalidPolicyPathException(message: String) : BdkException(message) class Signer(message: String) : BdkException(message) class InvalidNetwork(message: String) : BdkException(message) class InvalidProgressValue(message: String) : BdkException(message) class ProgressUpdateException(message: String) : BdkException(message) class InvalidOutpoint(message: String) : BdkException(message) class Descriptor(message: String) : BdkException(message) class AddressValidator(message: String) : BdkException(message) class Encode(message: String) : BdkException(message) class Miniscript(message: String) : BdkException(message) class Bip32(message: String) : BdkException(message) class Secp256k1(message: String) : BdkException(message) class Json(message: String) : BdkException(message) class Hex(message: String) : BdkException(message)