|
|
|
@ -8,6 +8,7 @@ from decimal import Decimal, getcontext
|
|
|
|
|
from itertools import product
|
|
|
|
|
|
|
|
|
|
from test_framework.authproxy import JSONRPCException
|
|
|
|
|
from test_framework.descriptors import descsum_create
|
|
|
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
|
|
|
from test_framework.util import (
|
|
|
|
|
assert_equal,
|
|
|
|
@ -168,49 +169,91 @@ class WalletSendTest(BitcoinTestFramework):
|
|
|
|
|
self.nodes[1].createwallet(wallet_name="w1")
|
|
|
|
|
w1 = self.nodes[1].get_wallet_rpc("w1")
|
|
|
|
|
# w2 contains the private keys for w3
|
|
|
|
|
self.nodes[1].createwallet(wallet_name="w2")
|
|
|
|
|
self.nodes[1].createwallet(wallet_name="w2", blank=True)
|
|
|
|
|
w2 = self.nodes[1].get_wallet_rpc("w2")
|
|
|
|
|
xpriv = "tprv8ZgxMBicQKsPfHCsTwkiM1KT56RXbGGTqvc2hgqzycpwbHqqpcajQeMRZoBD35kW4RtyCemu6j34Ku5DEspmgjKdt2qe4SvRch5Kk8B8A2v"
|
|
|
|
|
xpub = "tpubD6NzVbkrYhZ4YkEfMbRJkQyZe7wTkbTNRECozCtJPtdLRn6cT1QKb8yHjwAPcAr26eHBFYs5iLiFFnCbwPRsncCKUKCfubHDMGKzMVcN1Jg"
|
|
|
|
|
if self.options.descriptors:
|
|
|
|
|
w2.importdescriptors([{
|
|
|
|
|
"desc": descsum_create("wpkh(" + xpriv + "/0/0/*)"),
|
|
|
|
|
"timestamp": "now",
|
|
|
|
|
"range": [0, 100],
|
|
|
|
|
"active": True
|
|
|
|
|
},{
|
|
|
|
|
"desc": descsum_create("wpkh(" + xpriv + "/0/1/*)"),
|
|
|
|
|
"timestamp": "now",
|
|
|
|
|
"range": [0, 100],
|
|
|
|
|
"active": True,
|
|
|
|
|
"internal": True
|
|
|
|
|
}])
|
|
|
|
|
else:
|
|
|
|
|
w2.sethdseed(True)
|
|
|
|
|
|
|
|
|
|
# w3 is a watch-only wallet, based on w2
|
|
|
|
|
self.nodes[1].createwallet(wallet_name="w3", disable_private_keys=True)
|
|
|
|
|
w3 = self.nodes[1].get_wallet_rpc("w3")
|
|
|
|
|
for _ in range(3):
|
|
|
|
|
a2_receive = w2.getnewaddress()
|
|
|
|
|
a2_change = w2.getrawchangeaddress() # doesn't actually use change derivation
|
|
|
|
|
res = w3.importmulti([{
|
|
|
|
|
"desc": w2.getaddressinfo(a2_receive)["desc"],
|
|
|
|
|
if self.options.descriptors:
|
|
|
|
|
# Match the privkeys in w2 for descriptors
|
|
|
|
|
res = w3.importdescriptors([{
|
|
|
|
|
"desc": descsum_create("wpkh(" + xpub + "/0/0/*)"),
|
|
|
|
|
"timestamp": "now",
|
|
|
|
|
"range": [0, 100],
|
|
|
|
|
"keypool": True,
|
|
|
|
|
"active": True,
|
|
|
|
|
"watchonly": True
|
|
|
|
|
},{
|
|
|
|
|
"desc": w2.getaddressinfo(a2_change)["desc"],
|
|
|
|
|
"desc": descsum_create("wpkh(" + xpub + "/0/1/*)"),
|
|
|
|
|
"timestamp": "now",
|
|
|
|
|
"range": [0, 100],
|
|
|
|
|
"keypool": True,
|
|
|
|
|
"active": True,
|
|
|
|
|
"internal": True,
|
|
|
|
|
"watchonly": True
|
|
|
|
|
}])
|
|
|
|
|
assert_equal(res, [{"success": True}, {"success": True}])
|
|
|
|
|
|
|
|
|
|
w0.sendtoaddress(a2_receive, 10) # fund w3
|
|
|
|
|
self.nodes[0].generate(1)
|
|
|
|
|
self.sync_blocks()
|
|
|
|
|
|
|
|
|
|
# w4 has private keys enabled, but only contains watch-only keys (from w2)
|
|
|
|
|
self.nodes[1].createwallet(wallet_name="w4", disable_private_keys=False)
|
|
|
|
|
w4 = self.nodes[1].get_wallet_rpc("w4")
|
|
|
|
|
for _ in range(3):
|
|
|
|
|
a2_receive = w2.getnewaddress()
|
|
|
|
|
res = w4.importmulti([{
|
|
|
|
|
"desc": w2.getaddressinfo(a2_receive)["desc"],
|
|
|
|
|
"timestamp": "now",
|
|
|
|
|
"keypool": False,
|
|
|
|
|
"watchonly": True
|
|
|
|
|
}])
|
|
|
|
|
assert_equal(res, [{"success": True}])
|
|
|
|
|
if not self.options.descriptors:
|
|
|
|
|
# Because legacy wallets use exclusively hardened derivation, we can't do a ranged import like we do for descriptors
|
|
|
|
|
a2_change = w2.getrawchangeaddress() # doesn't actually use change derivation
|
|
|
|
|
res = w3.importmulti([{
|
|
|
|
|
"desc": w2.getaddressinfo(a2_receive)["desc"],
|
|
|
|
|
"timestamp": "now",
|
|
|
|
|
"keypool": True,
|
|
|
|
|
"watchonly": True
|
|
|
|
|
},{
|
|
|
|
|
"desc": w2.getaddressinfo(a2_change)["desc"],
|
|
|
|
|
"timestamp": "now",
|
|
|
|
|
"keypool": True,
|
|
|
|
|
"internal": True,
|
|
|
|
|
"watchonly": True
|
|
|
|
|
}])
|
|
|
|
|
assert_equal(res, [{"success": True}, {"success": True}])
|
|
|
|
|
|
|
|
|
|
w0.sendtoaddress(a2_receive, 10) # fund w4
|
|
|
|
|
w0.sendtoaddress(a2_receive, 10) # fund w3
|
|
|
|
|
self.nodes[0].generate(1)
|
|
|
|
|
self.sync_blocks()
|
|
|
|
|
|
|
|
|
|
if not self.options.descriptors:
|
|
|
|
|
# w4 has private keys enabled, but only contains watch-only keys (from w2)
|
|
|
|
|
# This is legacy wallet behavior only as descriptor wallets don't allow watchonly and non-watchonly things in the same wallet.
|
|
|
|
|
self.nodes[1].createwallet(wallet_name="w4", disable_private_keys=False)
|
|
|
|
|
w4 = self.nodes[1].get_wallet_rpc("w4")
|
|
|
|
|
for _ in range(3):
|
|
|
|
|
a2_receive = w2.getnewaddress()
|
|
|
|
|
res = w4.importmulti([{
|
|
|
|
|
"desc": w2.getaddressinfo(a2_receive)["desc"],
|
|
|
|
|
"timestamp": "now",
|
|
|
|
|
"keypool": False,
|
|
|
|
|
"watchonly": True
|
|
|
|
|
}])
|
|
|
|
|
assert_equal(res, [{"success": True}])
|
|
|
|
|
|
|
|
|
|
w0.sendtoaddress(a2_receive, 10) # fund w4
|
|
|
|
|
self.nodes[0].generate(1)
|
|
|
|
|
self.sync_blocks()
|
|
|
|
|
|
|
|
|
|
self.log.info("Send to address...")
|
|
|
|
|
self.test_send(from_wallet=w0, to_wallet=w1, amount=1)
|
|
|
|
|
self.test_send(from_wallet=w0, to_wallet=w1, amount=1, add_to_wallet=True)
|
|
|
|
@ -241,11 +284,15 @@ class WalletSendTest(BitcoinTestFramework):
|
|
|
|
|
res = w2.walletprocesspsbt(res["psbt"])
|
|
|
|
|
assert res["complete"]
|
|
|
|
|
|
|
|
|
|
self.log.info("Create PSBT from wallet w4 with watch-only keys, sign with w2...")
|
|
|
|
|
self.test_send(from_wallet=w4, to_wallet=w1, amount=1, expect_error=(-4, "Insufficient funds"))
|
|
|
|
|
res = self.test_send(from_wallet=w4, to_wallet=w1, amount=1, include_watching=True, add_to_wallet=False)
|
|
|
|
|
res = w2.walletprocesspsbt(res["psbt"])
|
|
|
|
|
assert res["complete"]
|
|
|
|
|
if not self.options.descriptors:
|
|
|
|
|
# Descriptor wallets do not allow mixed watch-only and non-watch-only things in the same wallet.
|
|
|
|
|
# This is specifically testing that w4 ignores its own private keys and creates a psbt with send
|
|
|
|
|
# which is not something that needs to be tested in descriptor wallets.
|
|
|
|
|
self.log.info("Create PSBT from wallet w4 with watch-only keys, sign with w2...")
|
|
|
|
|
self.test_send(from_wallet=w4, to_wallet=w1, amount=1, expect_error=(-4, "Insufficient funds"))
|
|
|
|
|
res = self.test_send(from_wallet=w4, to_wallet=w1, amount=1, include_watching=True, add_to_wallet=False)
|
|
|
|
|
res = w2.walletprocesspsbt(res["psbt"])
|
|
|
|
|
assert res["complete"]
|
|
|
|
|
|
|
|
|
|
self.log.info("Create OP_RETURN...")
|
|
|
|
|
self.test_send(from_wallet=w0, to_wallet=w1, amount=1)
|
|
|
|
|