Skip to content

Commit c0f0c8e

Browse files
committed
tests: check spending of P2TR
1 parent a238012 commit c0f0c8e

File tree

1 file changed

+116
-10
lines changed

1 file changed

+116
-10
lines changed

test/functional/wallet_taproot.py

Lines changed: 116 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import random
88

9+
from decimal import Decimal
910
from test_framework.test_framework import BitcoinTestFramework
1011
from test_framework.util import assert_equal
1112
from test_framework.descriptors import descsum_create
@@ -233,20 +234,85 @@ def do_test_addr(self, comment, pattern, privmap, treefn, keys):
233234
# tr descriptors cannot be imported when Taproot is not active
234235
result = self.privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
235236
assert(result[0]["success"])
236-
result = self.privs_tr_disabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
237-
assert(not result[0]["success"])
238-
assert_equal(result[0]["error"]["code"], -4)
239-
assert_equal(result[0]["error"]["message"], "Cannot import tr() descriptor when Taproot is not active")
240237
result = self.pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
241238
assert(result[0]["success"])
242-
result = self.pubs_tr_disabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
243-
assert(not result[0]["success"])
244-
assert_equal(result[0]["error"]["code"], -4)
245-
assert_equal(result[0]["error"]["message"], "Cannot import tr() descriptor when Taproot is not active")
239+
if desc.startswith("tr"):
240+
result = self.privs_tr_disabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
241+
assert(not result[0]["success"])
242+
assert_equal(result[0]["error"]["code"], -4)
243+
assert_equal(result[0]["error"]["message"], "Cannot import tr() descriptor when Taproot is not active")
244+
result = self.pubs_tr_disabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
245+
assert(not result[0]["success"])
246+
assert_equal(result[0]["error"]["code"], -4)
247+
assert_equal(result[0]["error"]["message"], "Cannot import tr() descriptor when Taproot is not active")
248+
249+
def do_test_sendtoaddress(self, comment, pattern, privmap, treefn, keys_pay, keys_change):
250+
self.log.info("Testing %s through sendtoaddress" % comment)
251+
desc_pay = self.make_desc(pattern, privmap, keys_pay)
252+
desc_change = self.make_desc(pattern, privmap, keys_change)
253+
desc_pay_pub = self.make_desc(pattern, privmap, keys_pay, True)
254+
desc_change_pub = self.make_desc(pattern, privmap, keys_change, True)
255+
assert_equal(self.nodes[0].getdescriptorinfo(desc_pay)['descriptor'], desc_pay_pub)
256+
assert_equal(self.nodes[0].getdescriptorinfo(desc_change)['descriptor'], desc_change_pub)
257+
result = self.rpc_online.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
258+
assert(result[0]['success'])
259+
result = self.rpc_online.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
260+
assert(result[0]['success'])
261+
for i in range(4):
262+
addr_g = self.rpc_online.getnewaddress(address_type='bech32')
263+
if treefn is not None:
264+
addr_r = self.make_addr(treefn, keys_pay, i)
265+
assert_equal(addr_g, addr_r)
266+
boring_balance = int(self.boring.getbalance() * 100000000)
267+
to_amnt = random.randrange(1000000, boring_balance)
268+
self.boring.sendtoaddress(address=addr_g, amount=Decimal(to_amnt) / 100000000, subtractfeefromamount=True)
269+
self.nodes[0].generatetoaddress(1, self.boring.getnewaddress())
270+
test_balance = int(self.rpc_online.getbalance() * 100000000)
271+
ret_amnt = random.randrange(100000, test_balance)
272+
res = self.rpc_online.sendtoaddress(address=self.boring.getnewaddress(), amount=Decimal(ret_amnt) / 100000000, subtractfeefromamount=True)
273+
self.nodes[0].generatetoaddress(1, self.boring.getnewaddress())
274+
assert(self.rpc_online.gettransaction(res)["confirmations"] > 0)
275+
276+
def do_test_psbt(self, comment, pattern, privmap, treefn, keys_pay, keys_change):
277+
self.log.info("Testing %s through PSBT" % comment)
278+
desc_pay = self.make_desc(pattern, privmap, keys_pay, False)
279+
desc_change = self.make_desc(pattern, privmap, keys_change, False)
280+
desc_pay_pub = self.make_desc(pattern, privmap, keys_pay, True)
281+
desc_change_pub = self.make_desc(pattern, privmap, keys_change, True)
282+
assert_equal(self.nodes[0].getdescriptorinfo(desc_pay)['descriptor'], desc_pay_pub)
283+
assert_equal(self.nodes[0].getdescriptorinfo(desc_change)['descriptor'], desc_change_pub)
284+
result = self.psbt_online.importdescriptors([{"desc": desc_pay_pub, "active": True, "timestamp": "now"}])
285+
assert(result[0]['success'])
286+
result = self.psbt_online.importdescriptors([{"desc": desc_change_pub, "active": True, "timestamp": "now", "internal": True}])
287+
assert(result[0]['success'])
288+
result = self.psbt_offline.importdescriptors([{"desc": desc_pay, "active": True, "timestamp": "now"}])
289+
assert(result[0]['success'])
290+
result = self.psbt_offline.importdescriptors([{"desc": desc_change, "active": True, "timestamp": "now", "internal": True}])
291+
assert(result[0]['success'])
292+
for i in range(4):
293+
addr_g = self.psbt_online.getnewaddress(address_type='bech32')
294+
if treefn is not None:
295+
addr_r = self.make_addr(treefn, keys_pay, i)
296+
assert_equal(addr_g, addr_r)
297+
boring_balance = int(self.boring.getbalance() * 100000000)
298+
to_amnt = random.randrange(1000000, boring_balance)
299+
self.boring.sendtoaddress(address=addr_g, amount=Decimal(to_amnt) / 100000000, subtractfeefromamount=True)
300+
self.nodes[0].generatetoaddress(1, self.boring.getnewaddress())
301+
test_balance = int(self.psbt_online.getbalance() * 100000000)
302+
ret_amnt = random.randrange(100000, test_balance)
303+
psbt = self.psbt_online.walletcreatefundedpsbt([], [{self.boring.getnewaddress(): Decimal(ret_amnt) / 100000000}], None, {"subtractFeeFromOutputs":[0]})['psbt']
304+
res = self.psbt_offline.walletprocesspsbt(psbt)
305+
assert(res['complete'])
306+
rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
307+
txid = self.nodes[0].sendrawtransaction(rawtx)
308+
self.nodes[0].generatetoaddress(1, self.boring.getnewaddress())
309+
assert(self.psbt_online.gettransaction(txid)['confirmations'] > 0)
246310

247311
def do_test(self, comment, pattern, privmap, treefn, nkeys):
248-
keys = self.rand_keys(nkeys)
249-
self.do_test_addr(comment, pattern, privmap, treefn, keys)
312+
keys = self.rand_keys(nkeys * 4)
313+
self.do_test_addr(comment, pattern, privmap, treefn, keys[0:nkeys])
314+
self.do_test_sendtoaddress(comment, pattern, privmap, treefn, keys[0:nkeys], keys[nkeys:2*nkeys])
315+
self.do_test_psbt(comment, pattern, privmap, treefn, keys[2*nkeys:3*nkeys], keys[3*nkeys:4*nkeys])
250316

251317
def run_test(self):
252318
self.log.info("Creating wallets...")
@@ -258,8 +324,20 @@ def run_test(self):
258324
self.pubs_tr_enabled = self.nodes[0].get_wallet_rpc("pubs_tr_enabled")
259325
self.nodes[2].createwallet(wallet_name="pubs_tr_disabled", descriptors=True, blank=True, disable_private_keys=True)
260326
self.pubs_tr_disabled=self.nodes[2].get_wallet_rpc("pubs_tr_disabled")
327+
self.nodes[0].createwallet(wallet_name="boring")
261328
self.nodes[0].createwallet(wallet_name="addr_gen", descriptors=True, disable_private_keys=True, blank=True)
329+
self.nodes[0].createwallet(wallet_name="rpc_online", descriptors=True, blank=True)
330+
self.nodes[0].createwallet(wallet_name="psbt_online", descriptors=True, disable_private_keys=True, blank=True)
331+
self.nodes[1].createwallet(wallet_name="psbt_offline", descriptors=True, blank=True)
332+
self.boring = self.nodes[0].get_wallet_rpc("boring")
262333
self.addr_gen = self.nodes[0].get_wallet_rpc("addr_gen")
334+
self.rpc_online = self.nodes[0].get_wallet_rpc("rpc_online")
335+
self.psbt_online = self.nodes[0].get_wallet_rpc("psbt_online")
336+
self.psbt_offline = self.nodes[1].get_wallet_rpc("psbt_offline")
337+
338+
self.log.info("Mining blocks...")
339+
gen_addr = self.boring.getnewaddress()
340+
self.nodes[0].generatetoaddress(101, gen_addr)
263341

264342
self.do_test(
265343
"tr(XPRV)",
@@ -275,13 +353,27 @@ def run_test(self):
275353
lambda k1: (key(H_POINT), [pk(k1)]),
276354
1
277355
)
356+
self.do_test(
357+
"wpkh(XPRV)",
358+
"wpkh($1/*)",
359+
[True],
360+
None,
361+
1
362+
)
278363
self.do_test(
279364
"tr(XPRV,{H,{H,XPUB}})",
280365
"tr($1/*,{pk($H),{pk($H),pk($2/*)}})",
281366
[True, False],
282367
lambda k1, k2: (key(k1), [pk(H_POINT), [pk(H_POINT), pk(k2)]]),
283368
2
284369
)
370+
self.do_test(
371+
"wsh(multi(1,XPRV,XPUB))",
372+
"wsh(multi(1,$1/*,$2/*))",
373+
[True, False],
374+
None,
375+
2
376+
)
285377
self.do_test(
286378
"tr(XPUB,{{H,{H,XPUB}},{H,{H,{H,XPRV}}}})",
287379
"tr($1/*,{{pk($H),{pk($H),pk($2/*)}},{pk($H),{pk($H),{pk($H),pk($3/*)}}}})",
@@ -290,5 +382,19 @@ def run_test(self):
290382
3
291383
)
292384

385+
self.log.info("Sending everything back...")
386+
387+
txid = self.rpc_online.sendtoaddress(address=self.boring.getnewaddress(), amount=self.rpc_online.getbalance(), subtractfeefromamount=True)
388+
self.nodes[0].generatetoaddress(1, self.boring.getnewaddress())
389+
assert(self.rpc_online.gettransaction(txid)["confirmations"] > 0)
390+
391+
psbt = self.psbt_online.walletcreatefundedpsbt([], [{self.boring.getnewaddress(): self.psbt_online.getbalance()}], None, {"subtractFeeFromOutputs": [0]})['psbt']
392+
res = self.psbt_offline.walletprocesspsbt(psbt)
393+
assert(res['complete'])
394+
rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
395+
txid = self.nodes[0].sendrawtransaction(rawtx)
396+
self.nodes[0].generatetoaddress(1, self.boring.getnewaddress())
397+
assert(self.psbt_online.gettransaction(txid)['confirmations'] > 0)
398+
293399
if __name__ == '__main__':
294400
WalletTaprootTest().main()

0 commit comments

Comments
 (0)