From d2bbecc5f54ffb71f3f6d324beeaf26aac371af9 Mon Sep 17 00:00:00 2001 From: Alekos Filini Date: Tue, 15 Feb 2022 16:47:34 +0100 Subject: [PATCH 01/41] Build wheels using setuptools-rust Build wheels in a more "standard" way using setuptools-rust, which makes our life easier when dealing with multiple different platforms. Also use the new bdk-ffi's `generate` binary instead of relying on uniffi's bindgen cli. --- .gitignore | 5 + README.md | 55 +- bdk-ffi | 2 +- build.sh | 19 - generate.sh | 9 + nix/uniffi_0.14.1_cargo_lock.patch | 387 ++++++ nix/uniffi_0.15.2_cargo_lock.patch | 387 ++++++ nix/uniffi_bindgen.nix | 20 + requirements.txt | 3 + setup.py | 24 +- shell.nix | 17 + src/bdkpython/bdk.py | 1891 ---------------------------- 12 files changed, 850 insertions(+), 1969 deletions(-) delete mode 100644 build.sh create mode 100644 generate.sh create mode 100644 nix/uniffi_0.14.1_cargo_lock.patch create mode 100644 nix/uniffi_0.15.2_cargo_lock.patch create mode 100644 nix/uniffi_bindgen.nix create mode 100644 requirements.txt create mode 100644 shell.nix delete mode 100644 src/bdkpython/bdk.py diff --git a/.gitignore b/.gitignore index a11b87d..b763419 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,8 @@ __pycache__/ libbdkffi.dylib .idea/ .DS_Store + +*.swp + +src/bdkpython/bdk.py +*.whl diff --git a/README.md b/README.md index 1f33e6a..55df900 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,11 @@ python -m tox ## Build the package ```shell +# Install dependecies +pip install -r requirements.txt +# Generate the bindings first +bash generate.sh +# Build the wheel python -m build ```
@@ -34,53 +39,3 @@ python -m build pip install ./dist/bdkpython-0.0.1-py3-none-any.whl ```
- -## Known issues -Note that until the fix is merged upstream in [uniffi-rs](https://github.com/mozilla/uniffi-rs), the `loadIndirect()` function in the `bdk.py` module must be replaced with the following: -```python -def loadIndirect(): - if sys.platform == "linux": - # libname = "lib{}.so" - libname = os.path.join(os.path.dirname(__file__), "lib{}.so") - elif sys.platform == "darwin": - # libname = "lib{}.dylib" - libname = os.path.join(os.path.dirname(__file__), "lib{}.dylib") - elif sys.platform.startswith("win"): - # As of python3.8, ctypes does not seem to search $PATH when loading DLLs. - # We could use `os.add_dll_directory` to configure the search path, but - # it doesn't feel right to mess with application-wide settings. Let's - # assume that the `.dll` is next to the `.py` file and load by full path. - libname = os.path.join( - os.path.dirname(__file__), - "{}.dll", - ) - return getattr(ctypes.cdll, libname.format("bdkffi")) -``` - -## Support both macOS architectures -In order to support both macOS architectures, we must modify the `loadIndirect()` method a little further: -```python -import platform -def loadIndirect(): - if sys.platform == "linux": - # libname = "lib{}.so" - # libname = os.path.join(os.path.dirname(__file__), "lib{}.so") - libname = os.path.join(os.path.dirname(__file__), "linux-x86_64/lib{}.so") - elif sys.platform == "darwin": - # libname = "lib{}.dylib" - # libname = os.path.join(os.path.dirname(__file__), "lib{}.dylib") - if platform.machine() == "arm64": - libname = os.path.join(os.path.dirname(__file__), "darwin-arm64/lib{}.dylib") - elif platform.machine() == "x86_64": - libname = os.path.join(os.path.dirname(__file__), "darwin-x86_64/lib{}.dylib") - elif sys.platform.startswith("win"): - # As of python3.8, ctypes does not seem to search $PATH when loading DLLs. - # We could use `os.add_dll_directory` to configure the search path, but - # it doesn't feel right to mess with application-wide settings. Let's - # assume that the `.dll` is next to the `.py` file and load by full path. - libname = os.path.join( - os.path.dirname(__file__), - "{}.dll", - ) - return getattr(ctypes.cdll, libname.format("bdkffi")) -``` diff --git a/bdk-ffi b/bdk-ffi index e4d53b5..68f266a 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit e4d53b5e4b213e484bf4b76a4bf33884dd68f086 +Subproject commit 68f266a17b29a84e8c63ed90126c5c152d2f51aa diff --git a/build.sh b/build.sh deleted file mode 100644 index afd46bb..0000000 --- a/build.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -#set -euo pipefail - -#pushd bdk-ffi -echo "Confirm bdk-ffi rust library builds" -cargo build --manifest-path ./bdk-ffi/Cargo.toml --release - -echo "Generate bdk-ffi Python bindings" -# clean solution once uniffi-bindgen 0.15.3 is released -# uniffi-bindgen generate src/bdk.udl --no-format --out-dir ../src/bdkpython/ --language python - -# in the meantime, set UNIFFI_BINDGEN environment variable to a local, latest version of uniffi-rs/uniffi_bindgen/Cargo.toml -# and the BDK_PYTHON environment variable to the current directory -#cd $UNIFFI_BINDGEN/ -#cargo run -- generate $BDK_PYTHON/src/bdk.udl --no-format --out-dir ./src/bdkpython/ --language python -#cd - - -cargo run --manifest-path $UNIFFI_BINDGEN -- generate ./bdk-ffi/src/bdk.udl --no-format --out-dir ./src/bdkpython/ --language python -cp ./bdk-ffi/target/release/libbdkffi.dylib ./src/bdkpython/ diff --git a/generate.sh b/generate.sh new file mode 100644 index 0000000..653935d --- /dev/null +++ b/generate.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR=$(dirname "$(realpath $0)") +PY_SRC="${SCRIPT_DIR}/src/bdkpython/" + +echo "Generating bdk.py..." +GENERATE_PYTHON_BINDINGS_OUT="$PY_SRC" GENERATE_PYTHON_BINDINGS_FIXUP_LIB_PATH=bdkffi cargo run --manifest-path ./bdk-ffi/Cargo.toml --release --bin generate --features generate-python diff --git a/nix/uniffi_0.14.1_cargo_lock.patch b/nix/uniffi_0.14.1_cargo_lock.patch new file mode 100644 index 0000000..6c7244d --- /dev/null +++ b/nix/uniffi_0.14.1_cargo_lock.patch @@ -0,0 +1,387 @@ +--- /dev/null 2021-12-15 11:22:02.342000000 +0100 ++++ uniffi_bindgen/Cargo.lock 2021-12-15 16:15:16.132084011 +0100 +@@ -0,0 +1,384 @@ ++# This file is automatically @generated by Cargo. ++# It is not intended for manual editing. ++version = 3 ++ ++[[package]] ++name = "anyhow" ++version = "1.0.51" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" ++ ++[[package]] ++name = "arrayvec" ++version = "0.5.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" ++ ++[[package]] ++name = "askama" ++version = "0.10.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "d298738b6e47e1034e560e5afe63aa488fea34e25ec11b855a76f0d7b8e73134" ++dependencies = [ ++ "askama_derive", ++ "askama_escape", ++ "askama_shared", ++] ++ ++[[package]] ++name = "askama_derive" ++version = "0.10.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "ca2925c4c290382f9d2fa3d1c1b6a63fa1427099721ecca4749b154cc9c25522" ++dependencies = [ ++ "askama_shared", ++ "proc-macro2", ++ "syn", ++] ++ ++[[package]] ++name = "askama_escape" ++version = "0.10.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "90c108c1a94380c89d2215d0ac54ce09796823cca0fd91b299cfff3b33e346fb" ++ ++[[package]] ++name = "askama_shared" ++version = "0.11.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "2582b77e0f3c506ec4838a25fa8a5f97b9bed72bb6d3d272ea1c031d8bd373bc" ++dependencies = [ ++ "askama_escape", ++ "nom 6.2.1", ++ "proc-macro2", ++ "quote", ++ "serde", ++ "syn", ++ "toml", ++] ++ ++[[package]] ++name = "bitflags" ++version = "1.3.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" ++ ++[[package]] ++name = "bitvec" ++version = "0.19.6" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33" ++dependencies = [ ++ "funty", ++ "radium", ++ "tap", ++ "wyz", ++] ++ ++[[package]] ++name = "camino" ++version = "1.0.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b" ++dependencies = [ ++ "serde", ++] ++ ++[[package]] ++name = "cargo-platform" ++version = "0.1.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" ++dependencies = [ ++ "serde", ++] ++ ++[[package]] ++name = "cargo_metadata" ++version = "0.13.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "081e3f0755c1f380c2d010481b6fa2e02973586d5f2b24eebb7a2a1d98b143d8" ++dependencies = [ ++ "camino", ++ "cargo-platform", ++ "semver", ++ "semver-parser", ++ "serde", ++ "serde_json", ++] ++ ++[[package]] ++name = "cfg-if" ++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 = [ ++ "bitflags", ++ "textwrap", ++ "unicode-width", ++] ++ ++[[package]] ++name = "funty" ++version = "1.1.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" ++ ++[[package]] ++name = "heck" ++version = "0.3.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" ++dependencies = [ ++ "unicode-segmentation", ++] ++ ++[[package]] ++name = "itoa" ++version = "1.0.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" ++ ++[[package]] ++name = "lexical-core" ++version = "0.7.6" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" ++dependencies = [ ++ "arrayvec", ++ "bitflags", ++ "cfg-if", ++ "ryu", ++ "static_assertions", ++] ++ ++[[package]] ++name = "memchr" ++version = "2.3.4" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" ++ ++[[package]] ++name = "nom" ++version = "5.1.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" ++dependencies = [ ++ "memchr", ++ "version_check", ++] ++ ++[[package]] ++name = "nom" ++version = "6.2.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" ++dependencies = [ ++ "bitvec", ++ "funty", ++ "lexical-core", ++ "memchr", ++ "version_check", ++] ++ ++[[package]] ++name = "paste" ++version = "1.0.6" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" ++ ++[[package]] ++name = "pest" ++version = "2.1.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" ++dependencies = [ ++ "ucd-trie", ++] ++ ++[[package]] ++name = "proc-macro2" ++version = "1.0.34" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1" ++dependencies = [ ++ "unicode-xid", ++] ++ ++[[package]] ++name = "quote" ++version = "1.0.10" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" ++dependencies = [ ++ "proc-macro2", ++] ++ ++[[package]] ++name = "radium" ++version = "0.5.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" ++ ++[[package]] ++name = "ryu" ++version = "1.0.9" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" ++ ++[[package]] ++name = "semver" ++version = "0.11.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" ++dependencies = [ ++ "semver-parser", ++ "serde", ++] ++ ++[[package]] ++name = "semver-parser" ++version = "0.10.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" ++dependencies = [ ++ "pest", ++] ++ ++[[package]] ++name = "serde" ++version = "1.0.131" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" ++dependencies = [ ++ "serde_derive", ++] ++ ++[[package]] ++name = "serde_derive" ++version = "1.0.131" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" ++dependencies = [ ++ "proc-macro2", ++ "quote", ++ "syn", ++] ++ ++[[package]] ++name = "serde_json" ++version = "1.0.73" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" ++dependencies = [ ++ "itoa", ++ "ryu", ++ "serde", ++] ++ ++[[package]] ++name = "static_assertions" ++version = "1.1.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" ++ ++[[package]] ++name = "syn" ++version = "1.0.82" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" ++dependencies = [ ++ "proc-macro2", ++ "quote", ++ "unicode-xid", ++] ++ ++[[package]] ++name = "tap" ++version = "1.0.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" ++ ++[[package]] ++name = "textwrap" ++version = "0.11.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" ++dependencies = [ ++ "unicode-width", ++] ++ ++[[package]] ++name = "toml" ++version = "0.5.8" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" ++dependencies = [ ++ "serde", ++] ++ ++[[package]] ++name = "ucd-trie" ++version = "0.1.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" ++ ++[[package]] ++name = "unicode-segmentation" ++version = "1.8.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" ++ ++[[package]] ++name = "unicode-width" ++version = "0.1.9" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" ++ ++[[package]] ++name = "unicode-xid" ++version = "0.2.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" ++ ++[[package]] ++name = "uniffi_bindgen" ++version = "0.14.1" ++dependencies = [ ++ "anyhow", ++ "askama", ++ "cargo_metadata", ++ "clap", ++ "heck", ++ "paste", ++ "serde", ++ "toml", ++ "weedle", ++] ++ ++[[package]] ++name = "version_check" ++version = "0.9.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" ++ ++[[package]] ++name = "weedle" ++version = "0.12.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "610950904727748ca09682e857f0d6d6437f0ca862f32f9229edba8cec8b2635" ++dependencies = [ ++ "nom 5.1.2", ++] ++ ++[[package]] ++name = "wyz" ++version = "0.2.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/nix/uniffi_0.15.2_cargo_lock.patch b/nix/uniffi_0.15.2_cargo_lock.patch new file mode 100644 index 0000000..7fbc9e6 --- /dev/null +++ b/nix/uniffi_0.15.2_cargo_lock.patch @@ -0,0 +1,387 @@ +--- /dev/null 2021-12-15 11:22:02.342000000 +0100 ++++ uniffi_bindgen/Cargo.lock 2021-12-15 15:54:49.278543090 +0100 +@@ -0,0 +1,384 @@ ++# This file is automatically @generated by Cargo. ++# It is not intended for manual editing. ++version = 3 ++ ++[[package]] ++name = "anyhow" ++version = "1.0.51" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" ++ ++[[package]] ++name = "arrayvec" ++version = "0.5.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" ++ ++[[package]] ++name = "askama" ++version = "0.10.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "d298738b6e47e1034e560e5afe63aa488fea34e25ec11b855a76f0d7b8e73134" ++dependencies = [ ++ "askama_derive", ++ "askama_escape", ++ "askama_shared", ++] ++ ++[[package]] ++name = "askama_derive" ++version = "0.10.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "ca2925c4c290382f9d2fa3d1c1b6a63fa1427099721ecca4749b154cc9c25522" ++dependencies = [ ++ "askama_shared", ++ "proc-macro2", ++ "syn", ++] ++ ++[[package]] ++name = "askama_escape" ++version = "0.10.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "90c108c1a94380c89d2215d0ac54ce09796823cca0fd91b299cfff3b33e346fb" ++ ++[[package]] ++name = "askama_shared" ++version = "0.11.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "2582b77e0f3c506ec4838a25fa8a5f97b9bed72bb6d3d272ea1c031d8bd373bc" ++dependencies = [ ++ "askama_escape", ++ "nom 6.2.1", ++ "proc-macro2", ++ "quote", ++ "serde", ++ "syn", ++ "toml", ++] ++ ++[[package]] ++name = "bitflags" ++version = "1.3.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" ++ ++[[package]] ++name = "bitvec" ++version = "0.19.6" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33" ++dependencies = [ ++ "funty", ++ "radium", ++ "tap", ++ "wyz", ++] ++ ++[[package]] ++name = "camino" ++version = "1.0.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b" ++dependencies = [ ++ "serde", ++] ++ ++[[package]] ++name = "cargo-platform" ++version = "0.1.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" ++dependencies = [ ++ "serde", ++] ++ ++[[package]] ++name = "cargo_metadata" ++version = "0.13.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "081e3f0755c1f380c2d010481b6fa2e02973586d5f2b24eebb7a2a1d98b143d8" ++dependencies = [ ++ "camino", ++ "cargo-platform", ++ "semver", ++ "semver-parser", ++ "serde", ++ "serde_json", ++] ++ ++[[package]] ++name = "cfg-if" ++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 = [ ++ "bitflags", ++ "textwrap", ++ "unicode-width", ++] ++ ++[[package]] ++name = "funty" ++version = "1.1.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" ++ ++[[package]] ++name = "heck" ++version = "0.3.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" ++dependencies = [ ++ "unicode-segmentation", ++] ++ ++[[package]] ++name = "itoa" ++version = "1.0.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" ++ ++[[package]] ++name = "lexical-core" ++version = "0.7.6" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" ++dependencies = [ ++ "arrayvec", ++ "bitflags", ++ "cfg-if", ++ "ryu", ++ "static_assertions", ++] ++ ++[[package]] ++name = "memchr" ++version = "2.3.4" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" ++ ++[[package]] ++name = "nom" ++version = "5.1.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" ++dependencies = [ ++ "memchr", ++ "version_check", ++] ++ ++[[package]] ++name = "nom" ++version = "6.2.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" ++dependencies = [ ++ "bitvec", ++ "funty", ++ "lexical-core", ++ "memchr", ++ "version_check", ++] ++ ++[[package]] ++name = "paste" ++version = "1.0.6" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" ++ ++[[package]] ++name = "pest" ++version = "2.1.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" ++dependencies = [ ++ "ucd-trie", ++] ++ ++[[package]] ++name = "proc-macro2" ++version = "1.0.34" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1" ++dependencies = [ ++ "unicode-xid", ++] ++ ++[[package]] ++name = "quote" ++version = "1.0.10" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" ++dependencies = [ ++ "proc-macro2", ++] ++ ++[[package]] ++name = "radium" ++version = "0.5.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" ++ ++[[package]] ++name = "ryu" ++version = "1.0.9" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" ++ ++[[package]] ++name = "semver" ++version = "0.11.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" ++dependencies = [ ++ "semver-parser", ++ "serde", ++] ++ ++[[package]] ++name = "semver-parser" ++version = "0.10.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" ++dependencies = [ ++ "pest", ++] ++ ++[[package]] ++name = "serde" ++version = "1.0.131" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" ++dependencies = [ ++ "serde_derive", ++] ++ ++[[package]] ++name = "serde_derive" ++version = "1.0.131" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" ++dependencies = [ ++ "proc-macro2", ++ "quote", ++ "syn", ++] ++ ++[[package]] ++name = "serde_json" ++version = "1.0.73" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" ++dependencies = [ ++ "itoa", ++ "ryu", ++ "serde", ++] ++ ++[[package]] ++name = "static_assertions" ++version = "1.1.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" ++ ++[[package]] ++name = "syn" ++version = "1.0.82" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" ++dependencies = [ ++ "proc-macro2", ++ "quote", ++ "unicode-xid", ++] ++ ++[[package]] ++name = "tap" ++version = "1.0.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" ++ ++[[package]] ++name = "textwrap" ++version = "0.11.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" ++dependencies = [ ++ "unicode-width", ++] ++ ++[[package]] ++name = "toml" ++version = "0.5.8" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" ++dependencies = [ ++ "serde", ++] ++ ++[[package]] ++name = "ucd-trie" ++version = "0.1.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" ++ ++[[package]] ++name = "unicode-segmentation" ++version = "1.8.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" ++ ++[[package]] ++name = "unicode-width" ++version = "0.1.9" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" ++ ++[[package]] ++name = "unicode-xid" ++version = "0.2.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" ++ ++[[package]] ++name = "uniffi_bindgen" ++version = "0.15.2" ++dependencies = [ ++ "anyhow", ++ "askama", ++ "cargo_metadata", ++ "clap", ++ "heck", ++ "paste", ++ "serde", ++ "toml", ++ "weedle", ++] ++ ++[[package]] ++name = "version_check" ++version = "0.9.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" ++ ++[[package]] ++name = "weedle" ++version = "0.12.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "610950904727748ca09682e857f0d6d6437f0ca862f32f9229edba8cec8b2635" ++dependencies = [ ++ "nom 5.1.2", ++] ++ ++[[package]] ++name = "wyz" ++version = "0.2.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/nix/uniffi_bindgen.nix b/nix/uniffi_bindgen.nix new file mode 100644 index 0000000..42cf6ab --- /dev/null +++ b/nix/uniffi_bindgen.nix @@ -0,0 +1,20 @@ +with import {}; + +rustPlatform.buildRustPackage rec { + pname = "uniffi_bindgen"; + version = "0.15.2"; + src = fetchFromGitHub { + owner = "mozilla"; + repo = "uniffi-rs"; + rev = "6fa9c06a394b4e9b219fa30fc94e353d17f86e11"; + # rev = "refs/tags/v0.14.1"; + sha256 = "1chahy1ac1r88drpslln2p1b04cbg79ylpxzyyp92s1z7ldm5ddb"; # 0.15.2 + # sha256 = "1mff3f3fqqzqx1yv70ff1yzdnvbd90vg2r477mzzcgisg1wfpwi0"; # 0.14.1 + fetchSubmodules = true; + } + "/uniffi_bindgen/"; + + doCheck = false; + cargoSha256 = "sha256:08gg285fq8i32nf9kd8s0nn0niacd7sg8krv818nx41i18sm2cf3"; # 0.15.2 + # cargoSha256 = "sha256:01zp3rwlni988h02dqhkhzhwccs7bhwc1alhbf6gbw3av4b0m9cf"; # 0.14.1 + cargoPatches = [ ./uniffi_0.15.2_cargo_lock.patch ]; +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..d6ba728 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +semantic-version==2.9.0 +setuptools-rust==1.1.2 +typing_extensions==4.0.1 diff --git a/setup.py b/setup.py index 3006e53..55de5d7 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,9 @@ #!/usr/bin/env python -from setuptools import setup, find_packages +import os + +from setuptools import setup +from setuptools_rust import Binding, RustExtension LONG_DESCRIPTION = """# bdkpython The Python language bindings for the [bitcoindevkit](https://github.com/bitcoindevkit). @@ -60,17 +63,22 @@ def update(self, progress, update): ``` """ +rust_ext = RustExtension( + "bdkpython.bdkffi", + path="./bdk-ffi/Cargo.toml", + binding=Binding.NoBinding, +) + setup( - name='bdkpython', - version='0.0.4', - packages=find_packages(where="src"), - package_dir={"": "src"}, - package_data={"bdkpython": ["*/*.dylib", "*/*.so"]}, - include_package_data=True, - zip_safe=False, + name = 'bdkpython', + version = '0.0.4', description="The Python language bindings for the bitcoindevkit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', + rust_extensions=[rust_ext], + zip_safe=False, + packages=['bdkpython'], + package_dir={ 'bdkpython': './src/bdkpython' }, url="https://github.com/thunderbiscuit/bdk-python", author="Alekos Filini , Steve Myers ", license="MIT or Apache 2.0", diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..1b59fca --- /dev/null +++ b/shell.nix @@ -0,0 +1,17 @@ +with import {}; + +mkShell { + name = "bdk-python-shell"; + packages = [ ( import ./nix/uniffi_bindgen.nix ) ]; + buildInputs = with python37.pkgs; [ + pip + setuptools + ]; + shellHook = '' + export LD_LIBRARY_PATH=${pkgs.stdenv.cc.cc.lib}/lib:$LD_LIBRARY_PATH + alias pip="PIP_PREFIX='$(pwd)/_build/pip_packages' \pip" + export PYTHONPATH="$(pwd)/_build/pip_packages/lib/python3.7/site-packages:$(pwd):$PYTHONPATH" + export PATH="$(pwd)/_build/pip_packages/bin:$PATH" + unset SOURCE_DATE_EPOCH + ''; +} diff --git a/src/bdkpython/bdk.py b/src/bdkpython/bdk.py deleted file mode 100644 index b6e0679..0000000 --- a/src/bdkpython/bdk.py +++ /dev/null @@ -1,1891 +0,0 @@ -# This file was autogenerated by some hot garbage in the `uniffi` crate. -# Trust me, you don't want to mess with it! - -# Common helper code. -# -# Ideally this would live in a separate .py file where it can be unittested etc -# in isolation, and perhaps even published as a re-useable package. -# -# However, it's important that the details 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 Python -# helpers directly inline like we're doing here. - -import os -import sys -import ctypes -import enum -import struct -import contextlib -import datetime - - -class RustBuffer(ctypes.Structure): - _fields_ = [ - ("capacity", ctypes.c_int32), - ("len", ctypes.c_int32), - ("data", ctypes.POINTER(ctypes.c_char)), - ] - - @staticmethod - def alloc(size): - return rust_call(_UniFFILib.ffi_bdk_b9b3_rustbuffer_alloc, size) - - @staticmethod - def reserve(rbuf, additional): - return rust_call(_UniFFILib.ffi_bdk_b9b3_rustbuffer_reserve, rbuf, additional) - - def free(self): - return rust_call(_UniFFILib.ffi_bdk_b9b3_rustbuffer_free, self) - - def __str__(self): - return "RustBuffer(capacity={}, len={}, data={})".format( - self.capacity, - self.len, - self.data[0:self.len] - ) - - @contextlib.contextmanager - def allocWithBuilder(): - """Context-manger to allocate a buffer using a RustBufferBuilder. - - The allocated buffer will be automatically freed if an error occurs, ensuring that - we don't accidentally leak it. - """ - builder = RustBufferBuilder() - try: - yield builder - except: - builder.discard() - raise - - @contextlib.contextmanager - def consumeWithStream(self): - """Context-manager to consume a buffer using a RustBufferStream. - - The RustBuffer will be freed once the context-manager exits, ensuring that we don't - leak it even if an error occurs. - """ - try: - s = RustBufferStream(self) - yield s - if s.remaining() != 0: - raise RuntimeError("junk data left in buffer after consuming") - finally: - self.free() - - -class ForeignBytes(ctypes.Structure): - _fields_ = [ - ("len", ctypes.c_int32), - ("data", ctypes.POINTER(ctypes.c_char)), - ] - - def __str__(self): - return "ForeignBytes(len={}, data={})".format(self.len, self.data[0:self.len]) - - -class RustBufferStream(object): - """ - Helper for structured reading of bytes from a RustBuffer - """ - - def __init__(self, rbuf): - self.rbuf = rbuf - self.offset = 0 - - def remaining(self): - return self.rbuf.len - self.offset - - def _unpack_from(self, size, format): - if self.offset + size > self.rbuf.len: - raise InternalError("read past end of rust buffer") - value = struct.unpack(format, self.rbuf.data[self.offset:self.offset+size])[0] - self.offset += size - return value - - def read(self, size): - if self.offset + size > self.rbuf.len: - raise InternalError("read past end of rust buffer") - data = self.rbuf.data[self.offset:self.offset+size] - self.offset += size - return data - - def readI8(self): - return self._unpack_from(1, ">b") - - def readU8(self): - return self._unpack_from(1, ">B") - - def readI16(self): - return self._unpack_from(2, ">h") - - def readU16(self): - return self._unpack_from(2, ">H") - - def readI32(self): - return self._unpack_from(4, ">i") - - def readU32(self): - return self._unpack_from(4, ">I") - - def readI64(self): - return self._unpack_from(8, ">q") - - def readU64(self): - return self._unpack_from(8, ">Q") - - def readFloat(self): - v = self._unpack_from(4, ">f") - return v - - def readDouble(self): - return self._unpack_from(8, ">d") - - -class RustBufferBuilder(object): - """ - Helper for structured writing of bytes into a RustBuffer. - """ - - def __init__(self): - self.rbuf = RustBuffer.alloc(16) - self.rbuf.len = 0 - - def finalize(self): - rbuf = self.rbuf - self.rbuf = None - return rbuf - - def discard(self): - if self.rbuf is not None: - rbuf = self.finalize() - rbuf.free() - - @contextlib.contextmanager - def _reserve(self, numBytes): - if self.rbuf.len + numBytes > self.rbuf.capacity: - self.rbuf = RustBuffer.reserve(self.rbuf, numBytes) - yield None - self.rbuf.len += numBytes - - def _pack_into(self, size, format, value): - with self._reserve(size): - # XXX TODO: I feel like I should be able to use `struct.pack_into` here but can't figure it out. - for i, byte in enumerate(struct.pack(format, value)): - self.rbuf.data[self.rbuf.len + i] = byte - - def write(self, value): - with self._reserve(len(value)): - for i, byte in enumerate(value): - self.rbuf.data[self.rbuf.len + i] = byte - - def writeI8(self, v): - self._pack_into(1, ">b", v) - - def writeU8(self, v): - self._pack_into(1, ">B", v) - - def writeI16(self, v): - self._pack_into(2, ">h", v) - - def writeU16(self, v): - self._pack_into(2, ">H", v) - - def writeI32(self, v): - self._pack_into(4, ">i", v) - - def writeU32(self, v): - self._pack_into(4, ">I", v) - - def writeI64(self, v): - self._pack_into(8, ">q", v) - - def writeU64(self, v): - self._pack_into(8, ">Q", v) - - def writeFloat(self, v): - self._pack_into(4, ">f", v) - - def writeDouble(self, v): - self._pack_into(8, ">d", v) -# 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. - -class InternalError(Exception): - pass - -class RustCallStatus(ctypes.Structure): - """ - Error runtime. - """ - _fields_ = [ - ("code", ctypes.c_int8), - ("error_buf", RustBuffer), - ] - - # These match the values from the uniffi::rustcalls module - CALL_SUCCESS = 0 - CALL_ERROR = 1 - CALL_PANIC = 2 - - def __str__(self): - if self.code == RustCallStatus.CALL_SUCCESS: - return "RustCallStatus(CALL_SUCCESS)" - elif self.code == RustCallStatus.CALL_ERROR: - return "RustCallStatus(CALL_ERROR)" - elif self.code == RustCallStatus.CALL_PANIC: - return "RustCallStatus(CALL_SUCCESS)" - else: - return "RustCallStatus()" - -def rust_call(fn, *args): - # Call a rust function - return rust_call_with_error(None, fn, *args) - -def rust_call_with_error(error_class, fn, *args): - # Call a rust function and handle any errors - # - # This function is used for rust calls that return Result<> and therefore can set the CALL_ERROR status code. - # error_class must be set to the error class that corresponds to the result. - call_status = RustCallStatus(code=RustCallStatus.CALL_SUCCESS, error_buf=RustBuffer(0, 0, None)) - - args_with_error = args + (ctypes.byref(call_status),) - result = fn(*args_with_error) - if call_status.code == RustCallStatus.CALL_SUCCESS: - return result - elif call_status.code == RustCallStatus.CALL_ERROR: - if error_class is None: - call_status.err_buf.contents.free() - raise InternalError("rust_call_with_error: CALL_ERROR, but no error class set") - else: - raise error_class._lift(call_status.error_buf) - elif call_status.code == RustCallStatus.CALL_PANIC: - # 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 call_status.error_buf.len > 0: - msg = FfiConverterString._lift(call_status.error_buf) - else: - msg = "Unknown rust panic" - raise InternalError(msg) - else: - raise InternalError("Invalid RustCallStatus code: {}".format( - call_status.code)) - -# A function pointer for a callback as defined by UniFFI. -# Rust definition `fn(handle: u64, method: u32, args: RustBuffer, buf_ptr: *mut RustBuffer) -> int` -FOREIGN_CALLBACK_T = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_ulonglong, ctypes.c_ulong, RustBuffer, ctypes.POINTER(RustBuffer)) -# Types conforming to `Primitive` pass themselves directly over the FFI. -class Primitive: - @classmethod - def _lift(cls, value): - return value - - @classmethod - def _lower(cls, value): - return value - -# Helper class for new types that will always go through a RustBuffer. -# Classes should inherit from this and implement the `_read` static method -# and `_write` instance methods. -class ViaFfiUsingByteBuffer: - @classmethod - def _lift(cls, rbuf): - with rbuf.consumeWithStream() as stream: - return cls._read(stream) - - def _lower(self): - with RustBuffer.allocWithBuilder() as builder: - self._write(builder) - return builder.finalize() - -# Helper class for wrapper types that will always go through a RustBuffer. -# Classes should inherit from this and implement the `_read` and `_write` static methods. -class FfiConverterUsingByteBuffer: - @classmethod - def _lift(cls, rbuf): - with rbuf.consumeWithStream() as stream: - return cls._read(stream) - - @classmethod - def _lower(cls, value): - with RustBuffer.allocWithBuilder() as builder: - cls._write(value, builder) - return builder.finalize() - -# Helpers for structural types. - -class FfiConverterSequence: - @staticmethod - def _write(value, buf, writeItem): - items = len(value) - buf.writeI32(items) - for item in value: - writeItem(item, buf) - - @staticmethod - def _read(buf, readItem): - count = buf.readI32() - if count < 0: - raise InternalError("Unexpected negative sequence length") - - items = [] - while count > 0: - items.append(readItem(buf)) - count -= 1 - return items - -class FfiConverterOptional: - @staticmethod - def _write(value, buf, writeItem): - if value is None: - buf.writeU8(0) - return - - buf.writeU8(1) - writeItem(value, buf) - - @staticmethod - def _read(buf, readItem): - flag = buf.readU8() - if flag == 0: - return None - elif flag == 1: - return readItem(buf) - else: - raise InternalError("Unexpected flag byte for optional type") - -class FfiConverterDictionary: - @staticmethod - def _write(items, buf, writeItem): - buf.writeI32(len(items)) - for (key, value) in items.items(): - writeItem(key, value, buf) - - @staticmethod - def _read(buf, readItem): - count = buf.readI32() - if count < 0: - raise InternalError("Unexpected negative map size") - items = {} - while count > 0: - key, value = readItem(buf) - items[key] = value - count -= 1 - return items - -# Contains loading, initialization code, -# and the FFI Function declarations in a com.sun.jna.Library. -# This is how we find and load the dynamic library provided by the component. -# For now we just look it up by name. -# -# XXX TODO: This will probably grow some magic for resolving megazording in future. -# E.g. we might start by looking for the named component in `libuniffi.so` and if -# that fails, fall back to loading it separately from `lib${componentName}.so`. - -def loadIndirect(): - if sys.platform == "linux": - # libname = "lib{}.so" - libname = os.path.join(os.path.dirname(__file__), "lib{}.so") - elif sys.platform == "darwin": - # libname = "lib{}.dylib" - libname = os.path.join(os.path.dirname(__file__), "lib{}.dylib") - elif sys.platform.startswith("win"): - # As of python3.8, ctypes does not seem to search $PATH when loading DLLs. - # We could use `os.add_dll_directory` to configure the search path, but - # it doesn't feel right to mess with application-wide settings. Let's - # assume that the `.dll` is next to the `.py` file and load by full path. - libname = os.path.join( - os.path.dirname(__file__), - "{}.dll", - ) - return getattr(ctypes.cdll, libname.format("bdkffi")) - -# A ctypes library to expose the extern-C FFI definitions. -# This is an implementation detail which will be called internally by the public API. - -_UniFFILib = loadIndirect() -_UniFFILib.ffi_bdk_b9b3_OfflineWallet_object_free.argtypes = ( - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.ffi_bdk_b9b3_OfflineWallet_object_free.restype = None -_UniFFILib.bdk_b9b3_OfflineWallet_new.argtypes = ( - RustBuffer, - RustBuffer, - RustBuffer, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OfflineWallet_new.restype = ctypes.c_void_p -_UniFFILib.bdk_b9b3_OfflineWallet_get_new_address.argtypes = ( - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OfflineWallet_get_new_address.restype = RustBuffer -_UniFFILib.bdk_b9b3_OfflineWallet_get_last_unused_address.argtypes = ( - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OfflineWallet_get_last_unused_address.restype = RustBuffer -_UniFFILib.bdk_b9b3_OfflineWallet_get_balance.argtypes = ( - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OfflineWallet_get_balance.restype = ctypes.c_uint64 -_UniFFILib.bdk_b9b3_OfflineWallet_sign.argtypes = ( - ctypes.c_void_p, - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OfflineWallet_sign.restype = None -_UniFFILib.bdk_b9b3_OfflineWallet_get_transactions.argtypes = ( - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OfflineWallet_get_transactions.restype = RustBuffer -_UniFFILib.ffi_bdk_b9b3_OnlineWallet_object_free.argtypes = ( - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.ffi_bdk_b9b3_OnlineWallet_object_free.restype = None -_UniFFILib.bdk_b9b3_OnlineWallet_new.argtypes = ( - RustBuffer, - RustBuffer, - RustBuffer, - RustBuffer, - RustBuffer, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OnlineWallet_new.restype = ctypes.c_void_p -_UniFFILib.bdk_b9b3_OnlineWallet_get_new_address.argtypes = ( - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OnlineWallet_get_new_address.restype = RustBuffer -_UniFFILib.bdk_b9b3_OnlineWallet_get_last_unused_address.argtypes = ( - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OnlineWallet_get_last_unused_address.restype = RustBuffer -_UniFFILib.bdk_b9b3_OnlineWallet_get_balance.argtypes = ( - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OnlineWallet_get_balance.restype = ctypes.c_uint64 -_UniFFILib.bdk_b9b3_OnlineWallet_sign.argtypes = ( - ctypes.c_void_p, - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OnlineWallet_sign.restype = None -_UniFFILib.bdk_b9b3_OnlineWallet_get_transactions.argtypes = ( - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OnlineWallet_get_transactions.restype = RustBuffer -_UniFFILib.bdk_b9b3_OnlineWallet_get_network.argtypes = ( - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OnlineWallet_get_network.restype = RustBuffer -_UniFFILib.bdk_b9b3_OnlineWallet_sync.argtypes = ( - ctypes.c_void_p, - ctypes.c_uint64, - RustBuffer, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OnlineWallet_sync.restype = None -_UniFFILib.bdk_b9b3_OnlineWallet_broadcast.argtypes = ( - ctypes.c_void_p, - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_OnlineWallet_broadcast.restype = RustBuffer -_UniFFILib.ffi_bdk_b9b3_PartiallySignedBitcoinTransaction_object_free.argtypes = ( - ctypes.c_void_p, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.ffi_bdk_b9b3_PartiallySignedBitcoinTransaction_object_free.restype = None -_UniFFILib.bdk_b9b3_PartiallySignedBitcoinTransaction_new.argtypes = ( - ctypes.c_void_p, - RustBuffer, - ctypes.c_uint64, - RustBuffer, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_PartiallySignedBitcoinTransaction_new.restype = ctypes.c_void_p -_UniFFILib.ffi_bdk_b9b3_BdkProgress_init_callback.argtypes = ( - FOREIGN_CALLBACK_T, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.ffi_bdk_b9b3_BdkProgress_init_callback.restype = None -_UniFFILib.bdk_b9b3_generate_extended_key.argtypes = ( - RustBuffer, - RustBuffer, - RustBuffer, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_generate_extended_key.restype = RustBuffer -_UniFFILib.bdk_b9b3_restore_extended_key.argtypes = ( - RustBuffer, - RustBuffer, - RustBuffer, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.bdk_b9b3_restore_extended_key.restype = RustBuffer -_UniFFILib.ffi_bdk_b9b3_rustbuffer_alloc.argtypes = ( - ctypes.c_int32, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.ffi_bdk_b9b3_rustbuffer_alloc.restype = RustBuffer -_UniFFILib.ffi_bdk_b9b3_rustbuffer_from_bytes.argtypes = ( - ForeignBytes, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.ffi_bdk_b9b3_rustbuffer_from_bytes.restype = RustBuffer -_UniFFILib.ffi_bdk_b9b3_rustbuffer_free.argtypes = ( - RustBuffer, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.ffi_bdk_b9b3_rustbuffer_free.restype = None -_UniFFILib.ffi_bdk_b9b3_rustbuffer_reserve.argtypes = ( - RustBuffer, - ctypes.c_int32, - ctypes.POINTER(RustCallStatus), -) -_UniFFILib.ffi_bdk_b9b3_rustbuffer_reserve.restype = RustBuffer - -# Public interface members begin here. - -import threading - -class ConcurrentHandleMap: - """ - A map where inserting, getting and removing data is synchronized with a lock. - """ - - def __init__(self): - # type Handle = int - self._left_map = {} # type: Dict[Handle, Any] - self._right_map = {} # type: Dict[Any, Handle] - - self._lock = threading.Lock() - self._current_handle = 0 - self._stride = 1 - - - def insert(self, obj): - with self._lock: - if obj in self._right_map: - return self._right_map[obj] - else: - handle = self._current_handle - self._current_handle += self._stride - self._left_map[handle] = obj - self._right_map[obj] = handle - return handle - - def get(self, handle): - with self._lock: - return self._left_map.get(handle) - - def remove(self, handle): - with self._lock: - if handle in self._left_map: - obj = self._left_map.pop(handle) - del self._right_map[obj] - return obj - -# 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. -IDX_CALLBACK_FREE = 0 - -class FfiConverterCallbackInterface: - _handle_map = ConcurrentHandleMap() - - def __init__(self, cb): - self._foreign_callback = cb - - def drop(self, handle): - self.__class__._handle_map.remove(handle) - - @classmethod - def _lift(cls, handle): - obj = cls._handle_map.get(handle) - if not obj: - raise InternalError("The object in the handle map has been dropped already") - - return obj - - @classmethod - def _read(cls, buf): - handle = buf.readU64() - cls._lift(handle) - - @classmethod - def _lower(cls, cb): - handle = cls._handle_map.insert(cb) - return handle - - @classmethod - def _write(cls, cb, buf): - buf.writeU64(cls._lower(cb)) - - - -class Network(ViaFfiUsingByteBuffer, enum.Enum): - BITCOIN = 1 - TESTNET = 2 - SIGNET = 3 - REGTEST = 4 - - - @staticmethod - def _read(buf): - variant = buf.readI32() - if variant == 1: - return Network.BITCOIN - if variant == 2: - return Network.TESTNET - if variant == 3: - return Network.SIGNET - if variant == 4: - return Network.REGTEST - - raise InternalError("Raw enum value doesn't match any cases") - - def _write(self, buf): - if self is Network.BITCOIN: - i = 1 - buf.writeI32(1) - if self is Network.TESTNET: - i = 2 - buf.writeI32(2) - if self is Network.SIGNET: - i = 3 - buf.writeI32(3) - if self is Network.REGTEST: - i = 4 - buf.writeI32(4) - - - - - - - -class DatabaseConfig(ViaFfiUsingByteBuffer, object): - def __init__(self): - raise RuntimeError("DatabaseConfig cannot be instantiated directly") - - # Each enum variant is a nested class of the enum itself. - class MEMORY(object): - def __init__(self,junk ): - - self.junk = junk - - - def __str__(self): - return "DatabaseConfig.MEMORY(junk={} )".format(self.junk ) - - def __eq__(self, other): - if not other.is_memory(): - return False - if self.junk != other.junk: - return False - return True - class SLED(object): - def __init__(self,config ): - - self.config = config - - - def __str__(self): - return "DatabaseConfig.SLED(config={} )".format(self.config ) - - def __eq__(self, other): - if not other.is_sled(): - return False - if self.config != other.config: - return False - return True - - - # For each variant, we have an `is_NAME` method for easily checking - # whether an instance is that variant. - def is_memory(self): - return isinstance(self, DatabaseConfig.MEMORY) - def is_sled(self): - return isinstance(self, DatabaseConfig.SLED) - - - @classmethod - def _read(cls, buf): - variant = buf.readI32() - - if variant == 1: - return cls.MEMORY( - junk=FfiConverterString._read(buf), - ) - if variant == 2: - return cls.SLED( - config=SledDbConfiguration._read(buf), - ) - - raise InternalError("Raw enum value doesn't match any cases") - - def _write(self, buf): - if self.is_memory(): - buf.writeI32(1) - FfiConverterString._write(self.junk, buf) - if self.is_sled(): - buf.writeI32(2) - self.config._write(buf) - - -# Now, a little trick - we make each nested variant class be a subclass of the main -# enum class, so that method calls and instance checks etc will work intuitively. -# We might be able to do this a little more neatly with a metaclass, but this'll do. -DatabaseConfig.MEMORY = type("DatabaseConfig.MEMORY", (DatabaseConfig.MEMORY, DatabaseConfig,), {}) -DatabaseConfig.SLED = type("DatabaseConfig.SLED", (DatabaseConfig.SLED, DatabaseConfig,), {}) - - - - - - - -class Transaction(ViaFfiUsingByteBuffer, object): - def __init__(self): - raise RuntimeError("Transaction cannot be instantiated directly") - - # Each enum variant is a nested class of the enum itself. - class UNCONFIRMED(object): - def __init__(self,details ): - - self.details = details - - - def __str__(self): - return "Transaction.UNCONFIRMED(details={} )".format(self.details ) - - def __eq__(self, other): - if not other.is_unconfirmed(): - return False - if self.details != other.details: - return False - return True - class CONFIRMED(object): - def __init__(self,details, confirmation ): - - self.details = details - self.confirmation = confirmation - - - def __str__(self): - return "Transaction.CONFIRMED(details={}, confirmation={} )".format(self.details, self.confirmation ) - - def __eq__(self, other): - if not other.is_confirmed(): - return False - if self.details != other.details: - return False - if self.confirmation != other.confirmation: - return False - return True - - - # For each variant, we have an `is_NAME` method for easily checking - # whether an instance is that variant. - def is_unconfirmed(self): - return isinstance(self, Transaction.UNCONFIRMED) - def is_confirmed(self): - return isinstance(self, Transaction.CONFIRMED) - - - @classmethod - def _read(cls, buf): - variant = buf.readI32() - - if variant == 1: - return cls.UNCONFIRMED( - details=TransactionDetails._read(buf), - ) - if variant == 2: - return cls.CONFIRMED( - details=TransactionDetails._read(buf), - confirmation=Confirmation._read(buf), - ) - - raise InternalError("Raw enum value doesn't match any cases") - - def _write(self, buf): - if self.is_unconfirmed(): - buf.writeI32(1) - self.details._write(buf) - if self.is_confirmed(): - buf.writeI32(2) - self.details._write(buf) - self.confirmation._write(buf) - - -# Now, a little trick - we make each nested variant class be a subclass of the main -# enum class, so that method calls and instance checks etc will work intuitively. -# We might be able to do this a little more neatly with a metaclass, but this'll do. -Transaction.UNCONFIRMED = type("Transaction.UNCONFIRMED", (Transaction.UNCONFIRMED, Transaction,), {}) -Transaction.CONFIRMED = type("Transaction.CONFIRMED", (Transaction.CONFIRMED, Transaction,), {}) - - - - - - - -class BlockchainConfig(ViaFfiUsingByteBuffer, object): - def __init__(self): - raise RuntimeError("BlockchainConfig cannot be instantiated directly") - - # Each enum variant is a nested class of the enum itself. - class ELECTRUM(object): - def __init__(self,config ): - - self.config = config - - - def __str__(self): - return "BlockchainConfig.ELECTRUM(config={} )".format(self.config ) - - def __eq__(self, other): - if not other.is_electrum(): - return False - if self.config != other.config: - return False - return True - class ESPLORA(object): - def __init__(self,config ): - - self.config = config - - - def __str__(self): - return "BlockchainConfig.ESPLORA(config={} )".format(self.config ) - - def __eq__(self, other): - if not other.is_esplora(): - return False - if self.config != other.config: - return False - return True - - - # For each variant, we have an `is_NAME` method for easily checking - # whether an instance is that variant. - def is_electrum(self): - return isinstance(self, BlockchainConfig.ELECTRUM) - def is_esplora(self): - return isinstance(self, BlockchainConfig.ESPLORA) - - - @classmethod - def _read(cls, buf): - variant = buf.readI32() - - if variant == 1: - return cls.ELECTRUM( - config=ElectrumConfig._read(buf), - ) - if variant == 2: - return cls.ESPLORA( - config=EsploraConfig._read(buf), - ) - - raise InternalError("Raw enum value doesn't match any cases") - - def _write(self, buf): - if self.is_electrum(): - buf.writeI32(1) - self.config._write(buf) - if self.is_esplora(): - buf.writeI32(2) - self.config._write(buf) - - -# Now, a little trick - we make each nested variant class be a subclass of the main -# enum class, so that method calls and instance checks etc will work intuitively. -# We might be able to do this a little more neatly with a metaclass, but this'll do. -BlockchainConfig.ELECTRUM = type("BlockchainConfig.ELECTRUM", (BlockchainConfig.ELECTRUM, BlockchainConfig,), {}) -BlockchainConfig.ESPLORA = type("BlockchainConfig.ESPLORA", (BlockchainConfig.ESPLORA, BlockchainConfig,), {}) - - - - - - -class MnemonicType(ViaFfiUsingByteBuffer, enum.Enum): - WORDS12 = 1 - WORDS15 = 2 - WORDS18 = 3 - WORDS21 = 4 - WORDS24 = 5 - - - @staticmethod - def _read(buf): - variant = buf.readI32() - if variant == 1: - return MnemonicType.WORDS12 - if variant == 2: - return MnemonicType.WORDS15 - if variant == 3: - return MnemonicType.WORDS18 - if variant == 4: - return MnemonicType.WORDS21 - if variant == 5: - return MnemonicType.WORDS24 - - raise InternalError("Raw enum value doesn't match any cases") - - def _write(self, buf): - if self is MnemonicType.WORDS12: - i = 1 - buf.writeI32(1) - if self is MnemonicType.WORDS15: - i = 2 - buf.writeI32(2) - if self is MnemonicType.WORDS18: - i = 3 - buf.writeI32(3) - if self is MnemonicType.WORDS21: - i = 4 - buf.writeI32(4) - if self is MnemonicType.WORDS24: - i = 5 - buf.writeI32(5) - - - - - -def generate_extended_key(network,mnemonic_type,password): - network = network - mnemonic_type = mnemonic_type - password = (None if password is None else password) - _retval = rust_call_with_error(BdkError,_UniFFILib.bdk_b9b3_generate_extended_key,network._lower(),mnemonic_type._lower(),FfiConverterOptionalString._lower(password)) - return ExtendedKeyInfo._lift(_retval) - - - -def restore_extended_key(network,mnemonic,password): - network = network - mnemonic = mnemonic - password = (None if password is None else password) - _retval = rust_call_with_error(BdkError,_UniFFILib.bdk_b9b3_restore_extended_key,network._lower(),FfiConverterString._lower(mnemonic),FfiConverterOptionalString._lower(password)) - return ExtendedKeyInfo._lift(_retval) - - - -class OfflineWallet(object): - def __init__(self, descriptor,network,database_config): - descriptor = descriptor - network = network - database_config = database_config - self._pointer = rust_call_with_error(BdkError,_UniFFILib.bdk_b9b3_OfflineWallet_new,FfiConverterString._lower(descriptor),network._lower(),database_config._lower()) - - def __del__(self): - # In case of partial initialization of instances. - pointer = getattr(self, "_pointer", None) - if pointer is not None: - rust_call(_UniFFILib.ffi_bdk_b9b3_OfflineWallet_object_free, pointer) - - # Used by alternative constructors or any methods which return this type. - @classmethod - def _make_instance_(cls, pointer): - # Lightly yucky way to bypass the usual __init__ logic - # and just create a new instance with the required pointer. - inst = cls.__new__(cls) - inst._pointer = pointer - return inst - - - - def get_new_address(self, ): - _retval = rust_call(_UniFFILib.bdk_b9b3_OfflineWallet_get_new_address,self._pointer,) - return FfiConverterString._lift(_retval) - - def get_last_unused_address(self, ): - _retval = rust_call(_UniFFILib.bdk_b9b3_OfflineWallet_get_last_unused_address,self._pointer,) - return FfiConverterString._lift(_retval) - - def get_balance(self, ): - _retval = rust_call_with_error( - BdkError,_UniFFILib.bdk_b9b3_OfflineWallet_get_balance,self._pointer,) - return FfiConverterUInt64._lift(_retval) - - def sign(self, psbt): - psbt = psbt - rust_call_with_error( - BdkError,_UniFFILib.bdk_b9b3_OfflineWallet_sign,self._pointer,psbt._lower()) - - def get_transactions(self, ): - _retval = rust_call_with_error( - BdkError,_UniFFILib.bdk_b9b3_OfflineWallet_get_transactions,self._pointer,) - return FfiConverterSequenceEnumTransaction._lift(_retval) - - - - @classmethod - def _read(cls, buf): - ptr = buf.readU64() - if ptr == 0: - raise InternalError("Raw pointer value was null") - return cls._lift(ptr) - - @classmethod - def _write(cls, value, buf): - if not isinstance(value, OfflineWallet): - raise TypeError("Expected OfflineWallet instance, {} found".format(value.__class__.__name__)) - buf.writeU64(value._lower()) - - @classmethod - def _lift(cls, pointer): - return cls._make_instance_(pointer) - - def _lower(self): - return self._pointer - - -class OnlineWallet(object): - def __init__(self, descriptor,change_descriptor,network,database_config,blockchain_config): - descriptor = descriptor - change_descriptor = (None if change_descriptor is None else change_descriptor) - network = network - database_config = database_config - blockchain_config = blockchain_config - self._pointer = rust_call_with_error(BdkError,_UniFFILib.bdk_b9b3_OnlineWallet_new,FfiConverterString._lower(descriptor),FfiConverterOptionalString._lower(change_descriptor),network._lower(),database_config._lower(),blockchain_config._lower()) - - def __del__(self): - # In case of partial initialization of instances. - pointer = getattr(self, "_pointer", None) - if pointer is not None: - rust_call(_UniFFILib.ffi_bdk_b9b3_OnlineWallet_object_free, pointer) - - # Used by alternative constructors or any methods which return this type. - @classmethod - def _make_instance_(cls, pointer): - # Lightly yucky way to bypass the usual __init__ logic - # and just create a new instance with the required pointer. - inst = cls.__new__(cls) - inst._pointer = pointer - return inst - - - - def get_new_address(self, ): - _retval = rust_call(_UniFFILib.bdk_b9b3_OnlineWallet_get_new_address,self._pointer,) - return FfiConverterString._lift(_retval) - - def get_last_unused_address(self, ): - _retval = rust_call(_UniFFILib.bdk_b9b3_OnlineWallet_get_last_unused_address,self._pointer,) - return FfiConverterString._lift(_retval) - - def get_balance(self, ): - _retval = rust_call_with_error( - BdkError,_UniFFILib.bdk_b9b3_OnlineWallet_get_balance,self._pointer,) - return FfiConverterUInt64._lift(_retval) - - def sign(self, psbt): - psbt = psbt - rust_call_with_error( - BdkError,_UniFFILib.bdk_b9b3_OnlineWallet_sign,self._pointer,psbt._lower()) - - def get_transactions(self, ): - _retval = rust_call_with_error( - BdkError,_UniFFILib.bdk_b9b3_OnlineWallet_get_transactions,self._pointer,) - return FfiConverterSequenceEnumTransaction._lift(_retval) - - def get_network(self, ): - _retval = rust_call(_UniFFILib.bdk_b9b3_OnlineWallet_get_network,self._pointer,) - return Network._lift(_retval) - - def sync(self, progress_update,max_address_param): - progress_update = progress_update - max_address_param = (None if max_address_param is None else int(max_address_param)) - rust_call_with_error( - BdkError,_UniFFILib.bdk_b9b3_OnlineWallet_sync,self._pointer,FfiConverterCallbackInterfaceBdkProgress._lower(progress_update),FfiConverterOptionalUInt32._lower(max_address_param)) - - def broadcast(self, psbt): - psbt = psbt - _retval = rust_call_with_error( - BdkError,_UniFFILib.bdk_b9b3_OnlineWallet_broadcast,self._pointer,psbt._lower()) - return Transaction._lift(_retval) - - - - @classmethod - def _read(cls, buf): - ptr = buf.readU64() - if ptr == 0: - raise InternalError("Raw pointer value was null") - return cls._lift(ptr) - - @classmethod - def _write(cls, value, buf): - if not isinstance(value, OnlineWallet): - raise TypeError("Expected OnlineWallet instance, {} found".format(value.__class__.__name__)) - buf.writeU64(value._lower()) - - @classmethod - def _lift(cls, pointer): - return cls._make_instance_(pointer) - - def _lower(self): - return self._pointer - - -class PartiallySignedBitcoinTransaction(object): - def __init__(self, wallet,recipient,amount,fee_rate): - wallet = wallet - recipient = recipient - amount = int(amount) - fee_rate = (None if fee_rate is None else float(fee_rate)) - self._pointer = rust_call_with_error(BdkError,_UniFFILib.bdk_b9b3_PartiallySignedBitcoinTransaction_new,wallet._lower(),FfiConverterString._lower(recipient),FfiConverterUInt64._lower(amount),FfiConverterOptionalFloat._lower(fee_rate)) - - def __del__(self): - # In case of partial initialization of instances. - pointer = getattr(self, "_pointer", None) - if pointer is not None: - rust_call(_UniFFILib.ffi_bdk_b9b3_PartiallySignedBitcoinTransaction_object_free, pointer) - - # Used by alternative constructors or any methods which return this type. - @classmethod - def _make_instance_(cls, pointer): - # Lightly yucky way to bypass the usual __init__ logic - # and just create a new instance with the required pointer. - inst = cls.__new__(cls) - inst._pointer = pointer - return inst - - - - - - @classmethod - def _read(cls, buf): - ptr = buf.readU64() - if ptr == 0: - raise InternalError("Raw pointer value was null") - return cls._lift(ptr) - - @classmethod - def _write(cls, value, buf): - if not isinstance(value, PartiallySignedBitcoinTransaction): - raise TypeError("Expected PartiallySignedBitcoinTransaction instance, {} found".format(value.__class__.__name__)) - buf.writeU64(value._lower()) - - @classmethod - def _lift(cls, pointer): - return cls._make_instance_(pointer) - - def _lower(self): - return self._pointer - -class SledDbConfiguration(ViaFfiUsingByteBuffer, object): - def __init__(self,path, tree_name ): - self.path = path - self.tree_name = tree_name - - def __str__(self): - return "SledDbConfiguration(path={}, tree_name={} )".format(self.path, self.tree_name ) - - def __eq__(self, other): - if self.path != other.path: - return False - if self.tree_name != other.tree_name: - return False - return True - - @staticmethod - def _read(buf): - return SledDbConfiguration( - path=FfiConverterString._read(buf), - tree_name=FfiConverterString._read(buf) - ) - - def _write(self, buf): - FfiConverterString._write(self.path, buf) - FfiConverterString._write(self.tree_name, buf) - -class TransactionDetails(ViaFfiUsingByteBuffer, object): - def __init__(self,fees, received, sent, txid ): - self.fees = fees - self.received = received - self.sent = sent - self.txid = txid - - def __str__(self): - return "TransactionDetails(fees={}, received={}, sent={}, txid={} )".format(self.fees, self.received, self.sent, self.txid ) - - def __eq__(self, other): - if self.fees != other.fees: - return False - if self.received != other.received: - return False - if self.sent != other.sent: - return False - if self.txid != other.txid: - return False - return True - - @staticmethod - def _read(buf): - return TransactionDetails( - fees=FfiConverterOptionalUInt64._read(buf), - received=FfiConverterUInt64._read(buf), - sent=FfiConverterUInt64._read(buf), - txid=FfiConverterString._read(buf) - ) - - def _write(self, buf): - FfiConverterOptionalUInt64._write(self.fees, buf) - FfiConverterUInt64._write(self.received, buf) - FfiConverterUInt64._write(self.sent, buf) - FfiConverterString._write(self.txid, buf) - -class Confirmation(ViaFfiUsingByteBuffer, object): - def __init__(self,height, timestamp ): - self.height = height - self.timestamp = timestamp - - def __str__(self): - return "Confirmation(height={}, timestamp={} )".format(self.height, self.timestamp ) - - def __eq__(self, other): - if self.height != other.height: - return False - if self.timestamp != other.timestamp: - return False - return True - - @staticmethod - def _read(buf): - return Confirmation( - height=FfiConverterUInt32._read(buf), - timestamp=FfiConverterUInt64._read(buf) - ) - - def _write(self, buf): - FfiConverterUInt32._write(self.height, buf) - FfiConverterUInt64._write(self.timestamp, buf) - -class ElectrumConfig(ViaFfiUsingByteBuffer, object): - def __init__(self,url, socks5, retry, timeout, stop_gap ): - self.url = url - self.socks5 = socks5 - self.retry = retry - self.timeout = timeout - self.stop_gap = stop_gap - - def __str__(self): - return "ElectrumConfig(url={}, socks5={}, retry={}, timeout={}, stop_gap={} )".format(self.url, self.socks5, self.retry, self.timeout, self.stop_gap ) - - def __eq__(self, other): - if self.url != other.url: - return False - if self.socks5 != other.socks5: - return False - if self.retry != other.retry: - return False - if self.timeout != other.timeout: - return False - if self.stop_gap != other.stop_gap: - return False - return True - - @staticmethod - def _read(buf): - return ElectrumConfig( - url=FfiConverterString._read(buf), - socks5=FfiConverterOptionalString._read(buf), - retry=FfiConverterUInt8._read(buf), - timeout=FfiConverterOptionalUInt8._read(buf), - stop_gap=FfiConverterUInt64._read(buf) - ) - - def _write(self, buf): - FfiConverterString._write(self.url, buf) - FfiConverterOptionalString._write(self.socks5, buf) - FfiConverterUInt8._write(self.retry, buf) - FfiConverterOptionalUInt8._write(self.timeout, buf) - FfiConverterUInt64._write(self.stop_gap, buf) - -class EsploraConfig(ViaFfiUsingByteBuffer, object): - def __init__(self,base_url, proxy, timeout_read, timeout_write, stop_gap ): - self.base_url = base_url - self.proxy = proxy - self.timeout_read = timeout_read - self.timeout_write = timeout_write - self.stop_gap = stop_gap - - def __str__(self): - return "EsploraConfig(base_url={}, proxy={}, timeout_read={}, timeout_write={}, stop_gap={} )".format(self.base_url, self.proxy, self.timeout_read, self.timeout_write, self.stop_gap ) - - def __eq__(self, other): - if self.base_url != other.base_url: - return False - if self.proxy != other.proxy: - return False - if self.timeout_read != other.timeout_read: - return False - if self.timeout_write != other.timeout_write: - return False - if self.stop_gap != other.stop_gap: - return False - return True - - @staticmethod - def _read(buf): - return EsploraConfig( - base_url=FfiConverterString._read(buf), - proxy=FfiConverterOptionalString._read(buf), - timeout_read=FfiConverterUInt64._read(buf), - timeout_write=FfiConverterUInt64._read(buf), - stop_gap=FfiConverterUInt64._read(buf) - ) - - def _write(self, buf): - FfiConverterString._write(self.base_url, buf) - FfiConverterOptionalString._write(self.proxy, buf) - FfiConverterUInt64._write(self.timeout_read, buf) - FfiConverterUInt64._write(self.timeout_write, buf) - FfiConverterUInt64._write(self.stop_gap, buf) - -class ExtendedKeyInfo(ViaFfiUsingByteBuffer, object): - def __init__(self,mnemonic, xprv, fingerprint ): - self.mnemonic = mnemonic - self.xprv = xprv - self.fingerprint = fingerprint - - def __str__(self): - return "ExtendedKeyInfo(mnemonic={}, xprv={}, fingerprint={} )".format(self.mnemonic, self.xprv, self.fingerprint ) - - def __eq__(self, other): - if self.mnemonic != other.mnemonic: - return False - if self.xprv != other.xprv: - return False - if self.fingerprint != other.fingerprint: - return False - return True - - @staticmethod - def _read(buf): - return ExtendedKeyInfo( - mnemonic=FfiConverterString._read(buf), - xprv=FfiConverterString._read(buf), - fingerprint=FfiConverterString._read(buf) - ) - - def _write(self, buf): - FfiConverterString._write(self.mnemonic, buf) - FfiConverterString._write(self.xprv, buf) - FfiConverterString._write(self.fingerprint, buf) - -class BdkError(ViaFfiUsingByteBuffer): - - # Each variant is a nested class of the error itself. - # It just carries a string error message, so no special implementation is necessary. - class InvalidU32Bytes(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(1) - message = str(self) - FfiConverterString._write(message, buf) - class Generic(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(2) - message = str(self) - FfiConverterString._write(message, buf) - class ScriptDoesntHaveAddressForm(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(3) - message = str(self) - FfiConverterString._write(message, buf) - class NoRecipients(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(4) - message = str(self) - FfiConverterString._write(message, buf) - class NoUtxosSelected(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(5) - message = str(self) - FfiConverterString._write(message, buf) - class OutputBelowDustLimit(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(6) - message = str(self) - FfiConverterString._write(message, buf) - class InsufficientFunds(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(7) - message = str(self) - FfiConverterString._write(message, buf) - class BnBTotalTriesExceeded(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(8) - message = str(self) - FfiConverterString._write(message, buf) - class BnBNoExactMatch(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(9) - message = str(self) - FfiConverterString._write(message, buf) - class UnknownUtxo(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(10) - message = str(self) - FfiConverterString._write(message, buf) - class TransactionNotFound(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(11) - message = str(self) - FfiConverterString._write(message, buf) - class TransactionConfirmed(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(12) - message = str(self) - FfiConverterString._write(message, buf) - class IrreplaceableTransaction(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(13) - message = str(self) - FfiConverterString._write(message, buf) - class FeeRateTooLow(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(14) - message = str(self) - FfiConverterString._write(message, buf) - class FeeTooLow(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(15) - message = str(self) - FfiConverterString._write(message, buf) - class FeeRateUnavailable(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(16) - message = str(self) - FfiConverterString._write(message, buf) - class MissingKeyOrigin(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(17) - message = str(self) - FfiConverterString._write(message, buf) - class Key(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(18) - message = str(self) - FfiConverterString._write(message, buf) - class ChecksumMismatch(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(19) - message = str(self) - FfiConverterString._write(message, buf) - class SpendingPolicyRequired(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(20) - message = str(self) - FfiConverterString._write(message, buf) - class InvalidPolicyPathError(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(21) - message = str(self) - FfiConverterString._write(message, buf) - class Signer(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(22) - message = str(self) - FfiConverterString._write(message, buf) - class InvalidNetwork(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(23) - message = str(self) - FfiConverterString._write(message, buf) - class InvalidProgressValue(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(24) - message = str(self) - FfiConverterString._write(message, buf) - class ProgressUpdateError(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(25) - message = str(self) - FfiConverterString._write(message, buf) - class InvalidOutpoint(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(26) - message = str(self) - FfiConverterString._write(message, buf) - class Descriptor(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(27) - message = str(self) - FfiConverterString._write(message, buf) - class AddressValidator(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(28) - message = str(self) - FfiConverterString._write(message, buf) - class Encode(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(29) - message = str(self) - FfiConverterString._write(message, buf) - class Miniscript(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(30) - message = str(self) - FfiConverterString._write(message, buf) - class Bip32(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(31) - message = str(self) - FfiConverterString._write(message, buf) - class Secp256k1(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(32) - message = str(self) - FfiConverterString._write(message, buf) - class Json(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(33) - message = str(self) - FfiConverterString._write(message, buf) - class Hex(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(34) - message = str(self) - FfiConverterString._write(message, buf) - class Psbt(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(35) - message = str(self) - FfiConverterString._write(message, buf) - class PsbtParse(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(36) - message = str(self) - FfiConverterString._write(message, buf) - class Electrum(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(37) - message = str(self) - FfiConverterString._write(message, buf) - class Esplora(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(38) - message = str(self) - FfiConverterString._write(message, buf) - class Sled(ViaFfiUsingByteBuffer, Exception): - def _write(self, buf): - buf.writeI32(39) - message = str(self) - FfiConverterString._write(message, buf) - - @classmethod - def _read(cls, buf): - variant = buf.readI32() - if variant == 1: - return cls.InvalidU32Bytes(FfiConverterString._read(buf)) - if variant == 2: - return cls.Generic(FfiConverterString._read(buf)) - if variant == 3: - return cls.ScriptDoesntHaveAddressForm(FfiConverterString._read(buf)) - if variant == 4: - return cls.NoRecipients(FfiConverterString._read(buf)) - if variant == 5: - return cls.NoUtxosSelected(FfiConverterString._read(buf)) - if variant == 6: - return cls.OutputBelowDustLimit(FfiConverterString._read(buf)) - if variant == 7: - return cls.InsufficientFunds(FfiConverterString._read(buf)) - if variant == 8: - return cls.BnBTotalTriesExceeded(FfiConverterString._read(buf)) - if variant == 9: - return cls.BnBNoExactMatch(FfiConverterString._read(buf)) - if variant == 10: - return cls.UnknownUtxo(FfiConverterString._read(buf)) - if variant == 11: - return cls.TransactionNotFound(FfiConverterString._read(buf)) - if variant == 12: - return cls.TransactionConfirmed(FfiConverterString._read(buf)) - if variant == 13: - return cls.IrreplaceableTransaction(FfiConverterString._read(buf)) - if variant == 14: - return cls.FeeRateTooLow(FfiConverterString._read(buf)) - if variant == 15: - return cls.FeeTooLow(FfiConverterString._read(buf)) - if variant == 16: - return cls.FeeRateUnavailable(FfiConverterString._read(buf)) - if variant == 17: - return cls.MissingKeyOrigin(FfiConverterString._read(buf)) - if variant == 18: - return cls.Key(FfiConverterString._read(buf)) - if variant == 19: - return cls.ChecksumMismatch(FfiConverterString._read(buf)) - if variant == 20: - return cls.SpendingPolicyRequired(FfiConverterString._read(buf)) - if variant == 21: - return cls.InvalidPolicyPathError(FfiConverterString._read(buf)) - if variant == 22: - return cls.Signer(FfiConverterString._read(buf)) - if variant == 23: - return cls.InvalidNetwork(FfiConverterString._read(buf)) - if variant == 24: - return cls.InvalidProgressValue(FfiConverterString._read(buf)) - if variant == 25: - return cls.ProgressUpdateError(FfiConverterString._read(buf)) - if variant == 26: - return cls.InvalidOutpoint(FfiConverterString._read(buf)) - if variant == 27: - return cls.Descriptor(FfiConverterString._read(buf)) - if variant == 28: - return cls.AddressValidator(FfiConverterString._read(buf)) - if variant == 29: - return cls.Encode(FfiConverterString._read(buf)) - if variant == 30: - return cls.Miniscript(FfiConverterString._read(buf)) - if variant == 31: - return cls.Bip32(FfiConverterString._read(buf)) - if variant == 32: - return cls.Secp256k1(FfiConverterString._read(buf)) - if variant == 33: - return cls.Json(FfiConverterString._read(buf)) - if variant == 34: - return cls.Hex(FfiConverterString._read(buf)) - if variant == 35: - return cls.Psbt(FfiConverterString._read(buf)) - if variant == 36: - return cls.PsbtParse(FfiConverterString._read(buf)) - if variant == 37: - return cls.Electrum(FfiConverterString._read(buf)) - if variant == 38: - return cls.Esplora(FfiConverterString._read(buf)) - if variant == 39: - return cls.Sled(FfiConverterString._read(buf)) - - raise InternalError("Raw enum value doesn't match any cases") - - -# Declaration and FfiConverters for BdkProgress Callback Interface - -class BdkProgress: - def update(progress,message): - raise NotImplementedError - - - -def py_foreignCallbackCallbackInterfaceBdkProgress(handle, method, args, buf_ptr): - - def invoke_update(python_callback, args): - rval = None - with args.consumeWithStream() as buf: - rval = python_callback.update( - FfiConverterFloat._read(buf), - FfiConverterOptionalString._read(buf) - ) - return RustBuffer.alloc(0) - # TODO catch errors and report them back to Rust. - # https://github.com/mozilla/uniffi-rs/issues/351 - - - cb = FfiConverterCallbackInterfaceBdkProgress._lift(handle) - if not cb: - raise InternalError("No callback in handlemap; this is a Uniffi bug") - - if method == IDX_CALLBACK_FREE: - FfiConverterCallbackInterfaceBdkProgress.drop(handle) - # No return value. - # See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` - return 0 - - if method == 1: - buf_ptr[0] = invoke_update(cb, args) - # Value written to out buffer. - # See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` - return 1 - - - # This should never happen, because an out of bounds method index won't - # ever be used. Once we can catch errors, we should return an InternalException. - # https://github.com/mozilla/uniffi-rs/issues/351 - - # An unexpected error happened. - # See docs of ForeignCallback in `uniffi/src/ffi/foreigncallbacks.rs` - return -1 - -# We need to keep this function reference alive: -# if they get GC'd while in use then UniFFI internals could attempt to call a function -# that is in freed memory. -# That would be...uh...bad. Yeah, that's the word. Bad. -foreignCallbackCallbackInterfaceBdkProgress = FOREIGN_CALLBACK_T(py_foreignCallbackCallbackInterfaceBdkProgress) - -# The FfiConverter which transforms the Callbacks in to Handles to pass to Rust. -rust_call(lambda err: _UniFFILib.ffi_bdk_b9b3_BdkProgress_init_callback(foreignCallbackCallbackInterfaceBdkProgress, err)) -FfiConverterCallbackInterfaceBdkProgress = FfiConverterCallbackInterface(foreignCallbackCallbackInterfaceBdkProgress) -class FfiConverterUInt8(Primitive): - @staticmethod - def _read(buf): - return FfiConverterUInt8._lift(buf.readU8()) - - @staticmethod - def _write(value, buf): - buf.writeU8(FfiConverterUInt8._lower(value)) -class FfiConverterUInt32(Primitive): - @staticmethod - def _read(buf): - return FfiConverterUInt32._lift(buf.readU32()) - - @staticmethod - def _write(value, buf): - buf.writeU32(FfiConverterUInt32._lower(value)) -class FfiConverterUInt64(Primitive): - @staticmethod - def _read(buf): - return FfiConverterUInt64._lift(buf.readU64()) - - @staticmethod - def _write(value, buf): - buf.writeU64(FfiConverterUInt64._lower(value)) -class FfiConverterFloat(Primitive): - @staticmethod - def _read(buf): - return FfiConverterFloat._lift(buf.readFloat()) - - @staticmethod - def _write(value, buf): - buf.writeFloat(FfiConverterFloat._lower(value)) -class FfiConverterString: - @staticmethod - def _read(buf): - size = buf.readI32() - if size < 0: - raise InternalError("Unexpected negative string length") - utf8Bytes = buf.read(size) - return utf8Bytes.decode("utf-8") - - @staticmethod - def _write(value, buf): - utf8Bytes = value.encode("utf-8") - buf.writeI32(len(utf8Bytes)) - buf.write(utf8Bytes) - - @staticmethod - def _lift(buf): - with buf.consumeWithStream() as stream: - return stream.read(stream.remaining()).decode("utf-8") - - @staticmethod - def _lower(value): - with RustBuffer.allocWithBuilder() as builder: - builder.write(value.encode("utf-8")) - return builder.finalize() -# Helper code for OfflineWallet class is found in ObjectTemplate.py -# Helper code for OnlineWallet class is found in ObjectTemplate.py -# Helper code for PartiallySignedBitcoinTransaction class is found in ObjectTemplate.py -# Helper code for Confirmation record is found in RecordTemplate.py -# Helper code for ElectrumConfig record is found in RecordTemplate.py -# Helper code for EsploraConfig record is found in RecordTemplate.py -# Helper code for ExtendedKeyInfo record is found in RecordTemplate.py -# Helper code for SledDbConfiguration record is found in RecordTemplate.py -# Helper code for TransactionDetails record is found in RecordTemplate.py -# Helper code for BlockchainConfig enum is found in EnumTemplate.py -# Helper code for DatabaseConfig enum is found in EnumTemplate.py -# Helper code for MnemonicType enum is found in EnumTemplate.py -# Helper code for Network enum is found in EnumTemplate.py -# Helper code for Transaction enum is found in EnumTemplate.py -# Helper code for BdkError error is found in ErrorTemplate.py - - -class FfiConverterOptionalUInt8(FfiConverterUsingByteBuffer): - @staticmethod - def _write(value, buf): - FfiConverterOptional._write(value, buf, lambda v, buf: FfiConverterUInt8._write(v, buf)) - - @staticmethod - def _read(buf): - return FfiConverterOptional._read(buf, lambda buf: FfiConverterUInt8._read(buf)) - - -class FfiConverterOptionalUInt32(FfiConverterUsingByteBuffer): - @staticmethod - def _write(value, buf): - FfiConverterOptional._write(value, buf, lambda v, buf: FfiConverterUInt32._write(v, buf)) - - @staticmethod - def _read(buf): - return FfiConverterOptional._read(buf, lambda buf: FfiConverterUInt32._read(buf)) - - -class FfiConverterOptionalUInt64(FfiConverterUsingByteBuffer): - @staticmethod - def _write(value, buf): - FfiConverterOptional._write(value, buf, lambda v, buf: FfiConverterUInt64._write(v, buf)) - - @staticmethod - def _read(buf): - return FfiConverterOptional._read(buf, lambda buf: FfiConverterUInt64._read(buf)) - - -class FfiConverterOptionalFloat(FfiConverterUsingByteBuffer): - @staticmethod - def _write(value, buf): - FfiConverterOptional._write(value, buf, lambda v, buf: FfiConverterFloat._write(v, buf)) - - @staticmethod - def _read(buf): - return FfiConverterOptional._read(buf, lambda buf: FfiConverterFloat._read(buf)) - - -class FfiConverterOptionalString(FfiConverterUsingByteBuffer): - @staticmethod - def _write(value, buf): - FfiConverterOptional._write(value, buf, lambda v, buf: FfiConverterString._write(v, buf)) - - @staticmethod - def _read(buf): - return FfiConverterOptional._read(buf, lambda buf: FfiConverterString._read(buf)) - - -class FfiConverterSequenceEnumTransaction(FfiConverterUsingByteBuffer): - @staticmethod - def _write(value, buf): - FfiConverterSequence._write(value, buf, lambda v, buf: v._write(buf)) - - @staticmethod - def _read(buf): - return FfiConverterSequence._read(buf, lambda buf: Transaction._read(buf)) - -__all__ = [ - "InternalError", - "Network", - "DatabaseConfig", - "Transaction", - "BlockchainConfig", - "MnemonicType", - "SledDbConfiguration", - "TransactionDetails", - "Confirmation", - "ElectrumConfig", - "EsploraConfig", - "ExtendedKeyInfo", - "generate_extended_key", - "restore_extended_key", - "OfflineWallet", - "OnlineWallet", - "PartiallySignedBitcoinTransaction", - "BdkError", - "BdkProgress", -] - From acb8380b619397efa7a05e6877062ddf1b1d470e Mon Sep 17 00:00:00 2001 From: Alekos Filini Date: Tue, 15 Feb 2022 16:47:49 +0100 Subject: [PATCH 02/41] Build wheels in GitHub Actions --- .github/workflows/build.yml | 107 ++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..d50e342 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,107 @@ +on: [push, pull_request] +name: Build wheels + +# We use manylinux2014 because older CentOS versions used by 2010 and 1 have a very old glibc version, which +# makes it very hard to use GitHub's javascript actions (checkout, upload-artifact, etc). +# They mount their own nodejs interpreter inside your container, but since that's not statically linked it +# tries to load glibc and fails because it requires a more recent version. + +jobs: + build-manylinux2014-x86_64-wheel: + name: 'Build Manylinux 2014 x86_64 wheel' + runs-on: ubuntu-latest + container: + image: quay.io/pypa/manylinux2014_x86_64 + env: + PLAT: manylinux2014_x86_64 + PYBIN: '/opt/python/${{ matrix.python }}/bin' + strategy: + matrix: + python: # Update this list whenever the docker image is updated (check /opt/python/) + - cp36-cp36m + - cp37-cp37m + - cp38-cp38 + - cp39-cp39 + - cp310-cp310 + - pp37-pypy37_pp73 + - pp38-pypy38_pp73 + steps: + - name: checkout + uses: actions/checkout@v2 + with: + submodules: true + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - name: install requirements + run: ${PYBIN}/pip install -r requirements.txt + - name: generate bindings + run: bash generate.sh + - name: build wheel + run: ${PYBIN}/pip wheel . --no-deps -w /tmp/wheelhouse + - name: repair wheel + run: auditwheel repair /tmp/wheelhouse/* --plat "$PLAT" -w /tmp/wheelhouse-repaired + - uses: actions/upload-artifact@v2 + with: + name: bdkpython-manylinux2014-x86_64-${{ matrix.python }} + path: /tmp/wheelhouse-repaired/*.whl + build-macos-universal-wheel: + name: 'Build macOS universal wheel' + runs-on: macos-latest + strategy: + matrix: + python: + - '3.7' + - '3.8' + - '3.9' + - '3.10' + steps: + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + - run: python3 --version + - name: checkout + uses: actions/checkout@v2 + with: + submodules: true + - run: rustup target add aarch64-apple-darwin + - run: pip3 install --user -r requirements.txt + - run: pip3 install --user wheel + - run: bash generate.sh + - name: build wheel + env: + ARCHFLAGS: "-arch x86_64 -arch arm64" + run: python3 setup.py -v bdist_wheel + - uses: actions/upload-artifact@v2 + with: + name: bdkpython-macos-${{ matrix.python }} + path: dist/*.whl + build-windows-wheel: + name: 'Build windows wheel' + runs-on: windows-latest + strategy: + matrix: + python: + - '3.7' + - '3.8' + - '3.9' + - '3.10' + steps: + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + - run: python --version + - name: checkout + uses: actions/checkout@v2 + with: + submodules: true + - run: pip install --user -r requirements.txt + - run: ./generate.sh + shell: bash + - run: pip install --user wheel + - name: build wheel + run: python setup.py -v bdist_wheel + - uses: actions/upload-artifact@v2 + with: + name: bdkpython-win-${{ matrix.python }} + path: dist/*.whl From be87629aba0a8f0cd95207cf1d240108afccb9f0 Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Wed, 16 Feb 2022 21:29:43 -0500 Subject: [PATCH 03/41] Fix 'build the wheel' section of readme --- README.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 55df900..9f28457 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,7 @@ # bdk-python The Python language bindings for the [bitcoindevkit](https://github.com/bitcoindevkit). -See the [package on PyPI](https://pypi.org/project/bdkpython/). - -Currently supported architectures: -- macOS `arm64` -- macOS `x86_64` -- linux `x86_64` - +See the [package on PyPI](https://pypi.org/project/bdkpython/).
## Install from PyPI @@ -27,10 +21,12 @@ python -m tox ```shell # Install dependecies pip install -r requirements.txt + # Generate the bindings first bash generate.sh + # Build the wheel -python -m build +python3 setup.py -v bdist_wheel ```
@@ -38,4 +34,3 @@ python -m build ```shell pip install ./dist/bdkpython-0.0.1-py3-none-any.whl ``` -
From a6943af68654eb8f507cca59b12be0e6515752ee Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Wed, 16 Feb 2022 21:30:36 -0500 Subject: [PATCH 04/41] Add build directory to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b763419..e2dc9d5 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ libbdkffi.dylib src/bdkpython/bdk.py *.whl +build/ From 7982a73aa71dad7866e28fd04a6dea6148027731 Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Wed, 16 Feb 2022 21:31:39 -0500 Subject: [PATCH 05/41] Fix long description examples after API change --- setup.py | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/setup.py b/setup.py index 55de5d7..3e36a59 100644 --- a/setup.py +++ b/setup.py @@ -13,25 +13,11 @@ pip install bdkpython ``` -## Simple examples -**Generate a testnet address** +## Simple example ```python import bdkpython as bdk -descriptor = "wpkh(tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/84h/1h/0h/0/*)" -config = bdk.DatabaseConfig.MEMORY("") - -wallet = bdk.OfflineWallet(descriptor, bdk.Network.TESTNET, config) -address = wallet.get_new_address() - -print(f"New BIP84 testnet address: {address}") -``` - -**Sync a wallet using Electrum** -```python -import bdkpython as bdk - descriptor = "wpkh(tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/84h/1h/0h/0/*)" config = bdk.DatabaseConfig.MEMORY("") client = bdk.BlockchainConfig.ELECTRUM( @@ -44,7 +30,7 @@ ) ) -wallet = bdk.OnlineWallet( +wallet = bdk.Wallet( descriptor=descriptor, change_descriptor=descriptor, network=bdk.Network.TESTNET, @@ -52,15 +38,19 @@ blockchain_config=client ) +# print new receive address +address = wallet.get_new_address() +print(f"New BIP84 testnet address: {address}") + + +# print wallet balance class LogProgress(bdk.BdkProgress): def update(self, progress, update): pass - + wallet.sync(progress_update=LogProgress(), max_address_param=20) balance = wallet.get_balance() - print(f"Wallet balance is: {balance}") -``` """ rust_ext = RustExtension( @@ -71,7 +61,7 @@ def update(self, progress, update): setup( name = 'bdkpython', - version = '0.0.4', + version = '0.1.0', description="The Python language bindings for the bitcoindevkit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', From 472edb6e8ca93bce0a08d7adab4e9faec6669971 Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Tue, 22 Feb 2022 14:03:08 -0500 Subject: [PATCH 06/41] Add publish job to GitHub workflow --- .github/workflows/build.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d50e342..2aa6603 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,6 +45,7 @@ jobs: with: name: bdkpython-manylinux2014-x86_64-${{ matrix.python }} path: /tmp/wheelhouse-repaired/*.whl + build-macos-universal-wheel: name: 'Build macOS universal wheel' runs-on: macos-latest @@ -76,6 +77,7 @@ jobs: with: name: bdkpython-macos-${{ matrix.python }} path: dist/*.whl + build-windows-wheel: name: 'Build windows wheel' runs-on: windows-latest @@ -105,3 +107,14 @@ jobs: with: name: bdkpython-win-${{ matrix.python }} path: dist/*.whl + + publish-pypi: + needs: [build-manylinux2014-x86_64-wheel, build-macos-universal-wheel, build-windows-wheel] + - name: 'Publish on PyPI' + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.TEST_PYPI_API_TOKEN }} + repository_url: https://test.pypi.org/legacy/ + From 4de866de209f6c863b3782ccc0957b9d3e5e7f78 Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Tue, 22 Feb 2022 14:04:02 -0500 Subject: [PATCH 07/41] Bump package version to 0.0.5 --- .github/workflows/build.yml | 34 ++++++++++++++++++++++++++++------ setup.py | 2 +- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2aa6603..24c75c7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,5 @@ on: [push, pull_request] -name: Build wheels +name: Build and publish wheels # We use manylinux2014 because older CentOS versions used by 2010 and 1 have a very old glibc version, which # makes it very hard to use GitHub's javascript actions (checkout, upload-artifact, etc). @@ -109,12 +109,34 @@ jobs: path: dist/*.whl publish-pypi: + name: 'Publish on PyPI' + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + runs-on: ubuntu-latest needs: [build-manylinux2014-x86_64-wheel, build-macos-universal-wheel, build-windows-wheel] - - name: 'Publish on PyPI' - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + # needs: [build-macos-universal-wheel] + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: 'Download artifacts in dist/ directory' + uses: actions/download-artifact@v2 + with: + path: dist/ + + # - name: Display structure of downloaded files + # run: ls -R + + # - name: 'Publish on test PyPI' + # uses: pypa/gh-action-pypi-publish@release/v1 + # with: + # user: __token__ + # password: ${{ secrets.TEST_PYPI_API_TOKEN }} + # repository_url: https://test.pypi.org/legacy/ + # packages_dir: dist/*/ + + - name: 'Publish on PyPI' uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ - password: ${{ secrets.TEST_PYPI_API_TOKEN }} - repository_url: https://test.pypi.org/legacy/ - + password: ${{ secrets.PYPI_API_TOKEN }} + packages_dir: dist/*/ \ No newline at end of file diff --git a/setup.py b/setup.py index 3e36a59..4c49a3a 100644 --- a/setup.py +++ b/setup.py @@ -61,7 +61,7 @@ def update(self, progress, update): setup( name = 'bdkpython', - version = '0.1.0', + version = '0.0.5', description="The Python language bindings for the bitcoindevkit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', From 453dc6e7ea71c229873e2e348460d5125d8eaa37 Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Tue, 1 Mar 2022 10:37:18 -0500 Subject: [PATCH 08/41] Bump bdk-ffi submodule to v0.3.0 --- bdk-ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bdk-ffi b/bdk-ffi index 68f266a..d17ea4b 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit 68f266a17b29a84e8c63ed90126c5c152d2f51aa +Subproject commit d17ea4b90c015c9a6cf5d2cf2f77e901d93fd089 From e851f42aee5dd91e951cb5bd428299a80e04ae3d Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Thu, 3 Mar 2022 15:55:22 -0500 Subject: [PATCH 09/41] Bump version to v0.0.6-SNAPSHOT --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4c49a3a..fbce3e1 100644 --- a/setup.py +++ b/setup.py @@ -61,7 +61,7 @@ def update(self, progress, update): setup( name = 'bdkpython', - version = '0.0.5', + version = '0.0.6-SNAPSHOT', description="The Python language bindings for the bitcoindevkit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', From d41f787efd7a1dc72a597df129c8b8bc7ca3cc99 Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Thu, 3 Mar 2022 16:06:34 -0500 Subject: [PATCH 10/41] Add pull request template --- .github/pull_request_template.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..c44596a --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,24 @@ + + +## Description + + +## Notes to the reviewers + + +## Checklists + +## All Submissions: +* [ ] I've signed all my commits +* [ ] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) + +#### New Features: +* [ ] I've added tests for the new feature +* [ ] I've added docs for the new feature +* [ ] I've updated `CHANGELOG.md` + +#### Bugfixes: +* [ ] This pull request breaks the existing API +* [ ] I've added tests to reproduce the issue which are now passing +* [ ] I'm linking the issue being fixed by this PR From e42e2c15e2d58eda3a3571366d7fc009f9e7fabb Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Thu, 3 Mar 2022 16:24:46 -0500 Subject: [PATCH 11/41] Add bug report template --- .github/ISSUE_TEMPLATE/bug_report.md | 38 ++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..3d2de18 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: 🐞 Bug +about: File a bug/issue +title: '[BUG:] ' +labels: bug +--- + +<!-- +Note: Please search to see if an issue already exists for the bug you encountered. +--> + +### Current Behavior: +<!-- A concise description of what you're experiencing. --> + +### Expected Behavior: +<!-- A concise description of what you expected to happen. --> + +### Steps To Reproduce: +<!-- +Example: steps to reproduce the behavior: +1. In this environment... +2. With this config... +3. Run '...' +4. See error... +--> + +### Environment: +<!-- +Example: +- OS: Ubuntu 20.04 +- Node: 13.14.0 +- npm: 7.6.3 +--> + +### Anything else: +<!-- +Links? References? Anything that will give us more context about the issue that you are encountering! +--> From 680d3ccc865a65dafa7736867363e8df25bd9c4d Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Thu, 3 Mar 2022 16:28:45 -0500 Subject: [PATCH 12/41] Add feature request template --- .github/ISSUE_TEMPLATE/feature_request.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..6fd56fd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,23 @@ +--- +name: 🚀 Feature Request +about: Request a feature +title: '[Feature Request:] <title>' +labels: enhancement +--- + +### Is your proposal related to a problem? +<!-- + Provide a clear and concise description of what the problem is. + For example, "I'm always frustrated when..." +--> + +### Describe the solution you'd like +<!-- + Provide a clear and concise description of what you want to happen. +--> + +### Additional context +<!-- + Is there anything else you can add about the proposal? + You might want to link to related issues here, if you haven't already. +--> From 6f848254bc99a1a168aa33750f3078e111a8870e Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Thu, 3 Mar 2022 16:40:51 -0500 Subject: [PATCH 13/41] Add Apache 2.0 and MIT licenses --- LICENSE | 14 ++++ LICENSE-APACHE | 201 +++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE-MIT | 17 +++++ 3 files changed, 232 insertions(+) create mode 100644 LICENSE create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c3f44ca --- /dev/null +++ b/LICENSE @@ -0,0 +1,14 @@ +This software is licensed under [Apache 2.0](LICENSE-APACHE) or +[MIT](LICENSE-MIT), at your option. + +Some files retain their own copyright notice, however, for full authorship +information, see version control history. + +Except as otherwise noted in individual files, all files in this repository are +licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or +http://opensource.org/licenses/MIT>, at your option. + +You may not use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of this software or any files in this repository except in +accordance with one or both of these licenses. diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..0e0676a --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,17 @@ + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 8b50e8d3ad578002b16ee08917877d4691d5e593 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Fri, 4 Mar 2022 08:53:11 -0500 Subject: [PATCH 14/41] Fix version numbering to comply with PEP 440 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fbce3e1..f55fe88 100644 --- a/setup.py +++ b/setup.py @@ -61,7 +61,7 @@ def update(self, progress, update): setup( name = 'bdkpython', - version = '0.0.6-SNAPSHOT', + version = '0.0.6.dev', description="The Python language bindings for the bitcoindevkit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', From 7c9a624eab16214ecc035fe95c9e1a40eb8952da Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Fri, 4 Mar 2022 09:07:27 -0500 Subject: [PATCH 15/41] Add changelog --- CHANGELOG.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..804ab4c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,24 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog], and this project adheres to [Semantic Versioning]. + +## [Unreleased] +### Added +- Community related files (bug report, feature request, and pull request templates) +- Changelog +- MIT and Apache 2.0 licenses + +## [0.0.1-0.0.5] +### Added +- Readme +- Rust binary to build +- CI workflow for tessting PRs +- Publishing workflow using GitHub Actions +- Basic examples +- Release on PyPI + +[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ +[Semantic Versioning]: https://semver.org/spec/v2.0.0.html +[unreleased]: https://github.com/bitcoindevkit/bdk-python/compare/v0.0.5...HEAD +[0.0.1-0.0.5]: https://github.com/bitcoindevkit/bdk-python/compare/58f189f987cc644a1d86e965623c8f50904588ad...v0.0.5 From 45216c7563cfeb36120f7c93ff8c5a6fe00b62de Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Fri, 6 May 2022 15:24:41 -0400 Subject: [PATCH 16/41] Update library to new bdk-ffi API version to 0.6.0 --- README.md | 4 ++-- generate.sh | 3 ++- setup.py | 8 ++++---- tests/test_bdk.py | 15 ++++++++++++--- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 9f28457..8ee3b0a 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,13 @@ python -m tox ## Build the package ```shell # Install dependecies -pip install -r requirements.txt +pip install --requirement requirements.txt # Generate the bindings first bash generate.sh # Build the wheel -python3 setup.py -v bdist_wheel +python3 setup.py --verbose bdist_wheel ``` <br/> diff --git a/generate.sh b/generate.sh index 653935d..d222d2d 100644 --- a/generate.sh +++ b/generate.sh @@ -6,4 +6,5 @@ SCRIPT_DIR=$(dirname "$(realpath $0)") PY_SRC="${SCRIPT_DIR}/src/bdkpython/" echo "Generating bdk.py..." -GENERATE_PYTHON_BINDINGS_OUT="$PY_SRC" GENERATE_PYTHON_BINDINGS_FIXUP_LIB_PATH=bdkffi cargo run --manifest-path ./bdk-ffi/Cargo.toml --release --bin generate --features generate-python +# GENERATE_PYTHON_BINDINGS_OUT="$PY_SRC" GENERATE_PYTHON_BINDINGS_FIXUP_LIB_PATH=bdkffi cargo run --manifest-path ./bdk-ffi/Cargo.toml --release --bin generate --features generate-python +BDKFFI_BINDGEN_PYTHON_FIXUP_PATH=bdkffi cargo run --manifest-path ./bdk-ffi/Cargo.toml --package bdk-ffi-bindgen -- --language python --udl-file ./bdk-ffi/src/bdk.udl --out-dir ./src/bdkpython/ diff --git a/setup.py b/setup.py index 4c49a3a..8041f9c 100644 --- a/setup.py +++ b/setup.py @@ -60,16 +60,16 @@ def update(self, progress, update): ) setup( - name = 'bdkpython', - version = '0.0.5', + name='bdkpython', + version='0.0.6.dev0', description="The Python language bindings for the bitcoindevkit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', rust_extensions=[rust_ext], zip_safe=False, packages=['bdkpython'], - package_dir={ 'bdkpython': './src/bdkpython' }, - url="https://github.com/thunderbiscuit/bdk-python", + package_dir={'bdkpython': './src/bdkpython'}, + url="https://github.com/bitcoindevkit/bdk-python", author="Alekos Filini <alekos.filini@gmail.com>, Steve Myers <steve@notmandatory.org>", license="MIT or Apache 2.0", ) diff --git a/tests/test_bdk.py b/tests/test_bdk.py index 85a6542..68d9a1f 100644 --- a/tests/test_bdk.py +++ b/tests/test_bdk.py @@ -3,7 +3,7 @@ # taken from bdk test suite @ https://github.com/bitcoindevkit/bdk/blob/master/src/descriptor/template.rs#L676 descriptor = "wpkh(tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/84h/0h/0h/0/*)" -config = bdk.DatabaseConfig.MEMORY("") +db_config = bdk.DatabaseConfig.MEMORY() client = bdk.BlockchainConfig.ELECTRUM( bdk.ElectrumConfig( "ssl://electrum.blockstream.info:60002", @@ -15,11 +15,20 @@ ) -def test_address_BIP84_testnet(): - wallet = bdk.OfflineWallet(descriptor, bdk.Network.TESTNET, config) +def test_address_bip84_testnet(): + wallet = bdk.Wallet( + descriptor=descriptor, + change_descriptor=None, + network=bdk.Network.TESTNET, + database_config=db_config + ) address = wallet.get_new_address() + print(f"New address is {address}") assert address == "tb1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvvztyse" + +test_address_bip84_testnet() + # def test_wallet_balance(): # wallet = bdk.OnlineWallet( # descriptor=descriptor, From d23dfb831b97d482235b1cec800620ed679d3556 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Wed, 11 May 2022 15:18:37 -0400 Subject: [PATCH 17/41] Update bdk-ffi submodule to version to 0.6.0 --- bdk-ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bdk-ffi b/bdk-ffi index d17ea4b..30e54ac 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit d17ea4b90c015c9a6cf5d2cf2f77e901d93fd089 +Subproject commit 30e54ac067f68e8c22d652837b4d5901c12e3384 From cc730b00b2746c1a6fe7051612423eb87b1c7f1a Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Wed, 11 May 2022 15:19:33 -0400 Subject: [PATCH 18/41] Fix test workflow in readme --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8ee3b0a..12baad9 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,11 @@ pip install bdkpython ## Run the tests ```shell -python -m tox +pip3 install --requirement requirements.txt +bash ./generate.sh +python3 setup.py --verbose bdist_wheel +pip3 install ./dist/bdkpython-<yourversion>-py3-none-any.whl +python3 ./tests/test_bdk.py ``` <br/> @@ -32,5 +36,5 @@ python3 setup.py --verbose bdist_wheel ## Install locally ```shell -pip install ./dist/bdkpython-0.0.1-py3-none-any.whl +pip install ./dist/bdkpython-<yourversion>-py3-none-any.whl ``` From 3ae2f48846b5637c73e0597443d58934432dc3ad Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Wed, 11 May 2022 16:02:49 -0400 Subject: [PATCH 19/41] Upgrade library to bdk-ffi 0.6.0 --- README.md | 2 +- generate.sh | 3 ++- setup.py | 36 ++++++++++++-------------- tests/test_bdk.py | 66 +++++++++++++++++++++++++---------------------- 4 files changed, 54 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 12baad9..0e258a1 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ pip3 install --requirement requirements.txt bash ./generate.sh python3 setup.py --verbose bdist_wheel pip3 install ./dist/bdkpython-<yourversion>-py3-none-any.whl -python3 ./tests/test_bdk.py +python -m unittest --verbose tests/test_bdk.py ``` <br/> diff --git a/generate.sh b/generate.sh index d222d2d..fe1bd45 100644 --- a/generate.sh +++ b/generate.sh @@ -7,4 +7,5 @@ PY_SRC="${SCRIPT_DIR}/src/bdkpython/" echo "Generating bdk.py..." # GENERATE_PYTHON_BINDINGS_OUT="$PY_SRC" GENERATE_PYTHON_BINDINGS_FIXUP_LIB_PATH=bdkffi cargo run --manifest-path ./bdk-ffi/Cargo.toml --release --bin generate --features generate-python -BDKFFI_BINDGEN_PYTHON_FIXUP_PATH=bdkffi cargo run --manifest-path ./bdk-ffi/Cargo.toml --package bdk-ffi-bindgen -- --language python --udl-file ./bdk-ffi/src/bdk.udl --out-dir ./src/bdkpython/ +# BDKFFI_BINDGEN_PYTHON_FIXUP_PATH=bdkffi cargo run --manifest-path ./bdk-ffi/Cargo.toml --package bdk-ffi-bindgen -- --language python --udl-file ./bdk-ffi/src/bdk.udl --out-dir ./src/bdkpython/ +BDKFFI_BINDGEN_OUTPUT_DIR="$PY_SRC" BDKFFI_BINDGEN_PYTHON_FIXUP_PATH=bdkffi cargo run --manifest-path ./bdk-ffi/Cargo.toml --package bdk-ffi-bindgen -- --language python --udl-file ./bdk-ffi/src/bdk.udl diff --git a/setup.py b/setup.py index 2619c8e..b2a68b1 100644 --- a/setup.py +++ b/setup.py @@ -18,24 +18,24 @@ import bdkpython as bdk -descriptor = "wpkh(tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/84h/1h/0h/0/*)" -config = bdk.DatabaseConfig.MEMORY("") -client = bdk.BlockchainConfig.ELECTRUM( - bdk.ElectrumConfig( - "ssl://electrum.blockstream.info:60002", - None, - 5, - None, - 100 - ) - ) +descriptor = "wpkh(tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/84h/0h/0h/0/*)" +db_config = bdk.DatabaseConfig.MEMORY() +blockchain_config = bdk.BlockchainConfig.ELECTRUM( + bdk.ElectrumConfig( + "ssl://electrum.blockstream.info:60002", + None, + 5, + None, + 100 + ) +) +blockchain = bdk.Blockchain(blockchain_config) wallet = bdk.Wallet( descriptor=descriptor, - change_descriptor=descriptor, + change_descriptor=None, network=bdk.Network.TESTNET, - database_config=config, - blockchain_config=client + database_config=db_config, ) # print new receive address @@ -44,11 +44,7 @@ # print wallet balance -class LogProgress(bdk.BdkProgress): - def update(self, progress, update): - pass - -wallet.sync(progress_update=LogProgress(), max_address_param=20) +wallet.sync(blockchain, None) balance = wallet.get_balance() print(f"Wallet balance is: {balance}") """ @@ -61,7 +57,7 @@ def update(self, progress, update): setup( name='bdkpython', - version = '0.0.6.dev', + version = '0.1.0.dev', description="The Python language bindings for the bitcoindevkit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', diff --git a/tests/test_bdk.py b/tests/test_bdk.py index 68d9a1f..6259c97 100644 --- a/tests/test_bdk.py +++ b/tests/test_bdk.py @@ -1,42 +1,46 @@ import bdkpython as bdk - +import unittest # taken from bdk test suite @ https://github.com/bitcoindevkit/bdk/blob/master/src/descriptor/template.rs#L676 descriptor = "wpkh(tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/84h/0h/0h/0/*)" db_config = bdk.DatabaseConfig.MEMORY() -client = bdk.BlockchainConfig.ELECTRUM( - bdk.ElectrumConfig( - "ssl://electrum.blockstream.info:60002", - None, - 5, - None, - 100 - ) +blockchain_config = bdk.BlockchainConfig.ELECTRUM( + bdk.ElectrumConfig( + "ssl://electrum.blockstream.info:60002", + None, + 5, + None, + 100 + ) ) +blockchain = bdk.Blockchain(blockchain_config) -def test_address_bip84_testnet(): - wallet = bdk.Wallet( - descriptor=descriptor, - change_descriptor=None, - network=bdk.Network.TESTNET, - database_config=db_config - ) - address = wallet.get_new_address() - print(f"New address is {address}") - assert address == "tb1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvvztyse" +class TestSimpleBip84Wallet(unittest.TestCase): + + def test_address_bip84_testnet(self): + wallet = bdk.Wallet( + descriptor=descriptor, + change_descriptor=None, + network=bdk.Network.TESTNET, + database_config=db_config + ) + address = wallet.get_new_address() + # print(f"New address is {address}") + assert address == "tb1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvvztyse", f"Wrong address {address}, should be tb1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvvztyse" + def test_wallet_balance(self): + wallet = bdk.Wallet( + descriptor=descriptor, + change_descriptor=None, + network=bdk.Network.TESTNET, + database_config=db_config, + ) + wallet.sync(blockchain, None) + balance = wallet.get_balance() + # print(f"Balance is {balance} sat") + assert balance > 0, "Balance is 0, send testnet coins to tb1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvvztyse" -test_address_bip84_testnet() -# def test_wallet_balance(): -# wallet = bdk.OnlineWallet( -# descriptor=descriptor, -# change_descriptor=descriptor, -# network=bdk.Network.TESTNET, -# database_config=config, -# blockchain_config=client -# ) -# wallet.sync() -# balance = wallet.get_balance() -# assert balance > 0 +if __name__ == '__main__': + unittest.main() From 29821069d804f0bcdaacf18d848b871f412221a6 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Wed, 11 May 2022 16:09:59 -0400 Subject: [PATCH 20/41] Use same wallet descriptor as for the bdk-kotlin tests --- tests/test_bdk.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/test_bdk.py b/tests/test_bdk.py index 6259c97..c43e2ac 100644 --- a/tests/test_bdk.py +++ b/tests/test_bdk.py @@ -1,8 +1,7 @@ import bdkpython as bdk import unittest -# taken from bdk test suite @ https://github.com/bitcoindevkit/bdk/blob/master/src/descriptor/template.rs#L676 -descriptor = "wpkh(tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/84h/0h/0h/0/*)" +descriptor = "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)" db_config = bdk.DatabaseConfig.MEMORY() blockchain_config = bdk.BlockchainConfig.ELECTRUM( bdk.ElectrumConfig( @@ -27,7 +26,7 @@ def test_address_bip84_testnet(self): ) address = wallet.get_new_address() # print(f"New address is {address}") - assert address == "tb1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvvztyse", f"Wrong address {address}, should be tb1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvvztyse" + assert address == "tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e", f"Wrong address {address}, should be tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e" def test_wallet_balance(self): wallet = bdk.Wallet( @@ -39,7 +38,7 @@ def test_wallet_balance(self): wallet.sync(blockchain, None) balance = wallet.get_balance() # print(f"Balance is {balance} sat") - assert balance > 0, "Balance is 0, send testnet coins to tb1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvvztyse" + assert balance > 0, "Balance is 0, send testnet coins to tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e" if __name__ == '__main__': From 03b20971739b464bf4ad855c4a02aeb644061491 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Wed, 11 May 2022 16:20:18 -0400 Subject: [PATCH 21/41] Bring changelog up to date with bdkpython 0.1.0 --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 804ab4c..0456cf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog], and this project adheres to [Semantic Versioning]. ## [Unreleased] + +## [0.0.5-0.1.0] ### Added - Community related files (bug report, feature request, and pull request templates) - Changelog - MIT and Apache 2.0 licenses +- Update BDK to version 0.18.0 +- Add BumpFeeTxBuilder to bump the fee on an unconfirmed tx created by the Wallet +- Change TxBuilder.build() to TxBuilder.finish() to align with bdk function name +- Fix Wallet.broadcast function, now returns a tx id as a hex string +- Remove creating a new spending Transaction via the PartiallySignedBitcoinTransaction constructor +- Add TxBuilder for creating new spending PartiallySignedBitcoinTransaction +- Add TxBuilder .add_recipient, .fee_rate, and .build functions +- Add TxBuilder .drain_wallet and .drain_to functions +- Update generate cli tool to generate all binding languages and rename to bdk-ffi-bindgen +- Add sqlite database support +- Fix memory database configuration enum, remove junk field +- Remove hard coded sync progress value (was always returning 21.0) ## [0.0.1-0.0.5] ### Added @@ -22,3 +36,4 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic [Semantic Versioning]: https://semver.org/spec/v2.0.0.html [unreleased]: https://github.com/bitcoindevkit/bdk-python/compare/v0.0.5...HEAD [0.0.1-0.0.5]: https://github.com/bitcoindevkit/bdk-python/compare/58f189f987cc644a1d86e965623c8f50904588ad...v0.0.5 +[0.0.5-0.1.0]: https:// \ No newline at end of file From 5db9b1bc7b2182c11c8ccbb8629ea77ee2a47ddf Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Thu, 23 Jun 2022 15:21:48 -0400 Subject: [PATCH 22/41] Bump bdk-ffi submodule to 0.7.0 tag --- .gitignore | 2 ++ CHANGELOG.md | 16 +++++++--------- README.md | 2 +- bdk-ffi | 2 +- setup.py | 12 +++++++----- tests/test_bdk.py | 3 ++- 6 files changed, 20 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index e2dc9d5..511e251 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ libbdkffi.dylib src/bdkpython/bdk.py *.whl build/ + +testing-setup-py-simple-example.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 0456cf7..dad65c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,16 +10,14 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic - Community related files (bug report, feature request, and pull request templates) - Changelog - MIT and Apache 2.0 licenses -- Update BDK to version 0.18.0 -- Add BumpFeeTxBuilder to bump the fee on an unconfirmed tx created by the Wallet -- Change TxBuilder.build() to TxBuilder.finish() to align with bdk function name -- Fix Wallet.broadcast function, now returns a tx id as a hex string -- Remove creating a new spending Transaction via the PartiallySignedBitcoinTransaction constructor -- Add TxBuilder for creating new spending PartiallySignedBitcoinTransaction -- Add TxBuilder .add_recipient, .fee_rate, and .build functions -- Add TxBuilder .drain_wallet and .drain_to functions +- Update BDK to version `0.19.0` +- Add `BumpFeeTxBuilder` to bump the fee on an unconfirmed tx created by the Wallet +- Add `Blockchain.broadcast` function (does not return anything) +- Add TxBuilder for creating new spending `PartiallySignedBitcoinTransaction` +- Add TxBuilder `add_recipient`, `fee_rate`, and `finish` functions +- Add TxBuilder `drain_wallet` and `drain_to` functions - Update generate cli tool to generate all binding languages and rename to bdk-ffi-bindgen -- Add sqlite database support +- Add sqlite database support - Fix memory database configuration enum, remove junk field - Remove hard coded sync progress value (was always returning 21.0) diff --git a/README.md b/README.md index 0e258a1..96ad34b 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ pip3 install --requirement requirements.txt bash ./generate.sh python3 setup.py --verbose bdist_wheel pip3 install ./dist/bdkpython-<yourversion>-py3-none-any.whl -python -m unittest --verbose tests/test_bdk.py +python -m unittest --verbose tests/test_bdk.py ``` <br/> diff --git a/bdk-ffi b/bdk-ffi index 30e54ac..80ed21e 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit 30e54ac067f68e8c22d652837b4d5901c12e3384 +Subproject commit 80ed21e4c9e61d6224e074258229a4d6da6cc049 diff --git a/setup.py b/setup.py index b2a68b1..fe9e568 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ from setuptools_rust import Binding, RustExtension LONG_DESCRIPTION = """# bdkpython -The Python language bindings for the [bitcoindevkit](https://github.com/bitcoindevkit). +The Python language bindings for the [Bitcoin Dev Kit](https://github.com/bitcoindevkit). ## Install the package ```shell @@ -39,8 +39,10 @@ ) # print new receive address -address = wallet.get_new_address() -print(f"New BIP84 testnet address: {address}") +address_info = wallet.get_address(bdk.AddressIndex.LAST_UNUSED) +address = address_info.address +index = address_info.index +print(f"New BIP84 testnet address: {address} at index {index}") # print wallet balance @@ -57,8 +59,8 @@ setup( name='bdkpython', - version = '0.1.0.dev', - description="The Python language bindings for the bitcoindevkit", + version='0.1.0.dev', + description="The Python language bindings for the Bitcoin Dev Kit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', rust_extensions=[rust_ext], diff --git a/tests/test_bdk.py b/tests/test_bdk.py index c43e2ac..b667b30 100644 --- a/tests/test_bdk.py +++ b/tests/test_bdk.py @@ -24,7 +24,8 @@ def test_address_bip84_testnet(self): network=bdk.Network.TESTNET, database_config=db_config ) - address = wallet.get_new_address() + address_info = wallet.get_address(bdk.AddressIndex.LAST_UNUSED) + address = address_info.address # print(f"New address is {address}") assert address == "tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e", f"Wrong address {address}, should be tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e" From 5862b13daced38a7b0e538ae305cb7cd8ebda009 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Wed, 29 Jun 2022 13:25:17 -0400 Subject: [PATCH 23/41] Fix changelog missing link --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dad65c5..a263f19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,4 +34,4 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic [Semantic Versioning]: https://semver.org/spec/v2.0.0.html [unreleased]: https://github.com/bitcoindevkit/bdk-python/compare/v0.0.5...HEAD [0.0.1-0.0.5]: https://github.com/bitcoindevkit/bdk-python/compare/58f189f987cc644a1d86e965623c8f50904588ad...v0.0.5 -[0.0.5-0.1.0]: https:// \ No newline at end of file +[0.0.5-0.1.0]: https://github.com/bitcoindevkit/bdk-python/compare/v0.0.5...v0.1.0 \ No newline at end of file From d978993d0630b35f7140e696a6b7d9f21ac4c7d6 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Wed, 29 Jun 2022 13:26:19 -0400 Subject: [PATCH 24/41] Fix version number for development --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fe9e568..0b00244 100644 --- a/setup.py +++ b/setup.py @@ -59,7 +59,7 @@ setup( name='bdkpython', - version='0.1.0.dev', + version='0.1.0.dev0', description="The Python language bindings for the Bitcoin Dev Kit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', From d50e2a6832f53f6c6056f5a417cfc3fd4a50d233 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Thu, 30 Jun 2022 15:37:58 -0400 Subject: [PATCH 25/41] Bump development version to 0.2.0.dev0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0b00244..25e6e03 100644 --- a/setup.py +++ b/setup.py @@ -59,7 +59,7 @@ setup( name='bdkpython', - version='0.1.0.dev0', + version='0.2.0.dev0', description="The Python language bindings for the Bitcoin Dev Kit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', From 4396ebaa72e716fc3d1fbb516cdc1a656f4742ae Mon Sep 17 00:00:00 2001 From: Sam Korn <korn94sam@gmail.com> Date: Fri, 1 Jul 2022 11:04:45 -0600 Subject: [PATCH 26/41] fix tox build and tests Signed-off-by: Sam Korn <korn94sam@gmail.com> --- .gitignore | 1 + CHANGELOG.md | 1 + README.md | 9 +++++++++ pyproject.toml | 7 +++++++ requirements-dev.txt | 2 ++ tox.ini | 12 +++++++++--- 6 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 pyproject.toml create mode 100644 requirements-dev.txt diff --git a/.gitignore b/.gitignore index 511e251..726b07a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ libbdkffi.dylib *.swp src/bdkpython/bdk.py +src/bdkpython/*.so *.whl build/ diff --git a/CHANGELOG.md b/CHANGELOG.md index a263f19..a0dff5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic - Add sqlite database support - Fix memory database configuration enum, remove junk field - Remove hard coded sync progress value (was always returning 21.0) +- Fix tests and tox build workflow ## [0.0.1-0.0.5] ### Added diff --git a/README.md b/README.md index 96ad34b..a482f5c 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,15 @@ python3 setup.py --verbose bdist_wheel ``` <br/> +## Run tox to build and test +```shell +# install dev requirements +pip install --requirement requirements-dev.txt + +# build and test +tox +``` + ## Install locally ```shell pip install ./dist/bdkpython-<yourversion>-py3-none-any.whl diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..2012f16 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,7 @@ +[build-system] +requires = ["setuptools", "wheel", "setuptools-rust"] + +[tool.pytest.ini_options] +pythonpath = [ + "." +] \ No newline at end of file diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..b95a8a8 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,2 @@ +pytest==7.1.2 +tox==3.25.1 diff --git a/tox.ini b/tox.ini index 95f6045..c01a149 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,16 @@ [tox] envlist = + py38 py39 + [testenv] -deps = - pytest - bdk +usedevelop=true +deps = + -rrequirements.txt + -rrequirements-dev.txt commands = + python3 setup.py -v build + python3 setup.py -v install pytest --verbose --override-ini console_output_style=count + python3 setup.py --verbose bdist_wheel From 7a9a6f516985bd7608a59d7a62a5a352d1a88a02 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Fri, 5 Aug 2022 09:45:33 -0400 Subject: [PATCH 27/41] Bump bdk-ffi to v0.8.0 tag --- bdk-ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bdk-ffi b/bdk-ffi index 80ed21e..138200d 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit 80ed21e4c9e61d6224e074258229a4d6da6cc049 +Subproject commit 138200db078cbd2b8a8d32ca8f4360bcd4b1eccd From d633d6d2a915ec4bc311d72f8c02e7b5f0a7bf19 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Fri, 5 Aug 2022 10:30:23 -0400 Subject: [PATCH 28/41] Update changelog to reflect 0.2.0 changes --- CHANGELOG.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0dff5c..bc24f09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic ## [Unreleased] +## [0.1.0-0.2.0] +### Added +- Update BDK to version `0.20.0` +- APIs Added + - TxBuilder.add_data(data) + - Wallet.list_unspent() returns a list of local UTXOs + - Add coin control methods on TxBuilder + +### Fixed +- Tox tests + ## [0.0.5-0.1.0] ### Added - Community related files (bug report, feature request, and pull request templates) @@ -35,4 +46,5 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic [Semantic Versioning]: https://semver.org/spec/v2.0.0.html [unreleased]: https://github.com/bitcoindevkit/bdk-python/compare/v0.0.5...HEAD [0.0.1-0.0.5]: https://github.com/bitcoindevkit/bdk-python/compare/58f189f987cc644a1d86e965623c8f50904588ad...v0.0.5 -[0.0.5-0.1.0]: https://github.com/bitcoindevkit/bdk-python/compare/v0.0.5...v0.1.0 \ No newline at end of file +[0.0.5-0.1.0]: https://github.com/bitcoindevkit/bdk-python/compare/v0.0.5...v0.1.0 +[0.1.0-0.2.0]: https://github.com/bitcoindevkit/bdk-python/compare/v0.1.0...v0.2.0 \ No newline at end of file From 66376f05ecdcf09245ad8ab175ae6d7ae558dbde Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Fri, 5 Aug 2022 10:31:24 -0400 Subject: [PATCH 29/41] Refactors to setup.py --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 25e6e03..f44f715 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,7 @@ """ rust_ext = RustExtension( - "bdkpython.bdkffi", + target="bdkpython.bdkffi", path="./bdk-ffi/Cargo.toml", binding=Binding.NoBinding, ) @@ -60,7 +60,7 @@ setup( name='bdkpython', version='0.2.0.dev0', - description="The Python language bindings for the Bitcoin Dev Kit", + description="The Python language bindings for the Bitcoin Development Kit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', rust_extensions=[rust_ext], From d916fbd7bea91aeadd022f6c642f89cf62d57f64 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderB@protonmail.com> Date: Sun, 7 Aug 2022 13:26:41 -0400 Subject: [PATCH 30/41] Fix CHANGELOG.md Co-authored-by: Steve Myers <github@notmandatory.org> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc24f09..62b78bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,7 +44,7 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ [Semantic Versioning]: https://semver.org/spec/v2.0.0.html -[unreleased]: https://github.com/bitcoindevkit/bdk-python/compare/v0.0.5...HEAD +[unreleased]: https://github.com/bitcoindevkit/bdk-python/compare/v0.2.0...HEAD [0.0.1-0.0.5]: https://github.com/bitcoindevkit/bdk-python/compare/58f189f987cc644a1d86e965623c8f50904588ad...v0.0.5 [0.0.5-0.1.0]: https://github.com/bitcoindevkit/bdk-python/compare/v0.0.5...v0.1.0 [0.1.0-0.2.0]: https://github.com/bitcoindevkit/bdk-python/compare/v0.1.0...v0.2.0 \ No newline at end of file From fbf9792b38cef473bcafd7d9c6295912dfdce445 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Sun, 7 Aug 2022 15:48:59 -0400 Subject: [PATCH 31/41] Bump version to 0.3.0.dev0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f44f715..6aacf32 100644 --- a/setup.py +++ b/setup.py @@ -59,7 +59,7 @@ setup( name='bdkpython', - version='0.2.0.dev0', + version='0.3.0.dev0', description="The Python language bindings for the Bitcoin Development Kit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', From 810e22dc9c4526199388bb0d316f73852ad022c4 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Tue, 20 Sep 2022 08:09:36 -0400 Subject: [PATCH 32/41] Bump bdk-ffi submodule to v0.9.0 tag --- bdk-ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bdk-ffi b/bdk-ffi index 138200d..485f4f7 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit 138200db078cbd2b8a8d32ca8f4360bcd4b1eccd +Subproject commit 485f4f72ce4d625e988effa67701adab0039aa64 From 02a572cbc6cd47bbc1aec31f48fd5039a5d93e2e Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Thu, 22 Sep 2022 10:25:33 -0400 Subject: [PATCH 33/41] Remove changelog This is in line with the bdk-jvm, bdk-android, and bdk-swift libraries, who all rely on the bdk-ffi changelog. --- CHANGELOG.md | 50 -------------------------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 62b78bb..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,50 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog], and this project adheres to [Semantic Versioning]. - -## [Unreleased] - -## [0.1.0-0.2.0] -### Added -- Update BDK to version `0.20.0` -- APIs Added - - TxBuilder.add_data(data) - - Wallet.list_unspent() returns a list of local UTXOs - - Add coin control methods on TxBuilder - -### Fixed -- Tox tests - -## [0.0.5-0.1.0] -### Added -- Community related files (bug report, feature request, and pull request templates) -- Changelog -- MIT and Apache 2.0 licenses -- Update BDK to version `0.19.0` -- Add `BumpFeeTxBuilder` to bump the fee on an unconfirmed tx created by the Wallet -- Add `Blockchain.broadcast` function (does not return anything) -- Add TxBuilder for creating new spending `PartiallySignedBitcoinTransaction` -- Add TxBuilder `add_recipient`, `fee_rate`, and `finish` functions -- Add TxBuilder `drain_wallet` and `drain_to` functions -- Update generate cli tool to generate all binding languages and rename to bdk-ffi-bindgen -- Add sqlite database support -- Fix memory database configuration enum, remove junk field -- Remove hard coded sync progress value (was always returning 21.0) -- Fix tests and tox build workflow - -## [0.0.1-0.0.5] -### Added -- Readme -- Rust binary to build -- CI workflow for tessting PRs -- Publishing workflow using GitHub Actions -- Basic examples -- Release on PyPI - -[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ -[Semantic Versioning]: https://semver.org/spec/v2.0.0.html -[unreleased]: https://github.com/bitcoindevkit/bdk-python/compare/v0.2.0...HEAD -[0.0.1-0.0.5]: https://github.com/bitcoindevkit/bdk-python/compare/58f189f987cc644a1d86e965623c8f50904588ad...v0.0.5 -[0.0.5-0.1.0]: https://github.com/bitcoindevkit/bdk-python/compare/v0.0.5...v0.1.0 -[0.1.0-0.2.0]: https://github.com/bitcoindevkit/bdk-python/compare/v0.1.0...v0.2.0 \ No newline at end of file From 96889b43a864eaa595ce10fa767d7bff8a64783d Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Thu, 22 Sep 2022 11:02:05 -0400 Subject: [PATCH 34/41] Add documentation on local testing --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a482f5c..b3a858f 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,18 @@ python3 setup.py --verbose bdist_wheel ``` <br/> -## Run tox to build and test +## Run tox to build and test locally ```shell # install dev requirements pip install --requirement requirements-dev.txt +# build bindings glue code (located at ./src/bdkpython/bdk.py) +source ./generate.sh + # build and test -tox +tox -vv ``` +<br/> ## Install locally ```shell From d539d8eaf83e8a9b94bb728534d002e1dc8617c4 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Thu, 22 Sep 2022 11:02:41 -0400 Subject: [PATCH 35/41] Update tests for bdk-ffi v0.9.0 --- tests/test_bdk.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_bdk.py b/tests/test_bdk.py index b667b30..e546592 100644 --- a/tests/test_bdk.py +++ b/tests/test_bdk.py @@ -38,8 +38,8 @@ def test_wallet_balance(self): ) wallet.sync(blockchain, None) balance = wallet.get_balance() - # print(f"Balance is {balance} sat") - assert balance > 0, "Balance is 0, send testnet coins to tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e" + # print(f"Balance is {balance.total} sat") + assert balance.total > 0, "Balance is 0, send testnet coins to tb1qzg4mckdh50nwdm9hkzq06528rsu73hjxxzem3e" if __name__ == '__main__': From 4ff428a9a64b2745bbf5b8be882df9172fcc3f20 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Thu, 22 Sep 2022 11:18:35 -0400 Subject: [PATCH 36/41] Update simple example in setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6aacf32..f079730 100644 --- a/setup.py +++ b/setup.py @@ -48,7 +48,7 @@ # print wallet balance wallet.sync(blockchain, None) balance = wallet.get_balance() -print(f"Wallet balance is: {balance}") +print(f"Wallet balance is: {balance.total}") """ rust_ext = RustExtension( From 4ff3f71cb8645a3a3f1b089d67923a07e5d9614c Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Thu, 3 Nov 2022 11:32:32 -0400 Subject: [PATCH 37/41] Bump bdk-ffi submodule to v0.10.0 (bdk version 0.23.0) --- README.md | 2 +- bdk-ffi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b3a858f..c89f245 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ python -m unittest --verbose tests/test_bdk.py ## Build the package ```shell -# Install dependecies +# Install dependencies pip install --requirement requirements.txt # Generate the bindings first diff --git a/bdk-ffi b/bdk-ffi index 485f4f7..e6cf423 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit 485f4f72ce4d625e988effa67701adab0039aa64 +Subproject commit e6cf4237218be9c6143936e7d0056e5270d4c227 From 82126ece78042c940cde44ecac7701d113300eed Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Thu, 3 Nov 2022 15:22:25 -0400 Subject: [PATCH 38/41] Add publishing CI workflow --- .github/workflows/build.yml | 35 +-------- .github/workflows/publish.yml | 141 ++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 24c75c7..e4e8293 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,5 @@ +name: Build wheels on: [push, pull_request] -name: Build and publish wheels # We use manylinux2014 because older CentOS versions used by 2010 and 1 have a very old glibc version, which # makes it very hard to use GitHub's javascript actions (checkout, upload-artifact, etc). @@ -107,36 +107,3 @@ jobs: with: name: bdkpython-win-${{ matrix.python }} path: dist/*.whl - - publish-pypi: - name: 'Publish on PyPI' - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') - runs-on: ubuntu-latest - needs: [build-manylinux2014-x86_64-wheel, build-macos-universal-wheel, build-windows-wheel] - # needs: [build-macos-universal-wheel] - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: 'Download artifacts in dist/ directory' - uses: actions/download-artifact@v2 - with: - path: dist/ - - # - name: Display structure of downloaded files - # run: ls -R - - # - name: 'Publish on test PyPI' - # uses: pypa/gh-action-pypi-publish@release/v1 - # with: - # user: __token__ - # password: ${{ secrets.TEST_PYPI_API_TOKEN }} - # repository_url: https://test.pypi.org/legacy/ - # packages_dir: dist/*/ - - - name: 'Publish on PyPI' - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} - packages_dir: dist/*/ \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..aeb16e6 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,141 @@ +name: Build and publish wheels on PyPI +on: [workflow_dispatch] + +# We use manylinux2014 because older CentOS versions used by 2010 and 1 have a very old glibc version, which +# makes it very hard to use GitHub's javascript actions (checkout, upload-artifact, etc). +# They mount their own nodejs interpreter inside your container, but since that's not statically linked it +# tries to load glibc and fails because it requires a more recent version. + +jobs: + build-manylinux2014-x86_64-wheel: + name: 'Build Manylinux 2014 x86_64 wheel' + runs-on: ubuntu-latest + container: + image: quay.io/pypa/manylinux2014_x86_64 + env: + PLAT: manylinux2014_x86_64 + PYBIN: '/opt/python/${{ matrix.python }}/bin' + strategy: + matrix: + python: # Update this list whenever the docker image is updated (check /opt/python/) + - cp36-cp36m + - cp37-cp37m + - cp38-cp38 + - cp39-cp39 + - cp310-cp310 + - pp37-pypy37_pp73 + - pp38-pypy38_pp73 + steps: + - name: checkout + uses: actions/checkout@v2 + with: + submodules: true + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - name: install requirements + run: ${PYBIN}/pip install -r requirements.txt + - name: generate bindings + run: bash generate.sh + - name: build wheel + run: ${PYBIN}/pip wheel . --no-deps -w /tmp/wheelhouse + - name: repair wheel + run: auditwheel repair /tmp/wheelhouse/* --plat "$PLAT" -w /tmp/wheelhouse-repaired + - uses: actions/upload-artifact@v2 + with: + name: bdkpython-manylinux2014-x86_64-${{ matrix.python }} + path: /tmp/wheelhouse-repaired/*.whl + + build-macos-universal-wheel: + name: 'Build macOS universal wheel' + runs-on: macos-latest + strategy: + matrix: + python: + - '3.7' + - '3.8' + - '3.9' + - '3.10' + steps: + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + - run: python3 --version + - name: checkout + uses: actions/checkout@v2 + with: + submodules: true + - run: rustup target add aarch64-apple-darwin + - run: pip3 install --user -r requirements.txt + - run: pip3 install --user wheel + - run: bash generate.sh + - name: build wheel + env: + ARCHFLAGS: "-arch x86_64 -arch arm64" + run: python3 setup.py -v bdist_wheel + - uses: actions/upload-artifact@v2 + with: + name: bdkpython-macos-${{ matrix.python }} + path: dist/*.whl + + build-windows-wheel: + name: 'Build windows wheel' + runs-on: windows-latest + strategy: + matrix: + python: + - '3.7' + - '3.8' + - '3.9' + - '3.10' + steps: + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + - run: python --version + - name: checkout + uses: actions/checkout@v2 + with: + submodules: true + - run: pip install --user -r requirements.txt + - run: ./generate.sh + shell: bash + - run: pip install --user wheel + - name: build wheel + run: python setup.py -v bdist_wheel + - uses: actions/upload-artifact@v2 + with: + name: bdkpython-win-${{ matrix.python }} + path: dist/*.whl + + publish-pypi: + name: 'Publish on PyPI' + runs-on: ubuntu-latest + needs: [build-manylinux2014-x86_64-wheel, build-macos-universal-wheel, build-windows-wheel] + # needs: [build-macos-universal-wheel] + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: 'Download artifacts in dist/ directory' + uses: actions/download-artifact@v2 + with: + path: dist/ + + # - name: Display structure of downloaded files + # run: ls -R + + # - name: 'Publish on test PyPI' + # uses: pypa/gh-action-pypi-publish@release/v1 + # with: + # user: __token__ + # password: ${{ secrets.TEST_PYPI_API_TOKEN }} + # repository_url: https://test.pypi.org/legacy/ + # packages_dir: dist/*/ + + - name: 'Publish on PyPI' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} + packages_dir: dist/*/ \ No newline at end of file From ec7b3769b59ecfa1b02a193c357d62aeca66a9b6 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Wed, 9 Nov 2022 12:52:15 -0500 Subject: [PATCH 39/41] Bump bdk-ffi submodule to v0.11.0 (bdk version 0.24.0) Signed-off-by: thunderbiscuit <thunderbiscuit@protonmail.com> --- bdk-ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bdk-ffi b/bdk-ffi index e6cf423..0648075 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit e6cf4237218be9c6143936e7d0056e5270d4c227 +Subproject commit 0648075555b86365e2408fab484782a2b793b545 From 2a9721899128c79ada6b13922ed04689c3f2f01d Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Wed, 9 Nov 2022 15:26:51 -0500 Subject: [PATCH 40/41] Bump library development version to 0.6.0.dev0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f079730..8462a6a 100644 --- a/setup.py +++ b/setup.py @@ -59,7 +59,7 @@ setup( name='bdkpython', - version='0.3.0.dev0', + version='0.6.0.dev0', description="The Python language bindings for the Bitcoin Development Kit", long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown', From cca5a733753a04bf566b9867854a0c1a9c9794a2 Mon Sep 17 00:00:00 2001 From: thunderbiscuit <thunderbiscuit@protonmail.com> Date: Tue, 15 Nov 2022 10:09:04 -0500 Subject: [PATCH 41/41] Add notice of archival and move to bdk-ffi repository --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index c89f245..5d55c92 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,11 @@ # bdk-python + +⚠️⚠️ The code in this repository has been moved to [bdk-ffi](https://github.com/bitcoindevkit/bdk-ffi), and development is continuing there. This repository is now considered an archive, and will not accept new pull requests or issues. ⚠️⚠️ + +<br/> +<br/> +<br/> + The Python language bindings for the [bitcoindevkit](https://github.com/bitcoindevkit). See the [package on PyPI](https://pypi.org/project/bdkpython/).