#!/usr/bin/env python3
"""Verify the full PSBT + importdescriptors pipeline against the live node."""
import sys
import json
sys.path.insert(0, "/home/vincent/projects/btc-wallet/wallet-engine")
from wallet import WalletEngine
ENG = WalletEngine()
def test_rpc():
print("=== TEST 1: RPC connectivity ===")
height = ENG.get_block_count()
print(f" Block height: {height}")
net = ENG.get_network_info()
print(f" Version: {net['version']}, Connections: {net['connections']}")
print(" PASS\n")
def test_import_descriptors():
print("=== TEST 2: importdescriptors (watch-only) ===")
# Generate test mnemonic and derive xpub
mnemonic = ENG.generate_mnemonic(128)
bip84 = ENG.derive_bip84(mnemonic)
xpub = bip84["xpub"]
print(f" Test mnemonic: {mnemonic}")
print(f" XPUB: {xpub}")
# Derive first address
addr = ENG.derive_bip84_address(mnemonic, address_index=0)
print(f" First address: {addr['address']}")
# Import as watch-only
try:
result = ENG.import_wallet_watchonly(xpub, "test_watchonly")
print(f" Import result: {json.dumps(result['imported'], indent=2)}")
print(" PASS\n")
return True
except Exception as e:
print(f" FAIL: {e}\n")
return False
def test_balance():
print("=== TEST 3: Balance check (watch-only wallet) ===")
mnemonic = ENG.generate_mnemonic(128)
addr = ENG.derive_bip84_address(mnemonic, address_index=0)
balance = ENG.get_balance(addr["address"])
print(f" Address: {addr['address']}")
print(f" Balance: {balance}")
# Fresh address should have 0 balance
print(" PASS (no error)\n")
def test_create_psbt():
print("=== TEST 4: create_psbt ===")
# Need a wallet with UTXOs to test create_psbt properly
# For now, test with a dummy wallet to verify the error path
mnemonic = ENG.generate_mnemonic(128)
wallet = ENG.create_wallet("test_wallet", mnemonic)
try:
result = ENG.create_psbt(
wallet,
outputs=[{"address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq", "amount": 0.001}],
fee_rate=1.0
)
print(f" Result: {result}")
print(" UNEXPECTED: Should have failed (no UTXOs)")
except ValueError as e:
print(f" Expected error (no UTXOs): {e}")
print(" PASS\n")
except Exception as e:
print(f" FAIL: {type(e).__name__}: {e}\n")
def test_decode_psbt():
print("=== TEST 5: decode_psbt / utxtoelement ===")
# Test decodepsbt RPC availability
try:
result = ENG._rpc_call("help")
methods = [m for m in result if "psbt" in m.lower()]
psbt_methods = [m for m in methods if not m.startswith("-")]
print(f" Available PSBT methods: {psbt_methods}")
print(" PASS\n")
except Exception as e:
print(f" FAIL: {e}\n")
def test_sign_raw_issues():
print("=== TEST 6: Check signrawtransactionwithkey behavior ===")
# signrawtransactionwithkey expects a raw tx hex, NOT a PSBT
# For PSBTs, we need walletprocesspsbt or signpsbt
# Let's check what the node offers
try:
help = ENG._rpc_call("help")
relevant = [m for m in help if any(k in m.lower() for k in ["signpsbt", "walletprocesspsbt", "signrawtransaction"])]
non_deprecated = [m for m in relevant if not m.startswith("-")]
print(f" Signing-related methods: {non_deprecated}")
print(" PASS\n")
except Exception as e:
print(f" FAIL: {e}\n")
if __name__ == "__main__":
test_rpc()
test_import_descriptors()
test_balance()
test_create_psbt()
test_decode_psbt()
test_sign_raw_issues()
print("=== ALL TESTS COMPLETE ===")