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 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 @@ print(f"Wallet balance is: {balance}") ``` """ +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", -] -