aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/functional/data/rpc_psbt.json4
-rwxr-xr-xtest/functional/feature_proxy.py10
-rwxr-xr-xtest/functional/rpc_deriveaddresses.py7
-rwxr-xr-xtest/functional/rpc_psbt.py22
-rw-r--r--test/functional/test_framework/psbt.py9
-rwxr-xr-xtest/functional/test_framework/test_framework.py17
-rwxr-xr-xtest/functional/wallet_listsinceblock.py14
-rwxr-xr-xtest/functional/wallet_listtransactions.py12
-rwxr-xr-xtest/functional/wallet_sendall.py35
-rwxr-xr-xtest/functional/wallet_taproot.py153
10 files changed, 213 insertions, 70 deletions
diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json
index 657faebffc..3127350872 100644
--- a/test/functional/data/rpc_psbt.json
+++ b/test/functional/data/rpc_psbt.json
@@ -44,6 +44,10 @@
[
"cHNidP8BAKOro2MDAwMDA5ggCAAA////CQAtAAD+///1AAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAD+///1Zm9ybmV3nWx1Y2vmelLmegAAAAAAAAAAAAAAAAAAAAMKAwMDAwMDAwMDAwMACvMBA3FkAAAAAAAAAAAABAAlAAAAAAAAACEWDQ0zDQ0NDQ0NDQ0NCwEAAH9/f39/fwMAAABNo6P///kAAA==",
"Input Taproot BIP32 keypath has an invalid length"
+ ],
+ [
+ "cHNidP8BAIkCAAAAAapfm08b0MipBvW9thL06f8rMbeazW7TIa0W9plHj4WoAAAAAAD9////AoCWmAAAAAAAIlEgC+blBlIP1iijRWxqjw1u9H02sqr7y8fno6/LdnvGqPl895x2AAAAACJRIM5wyjSexMbADl4K+AI1/68zyaDlE7guKvrEDUAjwqU1AAAAAAABASsAlDV3AAAAACJRIDfCpO/CIAqc0JKgBhsCfaPGdyroYtmH+4gQK/Mnn72UIRZGOixxmh9h2gqDIecYHcQHRa8w+Sokc//iDiqXz7uMGRkAHzYIzlYAAIABAACAAAAAgAAAAABhAAAAARcgRjoscZofYdoKgyHnGB3EB0WvMPkqJHP/4g4ql8+7jBkAAQUg1YCB33LpmkGemw3ncz7fcnjhL/bBG/PjH8vpgr2L3cUBBgAhB9WAgd9y6ZpBnpsN53M+33J44S/2wRvz4x/L6YK9i93FGQAfNgjOVgAAgAEAAIAAAACAAAAAAGIAAAAAAQUg9jMNus8cd+GAosBk9wn+pNP9wn7A+jy2Vq0cy+siJ8wBBgAhB/YzDbrPHHfhgKLAZPcJ/qTT/cJ+wPo8tlatHMvrIifMGQAfNgjOVgAAgAEAAIAAAACAAQAAAFEBAAAA",
+ "Output Taproot tree must not be empty"
]
],
"valid" : [
diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py
index d02d56d068..c90852562e 100755
--- a/test/functional/feature_proxy.py
+++ b/test/functional/feature_proxy.py
@@ -332,6 +332,16 @@ class ProxyTest(BitcoinTestFramework):
msg = "Error: Invalid -i2psam address or hostname: 'def:xyz'"
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
+ self.log.info("Test passing invalid -onlynet=i2p without -i2psam raises expected init error")
+ self.nodes[1].extra_args = ["-onlynet=i2p"]
+ msg = "Error: Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided"
+ self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
+
+ self.log.info("Test passing invalid -onlynet=cjdns without -cjdnsreachable raises expected init error")
+ self.nodes[1].extra_args = ["-onlynet=cjdns"]
+ msg = "Error: Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided"
+ self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
+
self.log.info("Test passing -onlynet=onion with -onion=0/-noonion raises expected init error")
msg = (
"Error: Outbound connections restricted to Tor (-onlynet=onion) but "
diff --git a/test/functional/rpc_deriveaddresses.py b/test/functional/rpc_deriveaddresses.py
index 42d7d59d56..a69326736d 100755
--- a/test/functional/rpc_deriveaddresses.py
+++ b/test/functional/rpc_deriveaddresses.py
@@ -44,6 +44,13 @@ class DeriveaddressesTest(BitcoinTestFramework):
combo_descriptor = descsum_create("combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)")
assert_equal(self.nodes[0].deriveaddresses(combo_descriptor), ["mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", "mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", address, "2NDvEwGfpEqJWfybzpKPHF2XH3jwoQV3D7x"])
+ # Before #26275, bitcoind would crash when deriveaddresses was
+ # called with derivation index 2147483647, which is the maximum
+ # positive value of a signed int32, and - currently - the
+ # maximum value that the deriveaddresses bitcoin RPC call
+ # accepts as derivation index.
+ assert_equal(self.nodes[0].deriveaddresses(descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), [2147483647, 2147483647]), ["bcrt1qtzs23vgzpreks5gtygwxf8tv5rldxvvsyfpdkg"])
+
hardened_without_privkey_descriptor = descsum_create("wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1'/1/0)")
assert_raises_rpc_error(-5, "Cannot derive script without private keys", self.nodes[0].deriveaddresses, hardened_without_privkey_descriptor)
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 4583ca25cf..1fe3b21542 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -27,6 +27,7 @@ from test_framework.psbt import (
PSBT_IN_SHA256,
PSBT_IN_HASH160,
PSBT_IN_HASH256,
+ PSBT_OUT_TAP_TREE,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -779,9 +780,18 @@ class PSBTTest(BitcoinTestFramework):
self.generate(self.nodes[0], 1)
self.nodes[0].importdescriptors([{"desc": descsum_create("tr({})".format(privkey)), "timestamp":"now"}])
- psbt = watchonly.sendall([wallet.getnewaddress()])["psbt"]
+ psbt = watchonly.sendall([wallet.getnewaddress(), addr])["psbt"]
psbt = self.nodes[0].walletprocesspsbt(psbt)["psbt"]
- self.nodes[0].sendrawtransaction(self.nodes[0].finalizepsbt(psbt)["hex"])
+ txid = self.nodes[0].sendrawtransaction(self.nodes[0].finalizepsbt(psbt)["hex"])
+ vout = find_vout_for_address(self.nodes[0], txid, addr)
+
+ # Make sure tap tree is in psbt
+ parsed_psbt = PSBT.from_base64(psbt)
+ assert_greater_than(len(parsed_psbt.o[vout].map[PSBT_OUT_TAP_TREE]), 0)
+ assert "taproot_tree" in self.nodes[0].decodepsbt(psbt)["outputs"][vout]
+ parsed_psbt.make_blank()
+ comb_psbt = self.nodes[0].combinepsbt([psbt, parsed_psbt.to_base64()])
+ assert_equal(comb_psbt, psbt)
self.log.info("Test that walletprocesspsbt both updates and signs a non-updated psbt containing Taproot inputs")
addr = self.nodes[0].getnewaddress("", "bech32m")
@@ -793,6 +803,14 @@ class PSBTTest(BitcoinTestFramework):
self.nodes[0].sendrawtransaction(rawtx)
self.generate(self.nodes[0], 1)
+ # Make sure tap tree is not in psbt
+ parsed_psbt = PSBT.from_base64(psbt)
+ assert PSBT_OUT_TAP_TREE not in parsed_psbt.o[0].map
+ assert "taproot_tree" not in self.nodes[0].decodepsbt(psbt)["outputs"][0]
+ parsed_psbt.make_blank()
+ comb_psbt = self.nodes[0].combinepsbt([psbt, parsed_psbt.to_base64()])
+ assert_equal(comb_psbt, psbt)
+
self.log.info("Test decoding PSBT with per-input preimage types")
# note that the decodepsbt RPC doesn't check whether preimages and hashes match
hash_ripemd160, preimage_ripemd160 = random_bytes(20), random_bytes(50)
diff --git a/test/functional/test_framework/psbt.py b/test/functional/test_framework/psbt.py
index 68945e7e84..3a5b4ec74d 100644
--- a/test/functional/test_framework/psbt.py
+++ b/test/functional/test_framework/psbt.py
@@ -123,6 +123,15 @@ class PSBT:
psbt = [x.serialize() for x in [self.g] + self.i + self.o]
return b"psbt\xff" + b"".join(psbt)
+ def make_blank(self):
+ """
+ Remove all fields except for PSBT_GLOBAL_UNSIGNED_TX
+ """
+ for m in self.i + self.o:
+ m.map.clear()
+
+ self.g = PSBTMap(map={0: self.g.map[0]})
+
def to_base64(self):
return base64.b64encode(self.serialize()).decode("utf8")
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index c880aabd21..b1164b98fd 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -596,24 +596,24 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.wait_until(lambda: sum(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in to_connection.getpeerinfo()) == to_num_peers)
def disconnect_nodes(self, a, b):
- def disconnect_nodes_helper(from_connection, node_num):
- def get_peer_ids():
+ def disconnect_nodes_helper(node_a, node_b):
+ def get_peer_ids(from_connection, node_num):
result = []
for peer in from_connection.getpeerinfo():
if "testnode{}".format(node_num) in peer['subver']:
result.append(peer['id'])
return result
- peer_ids = get_peer_ids()
+ peer_ids = get_peer_ids(node_a, node_b.index)
if not peer_ids:
self.log.warning("disconnect_nodes: {} and {} were not connected".format(
- from_connection.index,
- node_num,
+ node_a.index,
+ node_b.index,
))
return
for peer_id in peer_ids:
try:
- from_connection.disconnectnode(nodeid=peer_id)
+ node_a.disconnectnode(nodeid=peer_id)
except JSONRPCException as e:
# If this node is disconnected between calculating the peer id
# and issuing the disconnect, don't worry about it.
@@ -622,9 +622,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
raise
# wait to disconnect
- self.wait_until(lambda: not get_peer_ids(), timeout=5)
+ self.wait_until(lambda: not get_peer_ids(node_a, node_b.index), timeout=5)
+ self.wait_until(lambda: not get_peer_ids(node_b, node_a.index), timeout=5)
- disconnect_nodes_helper(self.nodes[a], b)
+ disconnect_nodes_helper(self.nodes[a], self.nodes[b])
def split_network(self):
"""
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index f259449bef..aff408ceb1 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -45,6 +45,7 @@ class ListSinceBlockTest(BitcoinTestFramework):
if self.options.descriptors:
self.test_desc()
self.test_send_to_self()
+ self.test_op_return()
def test_no_blockhash(self):
self.log.info("Test no blockhash")
@@ -448,6 +449,19 @@ class ListSinceBlockTest(BitcoinTestFramework):
assert any(c["address"] == addr for c in coins)
assert all(self.nodes[2].getaddressinfo(c["address"])["ischange"] for c in coins)
+ def test_op_return(self):
+ """Test if OP_RETURN outputs will be displayed correctly."""
+ block_hash = self.nodes[2].getbestblockhash()
+
+ raw_tx = self.nodes[2].createrawtransaction([], [{'data': 'aa'}])
+ funded_tx = self.nodes[2].fundrawtransaction(raw_tx)
+ signed_tx = self.nodes[2].signrawtransactionwithwallet(funded_tx['hex'])
+ tx_id = self.nodes[2].sendrawtransaction(signed_tx['hex'])
+
+ op_ret_tx = [tx for tx in self.nodes[2].listsinceblock(blockhash=block_hash)["transactions"] if tx['txid'] == tx_id][0]
+
+ assert 'address' not in op_ret_tx
+
if __name__ == '__main__':
ListSinceBlockTest().main()
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index 7c16b6328d..9bb06774a5 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -109,6 +109,7 @@ class ListTransactionsTest(BitcoinTestFramework):
self.run_rbf_opt_in_test()
self.run_externally_generated_address_test()
self.run_invalid_parameters_test()
+ self.test_op_return()
def run_rbf_opt_in_test(self):
"""Test the opt-in-rbf flag for sent and received transactions."""
@@ -284,6 +285,17 @@ class ListTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Negative count", self.nodes[0].listtransactions, count=-1)
assert_raises_rpc_error(-8, "Negative from", self.nodes[0].listtransactions, skip=-1)
+ def test_op_return(self):
+ """Test if OP_RETURN outputs will be displayed correctly."""
+ raw_tx = self.nodes[0].createrawtransaction([], [{'data': 'aa'}])
+ funded_tx = self.nodes[0].fundrawtransaction(raw_tx)
+ signed_tx = self.nodes[0].signrawtransactionwithwallet(funded_tx['hex'])
+ tx_id = self.nodes[0].sendrawtransaction(signed_tx['hex'])
+
+ op_ret_tx = [tx for tx in self.nodes[0].listtransactions() if tx['txid'] == tx_id][0]
+
+ assert 'address' not in op_ret_tx
+
if __name__ == '__main__':
ListTransactionsTest().main()
diff --git a/test/functional/wallet_sendall.py b/test/functional/wallet_sendall.py
index db4f32fe16..4fe11455b1 100755
--- a/test/functional/wallet_sendall.py
+++ b/test/functional/wallet_sendall.py
@@ -221,6 +221,11 @@ class SendallTest(BitcoinTestFramework):
self.add_utxos([16, 5])
spent_utxo = self.wallet.listunspent()[0]
+ # fails on out of bounds vout
+ assert_raises_rpc_error(-8,
+ "Input not found. UTXO ({}:{}) is not part of wallet.".format(spent_utxo["txid"], 1000),
+ self.wallet.sendall, recipients=[self.remainder_target], options={"inputs": [{"txid": spent_utxo["txid"], "vout": 1000}]})
+
# fails on unconfirmed spent UTXO
self.wallet.sendall(recipients=[self.remainder_target])
assert_raises_rpc_error(-8,
@@ -276,6 +281,33 @@ class SendallTest(BitcoinTestFramework):
recipients=[self.remainder_target],
fee_rate=100000)
+ @cleanup
+ def sendall_watchonly_specific_inputs(self):
+ self.log.info("Test sendall with a subset of UTXO pool in a watchonly wallet")
+ self.add_utxos([17, 4])
+ utxo = self.wallet.listunspent()[0]
+
+ self.nodes[0].createwallet(wallet_name="watching", disable_private_keys=True)
+ watchonly = self.nodes[0].get_wallet_rpc("watching")
+
+ import_req = [{
+ "desc": utxo["desc"],
+ "timestamp": 0,
+ }]
+ if self.options.descriptors:
+ watchonly.importdescriptors(import_req)
+ else:
+ watchonly.importmulti(import_req)
+
+ sendall_tx_receipt = watchonly.sendall(recipients=[self.remainder_target], options={"inputs": [utxo]})
+ psbt = sendall_tx_receipt["psbt"]
+ decoded = self.nodes[0].decodepsbt(psbt)
+ assert_equal(len(decoded["inputs"]), 1)
+ assert_equal(len(decoded["outputs"]), 1)
+ assert_equal(decoded["tx"]["vin"][0]["txid"], utxo["txid"])
+ assert_equal(decoded["tx"]["vin"][0]["vout"], utxo["vout"])
+ assert_equal(decoded["tx"]["vout"][0]["scriptPubKey"]["address"], self.remainder_target)
+
# This tests needs to be the last one otherwise @cleanup will fail with "Transaction too large" error
def sendall_fails_with_transaction_too_large(self):
self.log.info("Test that sendall fails if resulting transaction is too large")
@@ -341,6 +373,9 @@ class SendallTest(BitcoinTestFramework):
# Sendall fails when providing a fee that is too high
self.sendall_fails_on_high_fee()
+ # Sendall succeeds with watchonly wallets spending specific UTXOs
+ self.sendall_watchonly_specific_inputs()
+
# Sendall fails when many inputs result to too large transaction
self.sendall_fails_with_transaction_too_large()
diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py
index 3c630ba433..c2acafb373 100755
--- a/test/functional/wallet_taproot.py
+++ b/test/functional/wallet_taproot.py
@@ -5,6 +5,7 @@
"""Test generation and spending of P2TR addresses."""
import random
+import uuid
from decimal import Decimal
from test_framework.address import output_key_to_p2tr
@@ -229,17 +230,28 @@ class WalletTaprootTest(BitcoinTestFramework):
def do_test_addr(self, comment, pattern, privmap, treefn, keys):
self.log.info("Testing %s address derivation" % comment)
+
+ # Create wallets
+ wallet_uuid = uuid.uuid4().hex
+ self.nodes[0].createwallet(wallet_name=f"privs_tr_enabled_{wallet_uuid}", descriptors=True, blank=True)
+ self.nodes[0].createwallet(wallet_name=f"pubs_tr_enabled_{wallet_uuid}", descriptors=True, blank=True, disable_private_keys=True)
+ self.nodes[0].createwallet(wallet_name=f"addr_gen_{wallet_uuid}", descriptors=True, disable_private_keys=True, blank=True)
+ privs_tr_enabled = self.nodes[0].get_wallet_rpc(f"privs_tr_enabled_{wallet_uuid}")
+ pubs_tr_enabled = self.nodes[0].get_wallet_rpc(f"pubs_tr_enabled_{wallet_uuid}")
+ addr_gen = self.nodes[0].get_wallet_rpc(f"addr_gen_{wallet_uuid}")
+
desc = self.make_desc(pattern, privmap, keys, False)
desc_pub = self.make_desc(pattern, privmap, keys, True)
assert_equal(self.nodes[0].getdescriptorinfo(desc)['descriptor'], desc_pub)
- result = self.addr_gen.importdescriptors([{"desc": desc_pub, "active": True, "timestamp": "now"}])
+ result = addr_gen.importdescriptors([{"desc": desc_pub, "active": True, "timestamp": "now"}])
assert(result[0]['success'])
+ address_type = "bech32m" if "tr" in pattern else "bech32"
for i in range(4):
- addr_g = self.addr_gen.getnewaddress(address_type='bech32m')
+ addr_g = addr_gen.getnewaddress(address_type=address_type)
if treefn is not None:
addr_r = self.make_addr(treefn, keys, i)
assert_equal(addr_g, addr_r)
- desc_a = self.addr_gen.getaddressinfo(addr_g)['desc']
+ desc_a = addr_gen.getaddressinfo(addr_g)['desc']
if desc.startswith("tr("):
assert desc_a.startswith("tr(")
rederive = self.nodes[1].deriveaddresses(desc_a)
@@ -247,25 +259,37 @@ class WalletTaprootTest(BitcoinTestFramework):
assert_equal(rederive[0], addr_g)
# tr descriptors can be imported
- result = self.privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
+ result = privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
assert(result[0]["success"])
- result = self.pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
+ result = pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
assert(result[0]["success"])
+ # Cleanup
+ privs_tr_enabled.unloadwallet()
+ pubs_tr_enabled.unloadwallet()
+ addr_gen.unloadwallet()
+
def do_test_sendtoaddress(self, comment, pattern, privmap, treefn, keys_pay, keys_change):
self.log.info("Testing %s through sendtoaddress" % comment)
+
+ # Create wallets
+ wallet_uuid = uuid.uuid4().hex
+ self.nodes[0].createwallet(wallet_name=f"rpc_online_{wallet_uuid}", descriptors=True, blank=True)
+ rpc_online = self.nodes[0].get_wallet_rpc(f"rpc_online_{wallet_uuid}")
+
desc_pay = self.make_desc(pattern, privmap, keys_pay)
desc_change = self.make_desc(pattern, privmap, keys_change)
desc_pay_pub = self.make_desc(pattern, privmap, keys_pay, True)
desc_change_pub = self.make_desc(pattern, privmap, keys_change, True)
assert_equal(self.nodes[0].getdescriptorinfo(desc_pay)['descriptor'], desc_pay_pub)
assert_equal(self.nodes[0].getdescriptorinfo(desc_change)['descriptor'], desc_change_pub)
- result = self.rpc_online.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
+ result = rpc_online.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
assert(result[0]['success'])
- result = self.rpc_online.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
+ result = rpc_online.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
assert(result[0]['success'])
+ address_type = "bech32m" if "tr" in pattern else "bech32"
for i in range(4):
- addr_g = self.rpc_online.getnewaddress(address_type='bech32m')
+ addr_g = rpc_online.getnewaddress(address_type=address_type)
if treefn is not None:
addr_r = self.make_addr(treefn, keys_pay, i)
assert_equal(addr_g, addr_r)
@@ -273,31 +297,51 @@ class WalletTaprootTest(BitcoinTestFramework):
to_amnt = random.randrange(1000000, boring_balance)
self.boring.sendtoaddress(address=addr_g, amount=Decimal(to_amnt) / 100000000, subtractfeefromamount=True)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- test_balance = int(self.rpc_online.getbalance() * 100000000)
+ test_balance = int(rpc_online.getbalance() * 100000000)
ret_amnt = random.randrange(100000, test_balance)
# Increase fee_rate to compensate for the wallet's inability to estimate fees for script path spends.
- res = self.rpc_online.sendtoaddress(address=self.boring.getnewaddress(), amount=Decimal(ret_amnt) / 100000000, subtractfeefromamount=True, fee_rate=200)
+ res = rpc_online.sendtoaddress(address=self.boring.getnewaddress(), amount=Decimal(ret_amnt) / 100000000, subtractfeefromamount=True, fee_rate=200)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- assert(self.rpc_online.gettransaction(res)["confirmations"] > 0)
+ assert(rpc_online.gettransaction(res)["confirmations"] > 0)
+
+ # Cleanup
+ txid = rpc_online.sendall(recipients=[self.boring.getnewaddress()])["txid"]
+ self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
+ assert(rpc_online.gettransaction(txid)["confirmations"] > 0)
+ rpc_online.unloadwallet()
def do_test_psbt(self, comment, pattern, privmap, treefn, keys_pay, keys_change):
self.log.info("Testing %s through PSBT" % comment)
+
+ # Create wallets
+ wallet_uuid = uuid.uuid4().hex
+ self.nodes[0].createwallet(wallet_name=f"psbt_online_{wallet_uuid}", descriptors=True, disable_private_keys=True, blank=True)
+ self.nodes[1].createwallet(wallet_name=f"psbt_offline_{wallet_uuid}", descriptors=True, blank=True)
+ self.nodes[1].createwallet(f"key_only_wallet_{wallet_uuid}", descriptors=True, blank=True)
+ psbt_online = self.nodes[0].get_wallet_rpc(f"psbt_online_{wallet_uuid}")
+ psbt_offline = self.nodes[1].get_wallet_rpc(f"psbt_offline_{wallet_uuid}")
+ key_only_wallet = self.nodes[1].get_wallet_rpc(f"key_only_wallet_{wallet_uuid}")
+
desc_pay = self.make_desc(pattern, privmap, keys_pay, False)
desc_change = self.make_desc(pattern, privmap, keys_change, False)
desc_pay_pub = self.make_desc(pattern, privmap, keys_pay, True)
desc_change_pub = self.make_desc(pattern, privmap, keys_change, True)
assert_equal(self.nodes[0].getdescriptorinfo(desc_pay)['descriptor'], desc_pay_pub)
assert_equal(self.nodes[0].getdescriptorinfo(desc_change)['descriptor'], desc_change_pub)
- result = self.psbt_online.importdescriptors([{"desc": desc_pay_pub, "active": True, "timestamp": "now"}])
+ result = psbt_online.importdescriptors([{"desc": desc_pay_pub, "active": True, "timestamp": "now"}])
assert(result[0]['success'])
- result = self.psbt_online.importdescriptors([{"desc": desc_change_pub, "active": True, "timestamp": "now", "internal": True}])
+ result = psbt_online.importdescriptors([{"desc": desc_change_pub, "active": True, "timestamp": "now", "internal": True}])
assert(result[0]['success'])
- result = self.psbt_offline.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
+ result = psbt_offline.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
assert(result[0]['success'])
- result = self.psbt_offline.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
+ result = psbt_offline.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
assert(result[0]['success'])
+ for key in keys_pay + keys_change:
+ result = key_only_wallet.importdescriptors([{"desc": descsum_create(f"wpkh({key['xprv']}/*)"), "timestamp":"now"}])
+ assert(result[0]["success"])
+ address_type = "bech32m" if "tr" in pattern else "bech32"
for i in range(4):
- addr_g = self.psbt_online.getnewaddress(address_type='bech32m')
+ addr_g = psbt_online.getnewaddress(address_type=address_type)
if treefn is not None:
addr_r = self.make_addr(treefn, keys_pay, i)
assert_equal(addr_g, addr_r)
@@ -305,28 +349,43 @@ class WalletTaprootTest(BitcoinTestFramework):
to_amnt = random.randrange(1000000, boring_balance)
self.boring.sendtoaddress(address=addr_g, amount=Decimal(to_amnt) / 100000000, subtractfeefromamount=True)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- test_balance = int(self.psbt_online.getbalance() * 100000000)
+ test_balance = int(psbt_online.getbalance() * 100000000)
ret_amnt = random.randrange(100000, test_balance)
# Increase fee_rate to compensate for the wallet's inability to estimate fees for script path spends.
- psbt = self.psbt_online.walletcreatefundedpsbt([], [{self.boring.getnewaddress(): Decimal(ret_amnt) / 100000000}], None, {"subtractFeeFromOutputs":[0], "fee_rate": 200, "change_type": "bech32m"})['psbt']
- res = self.psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
-
- decoded = self.psbt_offline.decodepsbt(res["psbt"])
- if pattern.startswith("tr("):
- for psbtin in decoded["inputs"]:
- assert "non_witness_utxo" not in psbtin
- assert "witness_utxo" in psbtin
- assert "taproot_internal_key" in psbtin
- assert "taproot_bip32_derivs" in psbtin
- assert "taproot_key_path_sig" in psbtin or "taproot_script_path_sigs" in psbtin
- if "taproot_script_path_sigs" in psbtin:
- assert "taproot_merkle_root" in psbtin
- assert "taproot_scripts" in psbtin
-
- rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
+ psbt = psbt_online.walletcreatefundedpsbt([], [{self.boring.getnewaddress(): Decimal(ret_amnt) / 100000000}], None, {"subtractFeeFromOutputs":[0], "fee_rate": 200, "change_type": address_type})['psbt']
+ res = psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
+ for wallet in [psbt_offline, key_only_wallet]:
+ res = wallet.walletprocesspsbt(psbt=psbt, finalize=False)
+
+ decoded = wallet.decodepsbt(res["psbt"])
+ if pattern.startswith("tr("):
+ for psbtin in decoded["inputs"]:
+ assert "non_witness_utxo" not in psbtin
+ assert "witness_utxo" in psbtin
+ assert "taproot_internal_key" in psbtin
+ assert "taproot_bip32_derivs" in psbtin
+ assert "taproot_key_path_sig" in psbtin or "taproot_script_path_sigs" in psbtin
+ if "taproot_script_path_sigs" in psbtin:
+ assert "taproot_merkle_root" in psbtin
+ assert "taproot_scripts" in psbtin
+
+ rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
+ res = self.nodes[0].testmempoolaccept([rawtx])
+ assert res[0]["allowed"]
+
txid = self.nodes[0].sendrawtransaction(rawtx)
self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- assert(self.psbt_online.gettransaction(txid)['confirmations'] > 0)
+ assert(psbt_online.gettransaction(txid)['confirmations'] > 0)
+
+ # Cleanup
+ psbt = psbt_online.sendall(recipients=[self.boring.getnewaddress()], options={"psbt": True})["psbt"]
+ res = psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
+ rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
+ txid = self.nodes[0].sendrawtransaction(rawtx)
+ self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
+ assert(psbt_online.gettransaction(txid)['confirmations'] > 0)
+ psbt_online.unloadwallet()
+ psbt_offline.unloadwallet()
def do_test(self, comment, pattern, privmap, treefn):
nkeys = len(privmap)
@@ -336,21 +395,8 @@ class WalletTaprootTest(BitcoinTestFramework):
self.do_test_psbt(comment, pattern, privmap, treefn, keys[2*nkeys:3*nkeys], keys[3*nkeys:4*nkeys])
def run_test(self):
- self.log.info("Creating wallets...")
- self.nodes[0].createwallet(wallet_name="privs_tr_enabled", descriptors=True, blank=True)
- self.privs_tr_enabled = self.nodes[0].get_wallet_rpc("privs_tr_enabled")
- self.nodes[0].createwallet(wallet_name="pubs_tr_enabled", descriptors=True, blank=True, disable_private_keys=True)
- self.pubs_tr_enabled = self.nodes[0].get_wallet_rpc("pubs_tr_enabled")
self.nodes[0].createwallet(wallet_name="boring")
- self.nodes[0].createwallet(wallet_name="addr_gen", descriptors=True, disable_private_keys=True, blank=True)
- self.nodes[0].createwallet(wallet_name="rpc_online", descriptors=True, blank=True)
- self.nodes[0].createwallet(wallet_name="psbt_online", descriptors=True, disable_private_keys=True, blank=True)
- self.nodes[1].createwallet(wallet_name="psbt_offline", descriptors=True, blank=True)
self.boring = self.nodes[0].get_wallet_rpc("boring")
- self.addr_gen = self.nodes[0].get_wallet_rpc("addr_gen")
- self.rpc_online = self.nodes[0].get_wallet_rpc("rpc_online")
- self.psbt_online = self.nodes[0].get_wallet_rpc("psbt_online")
- self.psbt_offline = self.nodes[1].get_wallet_rpc("psbt_offline")
self.log.info("Mining blocks...")
gen_addr = self.boring.getnewaddress()
@@ -460,18 +506,5 @@ class WalletTaprootTest(BitcoinTestFramework):
lambda k1: key(k1)
)
- self.log.info("Sending everything back...")
-
- txid = self.rpc_online.sendall(recipients=[self.boring.getnewaddress()])["txid"]
- self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- assert(self.rpc_online.gettransaction(txid)["confirmations"] > 0)
-
- psbt = self.psbt_online.sendall(recipients=[self.boring.getnewaddress()], options={"psbt": True})["psbt"]
- res = self.psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
- rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
- txid = self.nodes[0].sendrawtransaction(rawtx)
- self.generatetoaddress(self.nodes[0], 1, self.boring.getnewaddress(), sync_fun=self.no_op)
- assert(self.psbt_online.gettransaction(txid)['confirmations'] > 0)
-
if __name__ == '__main__':
WalletTaprootTest().main()