diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml index f35a2bee..d9e47e6a 100644 --- a/.github/workflows/cont_integration.yml +++ b/.github/workflows/cont_integration.yml @@ -47,14 +47,14 @@ jobs: run: rustup update - name: Build - run: cargo build --features uniffi/cli + run: cargo build - name: Clippy if: ${{ matrix.rust.clippy }} - run: cargo clippy --all-targets --features "uniffi/bindgen-tests uniffi/cli" -- -D warnings + run: cargo clippy --all-targets --features "uniffi/bindgen-tests" -- -D warnings - name: Test - run: CLASSPATH=./tests/jna/jna-5.8.0.jar cargo test --features uniffi/bindgen-tests,uniffi/cli + run: CLASSPATH=./tests/jna/jna-5.8.0.jar cargo test --features uniffi/bindgen-tests fmt: name: Rust fmt diff --git a/.github/workflows/test-android.yaml b/.github/workflows/test-android.yaml index 9a961408..7591fd14 100644 --- a/.github/workflows/test-android.yaml +++ b/.github/workflows/test-android.yaml @@ -9,22 +9,10 @@ on: - "bdk-ffi/**" - "bdk-android/**" -env: - ANDROID_NDK_ROOT: /usr/local/lib/android/sdk/ndk/21.4.7075529 - # By default, the new ubuntu-20.04 images use the following ANDROID_NDK_ROOT - # ANDROID_NDK_ROOT: /usr/local/lib/android/sdk/ndk/25.0.8775105 - jobs: build: runs-on: ubuntu-20.04 steps: - - name: "Install Android NDK 21.4.7075529" - run: | - ANDROID_ROOT=/usr/local/lib/android - ANDROID_SDK_ROOT=${ANDROID_ROOT}/sdk - SDKMANAGER=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager - echo "y" | $SDKMANAGER "ndk;21.4.7075529" - - name: "Check out PR branch" uses: actions/checkout@v2 diff --git a/.github/workflows/test-swift.yaml b/.github/workflows/test-swift.yaml index 18cfed53..38c1d971 100644 --- a/.github/workflows/test-swift.yaml +++ b/.github/workflows/test-swift.yaml @@ -24,13 +24,13 @@ jobs: - name: Run bdk-ffi-bindgen working-directory: bdk-ffi - run: cargo run --features uniffi/cli --bin uniffi-bindgen generate src/bdk.udl --language swift --out-dir ../bdk-swift/Sources/BitcoinDevKit --no-format + run: cargo run --bin uniffi-bindgen generate src/bdk.udl --language swift --out-dir ../bdk-swift/Sources/BitcoinDevKit --no-format - name: Build bdk-ffi for x86_64-apple-darwin - run: cargo build --package bdk-ffi --features uniffi/cli --profile release-smaller --target x86_64-apple-darwin + run: cargo build --package bdk-ffi --profile release-smaller --target x86_64-apple-darwin - name: Build bdk-ffi for aarch64-apple-darwin - run: cargo build --package bdk-ffi --features uniffi/cli --profile release-smaller --target aarch64-apple-darwin + run: cargo build --package bdk-ffi --profile release-smaller --target aarch64-apple-darwin - name: Create lipo-ios-sim and lipo-macos run: | diff --git a/Cargo.lock b/Cargo.lock index 7e603bef..07fbc818 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,15 +19,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "anyhow" version = "1.0.69" @@ -163,16 +154,6 @@ dependencies = [ "uniffi", ] -[[package]] -name = "bdk-ffi-bindgen" -version = "0.2.0" -dependencies = [ - "anyhow", - "camino", - "structopt", - "uniffi_bindgen 0.21.1", -] - [[package]] name = "bdk-macros" version = "0.6.0" @@ -331,21 +312,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim 0.8.0", - "textwrap 0.11.0", - "unicode-width", - "vec_map", -] - [[package]] name = "clap" version = "3.2.23" @@ -358,9 +324,9 @@ dependencies = [ "clap_lex", "indexmap", "once_cell", - "strsim 0.10.0", + "strsim", "termcolor", - "textwrap 0.16.0", + "textwrap", ] [[package]] @@ -369,7 +335,7 @@ version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro-error", "proc-macro2", "quote", @@ -519,17 +485,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" -[[package]] -name = "goblin" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143" -dependencies = [ - "log", - "plain", - "scroll", -] - [[package]] name = "goblin" version = "0.6.1" @@ -559,15 +514,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "heck" version = "0.4.1" @@ -640,12 +586,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.139" @@ -768,9 +708,9 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "os_str_bytes" -version = "6.4.1" +version = "6.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" [[package]] name = "parking_lot" @@ -1124,42 +1064,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "structopt" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" -dependencies = [ - "clap 2.34.0", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" -dependencies = [ - "heck 0.3.3", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "syn" version = "1.0.107" @@ -1180,15 +1090,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "textwrap" version = "0.16.0" @@ -1197,18 +1098,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" dependencies = [ "proc-macro2", "quote", @@ -1277,18 +1178,6 @@ dependencies = [ "smallvec 0.6.14", ] -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - [[package]] name = "uniffi" version = "0.23.0" @@ -1296,35 +1185,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f71cc01459bc34cfe43fabf32b39f1228709bc6db1b3a664a92940af3d062376" dependencies = [ "anyhow", - "uniffi_bindgen 0.23.0", + "camino", + "clap", + "uniffi_bindgen", "uniffi_build", "uniffi_core", "uniffi_macros", ] -[[package]] -name = "uniffi_bindgen" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d46080a4840abccf7c0cce21931dae53215cbd7dd969b5e63c486235ce91a2a" -dependencies = [ - "anyhow", - "askama", - "bincode", - "camino", - "clap 3.2.23", - "fs-err", - "goblin 0.5.4", - "heck 0.4.1", - "once_cell", - "paste", - "serde", - "serde_json", - "toml", - "uniffi_meta 0.21.1", - "weedle2", -] - [[package]] name = "uniffi_bindgen" version = "0.23.0" @@ -1337,14 +1205,14 @@ dependencies = [ "camino", "fs-err", "glob", - "goblin 0.6.1", - "heck 0.4.1", + "goblin", + "heck", "once_cell", "paste", "serde", "serde_json", "toml", - "uniffi_meta 0.23.0", + "uniffi_meta", "uniffi_testing", "weedle2", ] @@ -1357,17 +1225,7 @@ checksum = "0ee1a28368ff3d83717e3d3e2e15a66269c43488c3f036914131bb68892f29fb" dependencies = [ "anyhow", "camino", - "uniffi_bindgen 0.23.0", -] - -[[package]] -name = "uniffi_checksum_derive" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b6e16d46caf942016997af8bbdf4b163bf8ae3deb0b667d9643de7b7ffd4c9" -dependencies = [ - "quote", - "syn", + "uniffi_bindgen", ] [[package]] @@ -1412,18 +1270,7 @@ dependencies = [ "syn", "toml", "uniffi_build", - "uniffi_meta 0.23.0", -] - -[[package]] -name = "uniffi_meta" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729835442da829c9b6f7c111c76cf87b2498e129101203bec94f0c39a3296a38" -dependencies = [ - "serde", - "siphasher", - "uniffi_checksum_derive 0.21.1", + "uniffi_meta", ] [[package]] @@ -1434,7 +1281,7 @@ checksum = "66fdab2c436aed7a6391bec64204ec33948bfed9b11b303235740771f85c4ea6" dependencies = [ "serde", "siphasher", - "uniffi_checksum_derive 0.23.0", + "uniffi_checksum_derive", ] [[package]] @@ -1494,12 +1341,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index b8d84b07..f36d6b82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] -members = ["bdk-ffi", "bdk-ffi-bindgen"] -default-members = ["bdk-ffi", "bdk-ffi-bindgen"] +members = ["bdk-ffi"] +default-members = ["bdk-ffi"] exclude = ["api-docs", "bdk-android", "bdk-jvm", "bdk-python", "bdk-swift"] [profile.release-smaller] @@ -9,4 +9,4 @@ opt-level = 'z' # Optimize for size. lto = true # Enable Link Time Optimization codegen-units = 1 # Reduce number of codegen units to increase optimizations. panic = 'abort' # Abort on panic -strip = true # Strip symbols from binary* \ No newline at end of file +strip = true # Strip symbols from binary* diff --git a/api-docs/kotlin/src/main/kotlin/org/bitcoindevkit/bdk.kt b/api-docs/kotlin/src/main/kotlin/org/bitcoindevkit/bdk.kt index 77ad251c..271d66cc 100644 --- a/api-docs/kotlin/src/main/kotlin/org/bitcoindevkit/bdk.kt +++ b/api-docs/kotlin/src/main/kotlin/org/bitcoindevkit/bdk.kt @@ -248,6 +248,7 @@ sealed class BlockchainConfig { * @property confirmationTime If the transaction is confirmed, [BlockTime] contains height and timestamp of the block containing the transaction. This property is null for unconfirmed transactions. */ data class TransactionDetails ( + var transaction?: Transaction, var fee: ULong?, var received: ULong, var sent: ULong, @@ -288,8 +289,60 @@ class Blockchain( * @param transactionBytes The transaction bytes, bitcoin consensus encoded. */ class Transaction(transactionBytes: List) { + /** Computes the txid. */ + fun txid(): String {} + + /** + * Returns the "weight" of this transaction, as defined by BIP141. + * + * For transactions with an empty witness, this is simply the consensus-serialized size times four. + * For transactions with a witness, this is the non-witness consensus-serialized size multiplied by three + * plus the with-witness consensus-serialized size. + */ + fun weight(): ULong {} + + /** Returns the regular byte-wise consensus-serialized size of this transaction. */ + fun size(): ULong {} + + /** + * Returns the "virtual size" (vsize) of this transaction. + * + * Will be ceil(weight / 4.0). Note this implements the virtual size as per BIP141, which is different to + * what is implemented in Bitcoin Core. The computation should be the same for any remotely sane transaction. + */ + fun vsize(): ULong {} + /** Return the transaction bytes, bitcoin consensus encoded. */ fun serialize(): List {} + + /** Is this a coin base transaction? */ + fun isCoinBase(): Boolean {} + + /** + * Returns true if the transaction itself opted in to be BIP-125-replaceable (RBF). + * This does not cover the case where a transaction becomes replaceable due to ancestors being RBF. + */ + fun isExplicitlyRbf(): Boolean {} + + /** Returns true if this transactions nLockTime is enabled (BIP-65). */ + fun isLockTimeEnabled(): Boolean {} + + /** The protocol version, is currently expected to be 1 or 2 (BIP 68). */ + fun version(): Int {} + + /** + * Block height or timestamp. Transaction cannot be included in a block until this height/time. + * Relevant BIPs + * BIP-65 OP_CHECKLOCKTIMEVERIFY + * BIP-113 Median time-past as endpoint for lock-time calculations + */ + fun lockTime(): UInt {} + + /** List of transaction inputs. */ + fun input(): List {} + + /** List of transaction outputs. */ + fun output(): List {} } /** @@ -331,11 +384,29 @@ data class OutPoint ( * A transaction output, which defines new coins to be created from old ones. * * @property value The value of the output, in satoshis. - * @property address The address of the output. + * @property scriptPubkey The script which must be satisfied for the output to be spent. */ data class TxOut ( var value: ULong, - var address: String + var scriptPubkey: Script +) + +/** + * Bitcoin transaction input. + * + * It contains the location of the previous transaction’s output, that it spends and set of scripts that satisfy its spending conditions. + * + * @property previousOutput The reference to the previous output that is being used an an input. + * @property scriptSig The script which pushes values on the stack which will cause the referenced output’s script to be accepted. + * @property sequence The sequence number, which suggests to miners which of two conflicting transactions should be preferred, or 0xFFFFFFFF to ignore this feature. This is generally never used since the miner behaviour cannot be enforced. + * @property witness Witness data: an array of byte-arrays. Note that this field is not (de)serialized with the rest of the TxIn in Encodable/Decodable, as it is (de)serialized at the end of the full Transaction. It is (de)serialized with the rest of the TxIn in other (de)serialization routines. + * + */ +data class TxIn ( + var previousOutput: OutPoint, + var scriptSig: Script, + var sequence: UInt, + var witness: List> ) /** @@ -420,7 +491,7 @@ class Wallet( fun sign(psbt: PartiallySignedTransaction): Boolean {} /** Return the list of transactions made and received by the wallet. Note that this method only operate on the internal database, which first needs to be [Wallet.sync] manually. */ - fun listTransactions(): List {} + fun listTransactions(includeRaw: Boolean): List {} /** Get the Bitcoin network the wallet is using. */ fun network(): Network {} diff --git a/bdk-android/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiAndroidPlugin.kt b/bdk-android/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiAndroidPlugin.kt index 7125126c..20200864 100644 --- a/bdk-android/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiAndroidPlugin.kt +++ b/bdk-android/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiAndroidPlugin.kt @@ -21,7 +21,7 @@ internal class UniFfiAndroidPlugin : Plugin { val buildAndroidAarch64Binary by tasks.register("buildAndroidAarch64Binary") { workingDir("${projectDir}/../../bdk-ffi") - val cargoArgs: List = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "aarch64-linux-android") + val cargoArgs: List = listOf("build", "--profile", "release-smaller", "--target", "aarch64-linux-android") executable("cargo") args(cargoArgs) @@ -36,7 +36,8 @@ internal class UniFfiAndroidPlugin : Plugin { environment( // add build toolchain to PATH Pair("PATH", "${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"), - Pair("CFLAGS", "-D__ANDROID_API__=21"), + Pair("CFLAGS", "-D__ANDROID_MIN_SDK_VERSION__=21"), + Pair("AR", "llvm-ar"), Pair("CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER", "aarch64-linux-android21-clang"), Pair("CC", "aarch64-linux-android21-clang") ) @@ -50,7 +51,7 @@ internal class UniFfiAndroidPlugin : Plugin { val buildAndroidX86_64Binary by tasks.register("buildAndroidX86_64Binary") { workingDir("${project.projectDir}/../../bdk-ffi") - val cargoArgs: List = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "x86_64-linux-android") + val cargoArgs: List = listOf("build", "--profile", "release-smaller", "--target", "x86_64-linux-android") executable("cargo") args(cargoArgs) @@ -65,7 +66,8 @@ internal class UniFfiAndroidPlugin : Plugin { environment( // add build toolchain to PATH Pair("PATH", "${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"), - Pair("CFLAGS", "-D__ANDROID_API__=21"), + Pair("CFLAGS", "-D__ANDROID_MIN_SDK_VERSION__=21"), + Pair("AR", "llvm-ar"), Pair("CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER", "x86_64-linux-android21-clang"), Pair("CC", "x86_64-linux-android21-clang") ) @@ -79,7 +81,7 @@ internal class UniFfiAndroidPlugin : Plugin { val buildAndroidArmv7Binary by tasks.register("buildAndroidArmv7Binary") { workingDir("${project.projectDir}/../../bdk-ffi") - val cargoArgs: List = listOf("build", "--features", "uniffi/cli", "--profile", "release-smaller", "--target", "armv7-linux-androideabi") + val cargoArgs: List = listOf("build", "--profile", "release-smaller", "--target", "armv7-linux-androideabi") executable("cargo") args(cargoArgs) @@ -94,7 +96,8 @@ internal class UniFfiAndroidPlugin : Plugin { environment( // add build toolchain to PATH Pair("PATH", "${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"), - Pair("CFLAGS", "-D__ANDROID_API__=21"), + Pair("CFLAGS", "-D__ANDROID_MIN_SDK_VERSION__=21"), + Pair("AR", "llvm-ar"), Pair("CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER", "armv7a-linux-androideabi21-clang"), Pair("CC", "armv7a-linux-androideabi21-clang") ) @@ -135,7 +138,7 @@ internal class UniFfiAndroidPlugin : Plugin { dependsOn(moveNativeAndroidLibs) workingDir("${project.projectDir}/../../bdk-ffi") - val cargoArgs: List = listOf("run", "--features", "uniffi/cli", "--bin", "uniffi-bindgen", "generate", "src/bdk.udl", "--language", "kotlin", "--out-dir", "../bdk-android/lib/src/main/kotlin", "--no-format") + val cargoArgs: List = listOf("run", "--bin", "uniffi-bindgen", "generate", "src/bdk.udl", "--language", "kotlin", "--out-dir", "../bdk-android/lib/src/main/kotlin", "--no-format") executable("cargo") args(cargoArgs) diff --git a/bdk-ffi-bindgen/Cargo.toml b/bdk-ffi-bindgen/Cargo.toml deleted file mode 100644 index 87ee0bcc..00000000 --- a/bdk-ffi-bindgen/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "bdk-ffi-bindgen" -version = "0.2.0" -edition = "2021" - -[dependencies] -anyhow = "1.0.45" # remove after upgrading to next version of uniffi -structopt = "0.3" -uniffi_bindgen = "0.21.0" -camino = "1.0.9" diff --git a/bdk-ffi-bindgen/src/main.rs b/bdk-ffi-bindgen/src/main.rs deleted file mode 100644 index 8a87fc5a..00000000 --- a/bdk-ffi-bindgen/src/main.rs +++ /dev/null @@ -1,138 +0,0 @@ -use camino::Utf8Path; -use std::fmt; -use std::path::{Path, PathBuf}; -use std::str::FromStr; -use structopt::StructOpt; - -#[derive(Debug, Eq, PartialEq)] -pub enum Language { - Kotlin, - Python, - Swift, -} - -impl fmt::Display for Language { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Language::Kotlin => write!(f, "kotlin"), - Language::Swift => write!(f, "swift"), - Language::Python => write!(f, "python"), - } - } -} - -#[derive(Debug)] -pub enum Error { - UnsupportedLanguage, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -impl FromStr for Language { - type Err = Error; - fn from_str(s: &str) -> Result { - match s { - "kotlin" => Ok(Language::Kotlin), - "python" => Ok(Language::Python), - "swift" => Ok(Language::Swift), - _ => Err(Error::UnsupportedLanguage), - } - } -} - -fn generate_bindings(opt: &Opt) -> anyhow::Result<(), anyhow::Error> { - let path: &Utf8Path = Utf8Path::from_path(&opt.udl_file).unwrap(); - let out_dir: &Utf8Path = Utf8Path::from_path(&opt.out_dir).unwrap(); - uniffi_bindgen::generate_bindings( - path, - None, - vec![opt.language.to_string().as_str()], - Some(out_dir), - None, - false, - )?; - - Ok(()) -} - -fn fixup_python_lib_path( - out_dir: &Path, - lib_name: &Path, -) -> Result<(), Box> { - use std::fs; - use std::io::Write; - - const LOAD_INDIRECT_DEF: &str = "def loadIndirect():"; - - let bindings_file = out_dir.join("bdk.py"); - let mut data = fs::read_to_string(&bindings_file)?; - - let pos = data - .find(LOAD_INDIRECT_DEF) - .unwrap_or_else(|| panic!("loadIndirect not found in `{}`", bindings_file.display())); - let range = pos..pos + LOAD_INDIRECT_DEF.len(); - - let replacement = format!( - r#" -def loadIndirect(): - import glob - return getattr(ctypes.cdll, glob.glob(os.path.join(os.path.dirname(os.path.abspath(__file__)), '{}.*'))[0]) - -def _loadIndirectOld():"#, - &lib_name.to_str().expect("lib name") - ); - data.replace_range(range, &replacement); - - let mut file = fs::OpenOptions::new() - .write(true) - .truncate(true) - .open(&bindings_file)?; - file.write_all(data.as_bytes())?; - - Ok(()) -} - -#[derive(Debug, StructOpt)] -#[structopt( - name = "bdk-ffi-bindgen", - about = "A tool to generate bdk-ffi language bindings" -)] -struct Opt { - /// UDL file - #[structopt(env = "BDKFFI_BINDGEN_UDL", short, long, default_value("src/bdk.udl"), parse(try_from_str = PathBuf::from_str))] - udl_file: PathBuf, - - /// Language to generate bindings for - #[structopt(env = "BDKFFI_BINDGEN_LANGUAGE", short, long, possible_values(&["kotlin","swift","python"]), parse(try_from_str = Language::from_str))] - language: Language, - - /// Output directory to put generated language bindings - #[structopt(env = "BDKFFI_BINDGEN_OUTPUT_DIR", short, long, parse(try_from_str = PathBuf::from_str))] - out_dir: PathBuf, - - /// Python fix up lib path - #[structopt(env = "BDKFFI_BINDGEN_PYTHON_FIXUP_PATH", short, long, parse(try_from_str = PathBuf::from_str))] - python_fixup_path: Option, -} - -fn main() -> Result<(), Box> { - let opt = Opt::from_args(); - - println!("Input UDL file is {:?}", opt.udl_file); - println!("Chosen language is {}", opt.language); - println!("Output directory is {:?}", opt.out_dir); - - generate_bindings(&opt)?; - - if opt.language == Language::Python { - if let Some(path) = opt.python_fixup_path { - println!("Fixing up python lib path, {:?}", &path); - fixup_python_lib_path(&opt.out_dir, &path)?; - } - } - Ok(()) -} diff --git a/bdk-ffi/Cargo.toml b/bdk-ffi/Cargo.toml index 78486688..45979f78 100644 --- a/bdk-ffi/Cargo.toml +++ b/bdk-ffi/Cargo.toml @@ -15,6 +15,9 @@ name = "bdkffi" name = "uniffi-bindgen" path = "uniffi-bindgen.rs" +[features] +default = ["uniffi/cli"] + [dependencies] bdk = { version = "0.27.1", features = ["all-keys", "use-esplora-ureq", "sqlite-bundled", "rpc"] } uniffi = { version = "0.23.0" } diff --git a/bdk-ffi/src/bdk.udl b/bdk-ffi/src/bdk.udl index 9be878dc..da760972 100644 --- a/bdk-ffi/src/bdk.udl +++ b/bdk-ffi/src/bdk.udl @@ -94,6 +94,7 @@ interface DatabaseConfig { }; dictionary TransactionDetails { + Transaction? transaction; u64? fee; u64 received; u64 sent; @@ -186,9 +187,16 @@ dictionary OutPoint { u32 vout; }; +dictionary TxIn { + OutPoint previous_output; + Script script_sig; + u32 sequence; + sequence> witness; +}; + dictionary TxOut { u64 value; - string address; + Script script_pubkey; }; enum KeychainKind { @@ -225,7 +233,7 @@ interface Wallet { boolean sign([ByRef] PartiallySignedTransaction psbt); [Throws=BdkError] - sequence list_transactions(); + sequence list_transactions(boolean include_raw); Network network(); @@ -244,10 +252,32 @@ interface FeeRate { }; interface Transaction { - [Throws=BdkError] - constructor(sequence transaction_bytes); + [Throws=BdkError] + constructor(sequence transaction_bytes); + + string txid(); + + u64 weight(); + + u64 size(); + + u64 vsize(); + + sequence serialize(); + + boolean is_coin_base(); + + boolean is_explicitly_rbf(); + + boolean is_lock_time_enabled(); + + i32 version(); + + u32 lock_time(); + + sequence input(); - sequence serialize(); + sequence output(); }; interface PartiallySignedTransaction { diff --git a/bdk-ffi/src/lib.rs b/bdk-ffi/src/lib.rs index f82b6cb7..15838545 100644 --- a/bdk-ffi/src/lib.rs +++ b/bdk-ffi/src/lib.rs @@ -15,6 +15,8 @@ use crate::keys::{DescriptorPublicKey, DescriptorSecretKey, Mnemonic}; use crate::psbt::PartiallySignedTransaction; use crate::wallet::{BumpFeeTxBuilder, TxBuilder, Wallet}; use bdk::bitcoin::blockdata::script::Script as BdkScript; +use bdk::bitcoin::blockdata::transaction::TxIn as BdkTxIn; +use bdk::bitcoin::blockdata::transaction::TxOut as BdkTxOut; use bdk::bitcoin::consensus::Decodable; use bdk::bitcoin::psbt::serialize::Serialize; use bdk::bitcoin::{ @@ -25,6 +27,7 @@ use bdk::database::any::{SledDbConfiguration, SqliteDbConfiguration}; use bdk::keys::bip39::WordCount; use bdk::wallet::AddressIndex as BdkAddressIndex; use bdk::wallet::AddressInfo as BdkAddressInfo; +use bdk::LocalUtxo as BdkLocalUtxo; use bdk::{Balance as BdkBalance, BlockTime, Error as BdkError, FeeRate, KeychainKind}; use std::convert::From; use std::fmt; @@ -49,7 +52,7 @@ pub struct AddressInfo { } impl From for AddressInfo { - fn from(x: bdk::wallet::AddressInfo) -> AddressInfo { + fn from(x: bdk::wallet::AddressInfo) -> Self { AddressInfo { index: x.index, address: x.address.to_string(), @@ -79,13 +82,13 @@ pub enum AddressIndex { /// Use with caution, if an index is given that is less than the current descriptor index /// then the returned address and subsequent addresses returned by calls to `AddressIndex::New` /// and `AddressIndex::LastUsed` may have already been used. Also if the index is reset to a - /// value earlier than the [`crate::blockchain::Blockchain`] stop_gap (default is 20) then a + /// value earlier than the [`Blockchain`] stop_gap (default is 20) then a /// larger stop_gap should be used to monitor for all possibly used addresses. Reset { index: u32 }, } impl From for BdkAddressIndex { - fn from(x: AddressIndex) -> BdkAddressIndex { + fn from(x: AddressIndex) -> Self { match x { AddressIndex::New => BdkAddressIndex::New, AddressIndex::LastUnused => BdkAddressIndex::LastUnused, @@ -98,6 +101,7 @@ impl From for BdkAddressIndex { /// A wallet transaction #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct TransactionDetails { + pub transaction: Option>, /// Transaction id. pub txid: String, /// Received value (sats) @@ -116,14 +120,18 @@ pub struct TransactionDetails { pub confirmation_time: Option, } -impl From<&bdk::TransactionDetails> for TransactionDetails { - fn from(x: &bdk::TransactionDetails) -> TransactionDetails { +impl From for TransactionDetails { + fn from(tx_details: bdk::TransactionDetails) -> Self { + let optional_tx: Option> = + tx_details.transaction.map(|tx| Arc::new(tx.into())); + TransactionDetails { - fee: x.fee, - txid: x.txid.to_string(), - received: x.received, - sent: x.sent, - confirmation_time: x.confirmation_time.clone(), + transaction: optional_tx, + fee: tx_details.fee, + txid: tx_details.txid.to_string(), + received: tx_details.received, + sent: tx_details.sent, + confirmation_time: tx_details.confirmation_time, } } } @@ -138,7 +146,7 @@ pub struct OutPoint { } impl From<&OutPoint> for BdkOutPoint { - fn from(x: &OutPoint) -> BdkOutPoint { + fn from(x: &OutPoint) -> Self { BdkOutPoint { txid: Txid::from_str(&x.txid).unwrap(), vout: x.vout, @@ -175,11 +183,23 @@ impl From for Balance { } /// A transaction output, which defines new coins to be created from old ones. +#[derive(Debug, Clone)] pub struct TxOut { /// The value of the output, in satoshis. value: u64, /// The address of the output. - address: String, + script_pubkey: Arc