From e640f99d90038139750d6a96f8ddf348d54a8e4e Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Tue, 22 Jul 2025 16:52:47 -0400 Subject: [PATCH 1/3] docs: add local testing and usage section to readme --- .gitignore | 2 +- README.md | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4d750b5..41a211e 100644 --- a/.gitignore +++ b/.gitignore @@ -62,4 +62,4 @@ src/bdkpython/*.so build/ testing-setup-py-simple-example.py -localenvironment/ +.localpythonenv/ diff --git a/README.md b/README.md index 5ee36b5..72e6e9c 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,19 @@ The Python language bindings for the [bitcoindevkit](https://github.com/bitcoindevkit). See the [package on PyPI](https://pypi.org/project/bdkpython/). + +## Local Testing and Usage + +1. Start a Python virtual environment +2. Run one of the build script +3. Create the wheel +4. Install the library +5. Run the tests + +```sh +source .localpythonenv/bin/activate +bash scripts/generate-macos-arm64.sh +python3 setup.py bdist_wheel +pip3 install ./dist/bdkpython-.whl --force-reinstall +python3 -m unittest --verbose +``` From 52a73300c6b0abecb4f172d857d82db5c88ddd23 Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Tue, 22 Jul 2025 16:53:57 -0400 Subject: [PATCH 2/3] test: remove live tests --- tests/test_live_kyoto.py | 62 ------------------- tests/test_live_tx_builder.py | 111 ---------------------------------- tests/test_live_wallet.py | 111 ---------------------------------- 3 files changed, 284 deletions(-) delete mode 100644 tests/test_live_kyoto.py delete mode 100644 tests/test_live_tx_builder.py delete mode 100644 tests/test_live_wallet.py diff --git a/tests/test_live_kyoto.py b/tests/test_live_kyoto.py deleted file mode 100644 index 651c714..0000000 --- a/tests/test_live_kyoto.py +++ /dev/null @@ -1,62 +0,0 @@ -from bdkpython import Persister, Network, Descriptor, KeychainKind, CbfBuilder, CbfComponents, CbfClient, CbfNode, CbfError, IpAddress, ScanType, Peer, Update, Wallet -import unittest -import os -import asyncio - -network: Network = Network.SIGNET - -ip: IpAddress = IpAddress.from_ipv4(68, 47, 229, 218) -peer: Peer = Peer(address=ip, port=None, v2_transport=False) - -descriptor: Descriptor = Descriptor( - "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/1h/0/*)", - network=network -) -change_descriptor: Descriptor = Descriptor( - "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/1h/1/*)", - network=network -) - -class LiveKyotoTest(unittest.IsolatedAsyncioTestCase): - - def tearDown(self) -> None: - if os.path.exists("./bdk_persistence.sqlite"): - os.remove("./bdk_persistence.sqlite") - if os.path.exists("./data/signet/headers.db"): - os.remove("./data/signet/headers.db") - if os.path.exists("./data/signet/peers.db"): - os.remove("./data/signet/peers.db") - - async def testKyoto(self) -> None: - persister: Persister = Persister.new_in_memory() - wallet: Wallet = Wallet( - descriptor, - change_descriptor, - network, - persister - ) - peers = [peer] - light_client: CbfComponents = CbfBuilder().scan_type(ScanType.NEW()).peers(peers).connections(1).build(wallet) - client: CbfClient = light_client.client - node: CbfNode = light_client.node - async def log_loop(client: CbfClient): - while True: - log = await client.next_log() - print(log) - log_task = asyncio.create_task(log_loop(client)) - node.run() - try: - update: Update = await client.update() - wallet.apply_update(update) - self.assertGreater( - wallet.balance().total.to_sat(), - 0, - f"Wallet balance must be greater than 0! Please send funds to {wallet.reveal_next_address(KeychainKind.EXTERNAL).address} and try again." - ) - log_task.cancel() - client.shutdown() - except CbfError as e: - raise e - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_live_tx_builder.py b/tests/test_live_tx_builder.py deleted file mode 100644 index aab9f48..0000000 --- a/tests/test_live_tx_builder.py +++ /dev/null @@ -1,111 +0,0 @@ -from bdkpython import Descriptor -from bdkpython import KeychainKind -from bdkpython import Wallet -from bdkpython import EsploraClient -from bdkpython import ScriptAmount -from bdkpython import FullScanRequest -from bdkpython import Address -from bdkpython import Psbt -from bdkpython import TxBuilder -from bdkpython import Persister -from bdkpython import Network -from bdkpython import Amount -from bdkpython import FeeRate - -import unittest -import os - -SIGNET_ESPLORA_URL = "http://signet.bitcoindevkit.net" -TESTNET_ESPLORA_URL = "https://esplora.testnet.kuutamo.cloud" - -descriptor: Descriptor = Descriptor( - "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/1h/0/*)", - Network.TESTNET -) -change_descriptor: Descriptor = Descriptor( - "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/1h/1/*)", - Network.TESTNET -) - -class LiveTxBuilderTest(unittest.TestCase): - - def tearDown(self) -> None: - if os.path.exists("./bdk_persistence.sqlite"): - os.remove("./bdk_persistence.sqlite") - - def test_tx_builder(self): - connection: Persister = Persister.new_in_memory() - wallet: Wallet = Wallet( - descriptor, - change_descriptor, - Network.SIGNET, - connection - ) - esplora_client: EsploraClient = EsploraClient(url = SIGNET_ESPLORA_URL) - full_scan_request: FullScanRequest = wallet.start_full_scan().build() - update = esplora_client.full_scan( - request=full_scan_request, - stop_gap=10, - parallel_requests=1 - ) - wallet.apply_update(update) - - self.assertGreater( - wallet.balance().total.to_sat(), - 0, - f"Wallet balance must be greater than 0! Please send funds to {wallet.reveal_next_address(KeychainKind.EXTERNAL).address} and try again." - ) - - recipient = Address( - address="tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", - network=Network.SIGNET - ) - - psbt = TxBuilder().add_recipient(script=recipient.script_pubkey(), amount=Amount.from_sat(4200)).fee_rate(fee_rate=FeeRate.from_sat_per_vb(2)).finish(wallet) - - self.assertTrue(psbt.serialize().startswith("cHNi"), "The PSBT should start with cHNi") - - def complex_tx_builder(self): - persister: Persister = Persister.new_in_memory() - wallet: Wallet = Wallet( - descriptor, - change_descriptor, - Network.SIGNET, - persister - ) - esplora_client: EsploraClient = EsploraClient(url = SIGNET_ESPLORA_URL) - full_scan_request: FullScanRequest = wallet.start_full_scan().build() - update = esplora_client.full_scan( - request=full_scan_request, - stop_gap=10, - parallel_requests=1 - ) - wallet.apply_update(update) - - self.assertGreater( - wallet.balance().total.to_sat(), - 0, - f"Wallet balance must be greater than 0! Please send funds to {wallet.reveal_next_address(KeychainKind.EXTERNAL).address} and try again." - ) - - recipient1 = Address( - address="tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", - network=Network.SIGNET - ) - recipient2 = Address( - address="tb1qw2c3lxufxqe2x9s4rdzh65tpf4d7fssjgh8nv6", - network=Network.SIGNET - ) - all_recipients = list( - ScriptAmount(recipient1.script_pubkey, 4200), - ScriptAmount(recipient2.script_pubkey, 4200) - ) - - psbt: Psbt = TxBuilder().set_recipients(all_recipients).fee_rate(fee_rate=FeeRate.from_sat_per_vb(2)).finish(wallet) - wallet.sign(psbt) - - self.assertTrue(psbt.serialize().startswith("cHNi"), "The PSBT should start with cHNi") - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_live_wallet.py b/tests/test_live_wallet.py deleted file mode 100644 index f4f5cf9..0000000 --- a/tests/test_live_wallet.py +++ /dev/null @@ -1,111 +0,0 @@ -from bdkpython import Descriptor -from bdkpython import KeychainKind -from bdkpython import Wallet -from bdkpython import EsploraClient -from bdkpython import FullScanRequest -from bdkpython import Address -from bdkpython import Psbt -from bdkpython import TxBuilder -from bdkpython import Persister -from bdkpython import Network -from bdkpython import Amount -from bdkpython import FeeRate - -import unittest -import os - -SIGNET_ESPLORA_URL = "http://signet.bitcoindevkit.net" -TESTNET_ESPLORA_URL = "https://esplora.testnet.kuutamo.cloud" - -descriptor: Descriptor = Descriptor( - "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/1h/0/*)", - Network.TESTNET -) -change_descriptor: Descriptor = Descriptor( - "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/1h/1/*)", - Network.TESTNET -) - -class LiveWalletTest(unittest.TestCase): - - def tearDown(self) -> None: - if os.path.exists("./bdk_persistence.sqlite"): - os.remove("./bdk_persistence.sqlite") - - def test_synced_balance(self): - persister: Persister = Persister.new_in_memory() - wallet: Wallet = Wallet( - descriptor, - change_descriptor, - Network.SIGNET, - persister - ) - esplora_client: EsploraClient = EsploraClient(url = SIGNET_ESPLORA_URL) - full_scan_request: FullScanRequest = wallet.start_full_scan().build() - update = esplora_client.full_scan( - request=full_scan_request, - stop_gap=10, - parallel_requests=1 - ) - wallet.apply_update(update) - - self.assertGreater( - wallet.balance().total.to_sat(), - 0, - f"Wallet balance must be greater than 0! Please send funds to {wallet.reveal_next_address(KeychainKind.EXTERNAL).address} and try again." - ) - - print(f"Transactions count: {len(wallet.transactions())}") - transactions = wallet.transactions()[:3] - for tx in transactions: - sent_and_received = wallet.sent_and_received(tx.transaction) - print(f"Transaction: {tx.transaction.compute_txid()}") - print(f"Sent {sent_and_received.sent.to_sat()}") - print(f"Received {sent_and_received.received.to_sat()}") - - - def test_broadcast_transaction(self): - persister: Persister = Persister.new_in_memory() - wallet: Wallet = Wallet( - descriptor, - change_descriptor, - Network.SIGNET, - persister - ) - esplora_client: EsploraClient = EsploraClient(url = SIGNET_ESPLORA_URL) - full_scan_request: FullScanRequest = wallet.start_full_scan().build() - update = esplora_client.full_scan( - request=full_scan_request, - stop_gap=10, - parallel_requests=1 - ) - wallet.apply_update(update) - - self.assertGreater( - wallet.balance().total.to_sat(), - 0, - f"Wallet balance must be greater than 0! Please send funds to {wallet.reveal_next_address(KeychainKind.EXTERNAL).address} and try again." - ) - - recipient = Address( - address="tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989", - network=Network.SIGNET - ) - - psbt: Psbt = TxBuilder().add_recipient(script=recipient.script_pubkey(), amount=Amount.from_sat(4200)).fee_rate(fee_rate=FeeRate.from_sat_per_vb(2)).finish(wallet) - self.assertTrue(psbt.serialize().startswith("cHNi"), "The PSBT should start with cHNi") - - walletDidSign = wallet.sign(psbt) - self.assertTrue(walletDidSign) - tx = psbt.extract_tx() - print(f"Transaction Id: {tx.compute_txid()}") - fee = wallet.calculate_fee(tx) - print(f"Transaction Fee: {fee.to_sat()}") - fee_rate = wallet.calculate_fee_rate(tx) - print(f"Transaction Fee Rate: {fee_rate.to_sat_per_vb_ceil()} sat/vB") - - esplora_client.broadcast(tx) - - -if __name__ == '__main__': - unittest.main() From 858a39f7883b070166d24c2485bb4363029e211f Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Wed, 23 Jul 2025 15:13:39 -0400 Subject: [PATCH 3/3] chore: checkout bdk-ffi @ v2.0.0 tag --- bdk-ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bdk-ffi b/bdk-ffi index c8d08e9..0256c27 160000 --- a/bdk-ffi +++ b/bdk-ffi @@ -1 +1 @@ -Subproject commit c8d08e9061b50bae139016243706d880687d748b +Subproject commit 0256c27e8f16b8dc3d7f864f6d0e0355bba38f7b