aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional')
-rwxr-xr-xtest/functional/feature_filelock.py2
-rwxr-xr-xtest/functional/feature_rbf.py2
-rwxr-xr-xtest/functional/feature_segwit.py595
-rwxr-xr-xtest/functional/interface_rest.py9
-rwxr-xr-xtest/functional/mempool_packages.py3
-rwxr-xr-xtest/functional/mining_prioritisetransaction.py2
-rwxr-xr-xtest/functional/p2p_invalid_messages.py2
-rwxr-xr-xtest/functional/p2p_ping.py14
-rwxr-xr-xtest/functional/p2p_segwit.py60
-rwxr-xr-xtest/functional/rpc_blockchain.py66
-rwxr-xr-xtest/functional/rpc_invalid_address_message.py2
-rwxr-xr-xtest/functional/test_framework/test_framework.py8
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/functional/tool_wallet.py6
-rwxr-xr-xtest/functional/wallet_abandonconflict.py2
-rwxr-xr-xtest/functional/wallet_address_types.py3
-rwxr-xr-xtest/functional/wallet_backup.py6
-rwxr-xr-xtest/functional/wallet_basic.py2
-rwxr-xr-xtest/functional/wallet_bumpfee.py10
-rwxr-xr-xtest/functional/wallet_create_tx.py4
-rwxr-xr-xtest/functional/wallet_hd.py2
-rwxr-xr-xtest/functional/wallet_import_rescan.py2
-rwxr-xr-xtest/functional/wallet_importdescriptors.py12
-rwxr-xr-xtest/functional/wallet_listdescriptors.py2
-rwxr-xr-xtest/functional/wallet_listsinceblock.py11
-rwxr-xr-xtest/functional/wallet_listtransactions.py13
-rwxr-xr-xtest/functional/wallet_multisig_descriptor_psbt.py8
-rwxr-xr-xtest/functional/wallet_multiwallet.py4
-rwxr-xr-xtest/functional/wallet_taproot.py2
29 files changed, 493 insertions, 362 deletions
diff --git a/test/functional/feature_filelock.py b/test/functional/feature_filelock.py
index e09107802b..0fc654e10a 100755
--- a/test/functional/feature_filelock.py
+++ b/test/functional/feature_filelock.py
@@ -35,7 +35,7 @@ class FilelockTest(BitcoinTestFramework):
wallet_dir = os.path.join(datadir, 'wallets')
self.log.info("Check that we can't start a second bitcoind instance using the same wallet")
if descriptors:
- expected_msg = "Error: SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another bitcoind?"
+ expected_msg = f"Error: SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another instance of {self.config['environment']['PACKAGE_NAME']}?"
else:
expected_msg = "Error: Error initializing wallet database environment"
self.nodes[1].assert_start_raises_init_error(extra_args=[f'-walletdir={wallet_dir}', f'-wallet={wallet_name}', '-noserver'], expected_msg=expected_msg, match=ErrorMatch.PARTIAL_REGEX)
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index 4eaaf46454..420147542e 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -539,7 +539,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert_equal(json1["vin"][0]["sequence"], 4294967295)
if self.is_wallet_compiled():
- self.init_wallet(0)
+ self.init_wallet(node=0)
rawtx2 = self.nodes[0].createrawtransaction([], outs)
frawtx2a = self.nodes[0].fundrawtransaction(rawtx2, {"replaceable": True})
frawtx2b = self.nodes[0].fundrawtransaction(rawtx2, {"replaceable": False})
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index 2f9ab34e99..5abe989e55 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -17,6 +17,7 @@ from test_framework.blocktools import (
send_to_witness,
witness_script,
)
+from test_framework.descriptors import descsum_create
from test_framework.messages import (
COIN,
COutPoint,
@@ -49,6 +50,9 @@ from test_framework.util import (
assert_raises_rpc_error,
try_rpc,
)
+from test_framework.wallet_util import (
+ get_generate_key,
+)
NODE_0 = 0
NODE_2 = 2
@@ -142,13 +146,39 @@ class SegWitTest(BitcoinTestFramework):
p2sh_ids = [] # p2sh_ids[NODE][TYPE] is an array of txids that spend to P2WPKH (TYPE=0) or P2WSH (TYPE=1) scripts to an address for NODE embedded in p2sh
wit_ids = [] # wit_ids[NODE][TYPE] is an array of txids that spend to P2WPKH (TYPE=0) or P2WSH (TYPE=1) scripts to an address for NODE via bare witness
for i in range(3):
- newaddress = self.nodes[i].getnewaddress()
- self.pubkey.append(self.nodes[i].getaddressinfo(newaddress)["pubkey"])
+ key = get_generate_key()
+ self.pubkey.append(key.pubkey)
+
multiscript = CScript([OP_1, bytes.fromhex(self.pubkey[-1]), OP_1, OP_CHECKMULTISIG])
- p2sh_ms_addr = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]], '', 'p2sh-segwit')['address']
- bip173_ms_addr = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]], '', 'bech32')['address']
+ p2sh_ms_addr = self.nodes[i].createmultisig(1, [self.pubkey[-1]], 'p2sh-segwit')['address']
+ bip173_ms_addr = self.nodes[i].createmultisig(1, [self.pubkey[-1]], 'bech32')['address']
assert_equal(p2sh_ms_addr, script_to_p2sh_p2wsh(multiscript))
assert_equal(bip173_ms_addr, script_to_p2wsh(multiscript))
+
+ p2sh_ms_desc = descsum_create(f"sh(wsh(multi(1,{key.privkey})))")
+ bip173_ms_desc = descsum_create(f"wsh(multi(1,{key.privkey}))")
+ assert_equal(self.nodes[i].deriveaddresses(p2sh_ms_desc)[0], p2sh_ms_addr)
+ assert_equal(self.nodes[i].deriveaddresses(bip173_ms_desc)[0], bip173_ms_addr)
+
+ sh_wpkh_desc = descsum_create(f"sh(wpkh({key.privkey}))")
+ wpkh_desc = descsum_create(f"wpkh({key.privkey})")
+ assert_equal(self.nodes[i].deriveaddresses(sh_wpkh_desc)[0], key.p2sh_p2wpkh_addr)
+ assert_equal(self.nodes[i].deriveaddresses(wpkh_desc)[0], key.p2wpkh_addr)
+
+ if self.options.descriptors:
+ res = self.nodes[i].importdescriptors([
+ {"desc": p2sh_ms_desc, "timestamp": "now"},
+ {"desc": bip173_ms_desc, "timestamp": "now"},
+ {"desc": sh_wpkh_desc, "timestamp": "now"},
+ {"desc": wpkh_desc, "timestamp": "now"},
+ ])
+ else:
+ # The nature of the legacy wallet is that this import results in also adding all of the necessary scripts
+ res = self.nodes[i].importmulti([
+ {"desc": p2sh_ms_desc, "timestamp": "now"},
+ ])
+ assert all([r["success"] for r in res])
+
p2sh_ids.append([])
wit_ids.append([])
for _ in range(2):
@@ -311,284 +341,285 @@ class SegWitTest(BitcoinTestFramework):
# Mine a block to clear the gbt cache again.
self.generate(self.nodes[0], 1)
- self.log.info("Verify behaviour of importaddress and listunspent")
-
- # Some public keys to be used later
- pubkeys = [
- "0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242", # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb
- "02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF", # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97
- "04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E", # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV
- "02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538", # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd
- "036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228", # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66
- "0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC", # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K
- "0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84", # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ
- ]
-
- # Import a compressed key and an uncompressed key, generate some multisig addresses
- self.nodes[0].importprivkey("92e6XLo5jVAVwrQKPNTs93oQco8f8sDNBcpv73Dsrs397fQtFQn")
- uncompressed_spendable_address = ["mvozP4UwyGD2mGZU4D2eMvMLPB9WkMmMQu"]
- self.nodes[0].importprivkey("cNC8eQ5dg3mFAVePDX4ddmPYpPbw41r9bm2jd1nLJT77e6RrzTRR")
- compressed_spendable_address = ["mmWQubrDomqpgSYekvsU7HWEVjLFHAakLe"]
- assert not self.nodes[0].getaddressinfo(uncompressed_spendable_address[0])['iscompressed']
- assert self.nodes[0].getaddressinfo(compressed_spendable_address[0])['iscompressed']
-
- self.nodes[0].importpubkey(pubkeys[0])
- compressed_solvable_address = [key_to_p2pkh(pubkeys[0])]
- self.nodes[0].importpubkey(pubkeys[1])
- compressed_solvable_address.append(key_to_p2pkh(pubkeys[1]))
- self.nodes[0].importpubkey(pubkeys[2])
- uncompressed_solvable_address = [key_to_p2pkh(pubkeys[2])]
-
- spendable_anytime = [] # These outputs should be seen anytime after importprivkey and addmultisigaddress
- spendable_after_importaddress = [] # These outputs should be seen after importaddress
- solvable_after_importaddress = [] # These outputs should be seen after importaddress but not spendable
- unsolvable_after_importaddress = [] # These outputs should be unsolvable after importaddress
- solvable_anytime = [] # These outputs should be solvable after importpubkey
- unseen_anytime = [] # These outputs should never be seen
-
- uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], compressed_spendable_address[0]])['address'])
- uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], uncompressed_spendable_address[0]])['address'])
- compressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_spendable_address[0]])['address'])
- uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], uncompressed_solvable_address[0]])['address'])
- compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]])['address'])
- compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], compressed_solvable_address[1]])['address'])
-
- # Test multisig_without_privkey
- # We have 2 public keys without private keys, use addmultisigaddress to add to wallet.
- # Money sent to P2SH of multisig of this should only be seen after importaddress with the BASE58 P2SH address.
-
- multisig_without_privkey_address = self.nodes[0].addmultisigaddress(2, [pubkeys[3], pubkeys[4]])['address']
- script = CScript([OP_2, bytes.fromhex(pubkeys[3]), bytes.fromhex(pubkeys[4]), OP_2, OP_CHECKMULTISIG])
- solvable_after_importaddress.append(script_to_p2sh_script(script))
-
- for i in compressed_spendable_address:
- v = self.nodes[0].getaddressinfo(i)
- if v['isscript']:
- [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
- # p2sh multisig with compressed keys should always be spendable
- spendable_anytime.extend([p2sh])
- # bare multisig can be watched and signed, but is not treated as ours
- solvable_after_importaddress.extend([bare])
- # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after direct importaddress
- spendable_after_importaddress.extend([p2wsh, p2sh_p2wsh])
- else:
- [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
- # normal P2PKH and P2PK with compressed keys should always be spendable
- spendable_anytime.extend([p2pkh, p2pk])
- # P2SH_P2PK, P2SH_P2PKH with compressed keys are spendable after direct importaddress
- spendable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
- # P2WPKH and P2SH_P2WPKH with compressed keys should always be spendable
- spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])
-
- for i in uncompressed_spendable_address:
- v = self.nodes[0].getaddressinfo(i)
- if v['isscript']:
- [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
- # p2sh multisig with uncompressed keys should always be spendable
- spendable_anytime.extend([p2sh])
- # bare multisig can be watched and signed, but is not treated as ours
- solvable_after_importaddress.extend([bare])
- # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
- unseen_anytime.extend([p2wsh, p2sh_p2wsh])
- else:
- [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
- # normal P2PKH and P2PK with uncompressed keys should always be spendable
- spendable_anytime.extend([p2pkh, p2pk])
- # P2SH_P2PK and P2SH_P2PKH are spendable after direct importaddress
- spendable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])
- # Witness output types with uncompressed keys are never seen
- unseen_anytime.extend([p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
-
- for i in compressed_solvable_address:
- v = self.nodes[0].getaddressinfo(i)
- if v['isscript']:
- # Multisig without private is not seen after addmultisigaddress, but seen after importaddress
- [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
- solvable_after_importaddress.extend([bare, p2sh, p2wsh, p2sh_p2wsh])
- else:
- [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
- # normal P2PKH, P2PK, P2WPKH and P2SH_P2WPKH with compressed keys should always be seen
- solvable_anytime.extend([p2pkh, p2pk, p2wpkh, p2sh_p2wpkh])
- # P2SH_P2PK, P2SH_P2PKH with compressed keys are seen after direct importaddress
- solvable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
-
- for i in uncompressed_solvable_address:
- v = self.nodes[0].getaddressinfo(i)
- if v['isscript']:
- [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
- # Base uncompressed multisig without private is not seen after addmultisigaddress, but seen after importaddress
- solvable_after_importaddress.extend([bare, p2sh])
- # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
- unseen_anytime.extend([p2wsh, p2sh_p2wsh])
- else:
- [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
- # normal P2PKH and P2PK with uncompressed keys should always be seen
- solvable_anytime.extend([p2pkh, p2pk])
- # P2SH_P2PK, P2SH_P2PKH with uncompressed keys are seen after direct importaddress
- solvable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])
- # Witness output types with uncompressed keys are never seen
- unseen_anytime.extend([p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
-
- op1 = CScript([OP_1])
- op0 = CScript([OP_0])
- # 2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe is the P2SH(P2PKH) version of mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V
- unsolvable_address_key = bytes.fromhex("02341AEC7587A51CDE5279E0630A531AEA2615A9F80B17E8D9376327BAEAA59E3D")
- unsolvablep2pkh = key_to_p2pkh_script(unsolvable_address_key)
- unsolvablep2wshp2pkh = script_to_p2wsh_script(unsolvablep2pkh)
- p2shop0 = script_to_p2sh_script(op0)
- p2wshop1 = script_to_p2wsh_script(op1)
- unsolvable_after_importaddress.append(unsolvablep2pkh)
- unsolvable_after_importaddress.append(unsolvablep2wshp2pkh)
- unsolvable_after_importaddress.append(op1) # OP_1 will be imported as script
- unsolvable_after_importaddress.append(p2wshop1)
- unseen_anytime.append(op0) # OP_0 will be imported as P2SH address with no script provided
- unsolvable_after_importaddress.append(p2shop0)
-
- spendable_txid = []
- solvable_txid = []
- spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime, 2))
- solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime, 1))
- self.mine_and_test_listunspent(spendable_after_importaddress + solvable_after_importaddress + unseen_anytime + unsolvable_after_importaddress, 0)
-
- importlist = []
- for i in compressed_spendable_address + uncompressed_spendable_address + compressed_solvable_address + uncompressed_solvable_address:
- v = self.nodes[0].getaddressinfo(i)
- if v['isscript']:
- bare = bytes.fromhex(v['hex'])
- importlist.append(bare.hex())
- importlist.append(script_to_p2wsh_script(bare).hex())
- else:
- pubkey = bytes.fromhex(v['pubkey'])
- p2pk = key_to_p2pk_script(pubkey)
- p2pkh = key_to_p2pkh_script(pubkey)
- importlist.append(p2pk.hex())
- importlist.append(p2pkh.hex())
- importlist.append(key_to_p2wpkh_script(pubkey).hex())
- importlist.append(script_to_p2wsh_script(p2pk).hex())
- importlist.append(script_to_p2wsh_script(p2pkh).hex())
-
- importlist.append(unsolvablep2pkh.hex())
- importlist.append(unsolvablep2wshp2pkh.hex())
- importlist.append(op1.hex())
- importlist.append(p2wshop1.hex())
-
- for i in importlist:
- # import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC
- # exceptions and continue.
- try_rpc(-4, "The wallet already contains the private key for this address or script", self.nodes[0].importaddress, i, "", False, True)
-
- self.nodes[0].importaddress(script_to_p2sh(op0)) # import OP_0 as address only
- self.nodes[0].importaddress(multisig_without_privkey_address) # Test multisig_without_privkey
-
- spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2))
- solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1))
- self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
- self.mine_and_test_listunspent(unseen_anytime, 0)
-
- spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2))
- solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1))
- self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
- self.mine_and_test_listunspent(unseen_anytime, 0)
-
- # Repeat some tests. This time we don't add witness scripts with importaddress
- # Import a compressed key and an uncompressed key, generate some multisig addresses
- self.nodes[0].importprivkey("927pw6RW8ZekycnXqBQ2JS5nPyo1yRfGNN8oq74HeddWSpafDJH")
- uncompressed_spendable_address = ["mguN2vNSCEUh6rJaXoAVwY3YZwZvEmf5xi"]
- self.nodes[0].importprivkey("cMcrXaaUC48ZKpcyydfFo8PxHAjpsYLhdsp6nmtB3E2ER9UUHWnw")
- compressed_spendable_address = ["n1UNmpmbVUJ9ytXYXiurmGPQ3TRrXqPWKL"]
-
- self.nodes[0].importpubkey(pubkeys[5])
- compressed_solvable_address = [key_to_p2pkh(pubkeys[5])]
- self.nodes[0].importpubkey(pubkeys[6])
- uncompressed_solvable_address = [key_to_p2pkh(pubkeys[6])]
-
- unseen_anytime = [] # These outputs should never be seen
- solvable_anytime = [] # These outputs should be solvable after importpubkey
- unseen_anytime = [] # These outputs should never be seen
-
- uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], compressed_spendable_address[0]])['address'])
- uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], uncompressed_spendable_address[0]])['address'])
- compressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_spendable_address[0]])['address'])
- uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], uncompressed_solvable_address[0]])['address'])
- compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]])['address'])
-
- premature_witaddress = []
-
- for i in compressed_spendable_address:
- v = self.nodes[0].getaddressinfo(i)
- if v['isscript']:
- [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
- premature_witaddress.append(script_to_p2sh(p2wsh))
- else:
- [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
- # P2WPKH, P2SH_P2WPKH are always spendable
- spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])
-
- for i in uncompressed_spendable_address + uncompressed_solvable_address:
- v = self.nodes[0].getaddressinfo(i)
- if v['isscript']:
- [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
- # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
- unseen_anytime.extend([p2wsh, p2sh_p2wsh])
- else:
- [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
- # P2WPKH, P2SH_P2WPKH with uncompressed keys are never seen
- unseen_anytime.extend([p2wpkh, p2sh_p2wpkh])
-
- for i in compressed_solvable_address:
- v = self.nodes[0].getaddressinfo(i)
- if v['isscript']:
- [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
- premature_witaddress.append(script_to_p2sh(p2wsh))
- else:
- [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
- # P2SH_P2PK, P2SH_P2PKH with compressed keys are always solvable
- solvable_anytime.extend([p2wpkh, p2sh_p2wpkh])
-
- self.mine_and_test_listunspent(spendable_anytime, 2)
- self.mine_and_test_listunspent(solvable_anytime, 1)
- self.mine_and_test_listunspent(unseen_anytime, 0)
-
- # Check that createrawtransaction/decoderawtransaction with non-v0 Bech32 works
- v1_addr = program_to_witness(1, [3, 5])
- v1_tx = self.nodes[0].createrawtransaction([getutxo(spendable_txid[0])], {v1_addr: 1})
- v1_decoded = self.nodes[1].decoderawtransaction(v1_tx)
- assert_equal(v1_decoded['vout'][0]['scriptPubKey']['address'], v1_addr)
- assert_equal(v1_decoded['vout'][0]['scriptPubKey']['hex'], "51020305")
-
- # Check that spendable outputs are really spendable
- self.create_and_mine_tx_from_txids(spendable_txid)
-
- # import all the private keys so solvable addresses become spendable
- self.nodes[0].importprivkey("cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb")
- self.nodes[0].importprivkey("cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97")
- self.nodes[0].importprivkey("91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV")
- self.nodes[0].importprivkey("cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd")
- self.nodes[0].importprivkey("cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66")
- self.nodes[0].importprivkey("cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K")
- self.create_and_mine_tx_from_txids(solvable_txid)
-
- # Test that importing native P2WPKH/P2WSH scripts works
- for use_p2wsh in [False, True]:
- if use_p2wsh:
- scriptPubKey = "00203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a"
- transaction = "01000000000100e1f505000000002200203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a00000000"
- else:
- scriptPubKey = "a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d87"
- transaction = "01000000000100e1f5050000000017a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d8700000000"
-
- self.nodes[1].importaddress(scriptPubKey, "", False)
- rawtxfund = self.nodes[1].fundrawtransaction(transaction)['hex']
- rawtxfund = self.nodes[1].signrawtransactionwithwallet(rawtxfund)["hex"]
- txid = self.nodes[1].sendrawtransaction(rawtxfund)
-
- assert_equal(self.nodes[1].gettransaction(txid, True)["txid"], txid)
- assert_equal(self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"], txid)
-
- # Assert it is properly saved
- self.restart_node(1)
- assert_equal(self.nodes[1].gettransaction(txid, True)["txid"], txid)
- assert_equal(self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"], txid)
+ if not self.options.descriptors:
+ self.log.info("Verify behaviour of importaddress and listunspent")
+
+ # Some public keys to be used later
+ pubkeys = [
+ "0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242", # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb
+ "02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF", # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97
+ "04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E", # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV
+ "02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538", # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd
+ "036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228", # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66
+ "0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC", # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K
+ "0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84", # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ
+ ]
+
+ # Import a compressed key and an uncompressed key, generate some multisig addresses
+ self.nodes[0].importprivkey("92e6XLo5jVAVwrQKPNTs93oQco8f8sDNBcpv73Dsrs397fQtFQn")
+ uncompressed_spendable_address = ["mvozP4UwyGD2mGZU4D2eMvMLPB9WkMmMQu"]
+ self.nodes[0].importprivkey("cNC8eQ5dg3mFAVePDX4ddmPYpPbw41r9bm2jd1nLJT77e6RrzTRR")
+ compressed_spendable_address = ["mmWQubrDomqpgSYekvsU7HWEVjLFHAakLe"]
+ assert not self.nodes[0].getaddressinfo(uncompressed_spendable_address[0])['iscompressed']
+ assert self.nodes[0].getaddressinfo(compressed_spendable_address[0])['iscompressed']
+
+ self.nodes[0].importpubkey(pubkeys[0])
+ compressed_solvable_address = [key_to_p2pkh(pubkeys[0])]
+ self.nodes[0].importpubkey(pubkeys[1])
+ compressed_solvable_address.append(key_to_p2pkh(pubkeys[1]))
+ self.nodes[0].importpubkey(pubkeys[2])
+ uncompressed_solvable_address = [key_to_p2pkh(pubkeys[2])]
+
+ spendable_anytime = [] # These outputs should be seen anytime after importprivkey and addmultisigaddress
+ spendable_after_importaddress = [] # These outputs should be seen after importaddress
+ solvable_after_importaddress = [] # These outputs should be seen after importaddress but not spendable
+ unsolvable_after_importaddress = [] # These outputs should be unsolvable after importaddress
+ solvable_anytime = [] # These outputs should be solvable after importpubkey
+ unseen_anytime = [] # These outputs should never be seen
+
+ uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], compressed_spendable_address[0]])['address'])
+ uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], uncompressed_spendable_address[0]])['address'])
+ compressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_spendable_address[0]])['address'])
+ uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], uncompressed_solvable_address[0]])['address'])
+ compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]])['address'])
+ compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], compressed_solvable_address[1]])['address'])
+
+ # Test multisig_without_privkey
+ # We have 2 public keys without private keys, use addmultisigaddress to add to wallet.
+ # Money sent to P2SH of multisig of this should only be seen after importaddress with the BASE58 P2SH address.
+
+ multisig_without_privkey_address = self.nodes[0].addmultisigaddress(2, [pubkeys[3], pubkeys[4]])['address']
+ script = CScript([OP_2, bytes.fromhex(pubkeys[3]), bytes.fromhex(pubkeys[4]), OP_2, OP_CHECKMULTISIG])
+ solvable_after_importaddress.append(script_to_p2sh_script(script))
+
+ for i in compressed_spendable_address:
+ v = self.nodes[0].getaddressinfo(i)
+ if v['isscript']:
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ # p2sh multisig with compressed keys should always be spendable
+ spendable_anytime.extend([p2sh])
+ # bare multisig can be watched and signed, but is not treated as ours
+ solvable_after_importaddress.extend([bare])
+ # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after direct importaddress
+ spendable_after_importaddress.extend([p2wsh, p2sh_p2wsh])
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # normal P2PKH and P2PK with compressed keys should always be spendable
+ spendable_anytime.extend([p2pkh, p2pk])
+ # P2SH_P2PK, P2SH_P2PKH with compressed keys are spendable after direct importaddress
+ spendable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
+ # P2WPKH and P2SH_P2WPKH with compressed keys should always be spendable
+ spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])
+
+ for i in uncompressed_spendable_address:
+ v = self.nodes[0].getaddressinfo(i)
+ if v['isscript']:
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ # p2sh multisig with uncompressed keys should always be spendable
+ spendable_anytime.extend([p2sh])
+ # bare multisig can be watched and signed, but is not treated as ours
+ solvable_after_importaddress.extend([bare])
+ # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
+ unseen_anytime.extend([p2wsh, p2sh_p2wsh])
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # normal P2PKH and P2PK with uncompressed keys should always be spendable
+ spendable_anytime.extend([p2pkh, p2pk])
+ # P2SH_P2PK and P2SH_P2PKH are spendable after direct importaddress
+ spendable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])
+ # Witness output types with uncompressed keys are never seen
+ unseen_anytime.extend([p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
+
+ for i in compressed_solvable_address:
+ v = self.nodes[0].getaddressinfo(i)
+ if v['isscript']:
+ # Multisig without private is not seen after addmultisigaddress, but seen after importaddress
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ solvable_after_importaddress.extend([bare, p2sh, p2wsh, p2sh_p2wsh])
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # normal P2PKH, P2PK, P2WPKH and P2SH_P2WPKH with compressed keys should always be seen
+ solvable_anytime.extend([p2pkh, p2pk, p2wpkh, p2sh_p2wpkh])
+ # P2SH_P2PK, P2SH_P2PKH with compressed keys are seen after direct importaddress
+ solvable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
+
+ for i in uncompressed_solvable_address:
+ v = self.nodes[0].getaddressinfo(i)
+ if v['isscript']:
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ # Base uncompressed multisig without private is not seen after addmultisigaddress, but seen after importaddress
+ solvable_after_importaddress.extend([bare, p2sh])
+ # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
+ unseen_anytime.extend([p2wsh, p2sh_p2wsh])
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # normal P2PKH and P2PK with uncompressed keys should always be seen
+ solvable_anytime.extend([p2pkh, p2pk])
+ # P2SH_P2PK, P2SH_P2PKH with uncompressed keys are seen after direct importaddress
+ solvable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])
+ # Witness output types with uncompressed keys are never seen
+ unseen_anytime.extend([p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
+
+ op1 = CScript([OP_1])
+ op0 = CScript([OP_0])
+ # 2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe is the P2SH(P2PKH) version of mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V
+ unsolvable_address_key = bytes.fromhex("02341AEC7587A51CDE5279E0630A531AEA2615A9F80B17E8D9376327BAEAA59E3D")
+ unsolvablep2pkh = key_to_p2pkh_script(unsolvable_address_key)
+ unsolvablep2wshp2pkh = script_to_p2wsh_script(unsolvablep2pkh)
+ p2shop0 = script_to_p2sh_script(op0)
+ p2wshop1 = script_to_p2wsh_script(op1)
+ unsolvable_after_importaddress.append(unsolvablep2pkh)
+ unsolvable_after_importaddress.append(unsolvablep2wshp2pkh)
+ unsolvable_after_importaddress.append(op1) # OP_1 will be imported as script
+ unsolvable_after_importaddress.append(p2wshop1)
+ unseen_anytime.append(op0) # OP_0 will be imported as P2SH address with no script provided
+ unsolvable_after_importaddress.append(p2shop0)
+
+ spendable_txid = []
+ solvable_txid = []
+ spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime, 2))
+ solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime, 1))
+ self.mine_and_test_listunspent(spendable_after_importaddress + solvable_after_importaddress + unseen_anytime + unsolvable_after_importaddress, 0)
+
+ importlist = []
+ for i in compressed_spendable_address + uncompressed_spendable_address + compressed_solvable_address + uncompressed_solvable_address:
+ v = self.nodes[0].getaddressinfo(i)
+ if v['isscript']:
+ bare = bytes.fromhex(v['hex'])
+ importlist.append(bare.hex())
+ importlist.append(script_to_p2wsh_script(bare).hex())
+ else:
+ pubkey = bytes.fromhex(v['pubkey'])
+ p2pk = key_to_p2pk_script(pubkey)
+ p2pkh = key_to_p2pkh_script(pubkey)
+ importlist.append(p2pk.hex())
+ importlist.append(p2pkh.hex())
+ importlist.append(key_to_p2wpkh_script(pubkey).hex())
+ importlist.append(script_to_p2wsh_script(p2pk).hex())
+ importlist.append(script_to_p2wsh_script(p2pkh).hex())
+
+ importlist.append(unsolvablep2pkh.hex())
+ importlist.append(unsolvablep2wshp2pkh.hex())
+ importlist.append(op1.hex())
+ importlist.append(p2wshop1.hex())
+
+ for i in importlist:
+ # import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC
+ # exceptions and continue.
+ try_rpc(-4, "The wallet already contains the private key for this address or script", self.nodes[0].importaddress, i, "", False, True)
+
+ self.nodes[0].importaddress(script_to_p2sh(op0)) # import OP_0 as address only
+ self.nodes[0].importaddress(multisig_without_privkey_address) # Test multisig_without_privkey
+
+ spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2))
+ solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1))
+ self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
+ self.mine_and_test_listunspent(unseen_anytime, 0)
+
+ spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2))
+ solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1))
+ self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
+ self.mine_and_test_listunspent(unseen_anytime, 0)
+
+ # Repeat some tests. This time we don't add witness scripts with importaddress
+ # Import a compressed key and an uncompressed key, generate some multisig addresses
+ self.nodes[0].importprivkey("927pw6RW8ZekycnXqBQ2JS5nPyo1yRfGNN8oq74HeddWSpafDJH")
+ uncompressed_spendable_address = ["mguN2vNSCEUh6rJaXoAVwY3YZwZvEmf5xi"]
+ self.nodes[0].importprivkey("cMcrXaaUC48ZKpcyydfFo8PxHAjpsYLhdsp6nmtB3E2ER9UUHWnw")
+ compressed_spendable_address = ["n1UNmpmbVUJ9ytXYXiurmGPQ3TRrXqPWKL"]
+
+ self.nodes[0].importpubkey(pubkeys[5])
+ compressed_solvable_address = [key_to_p2pkh(pubkeys[5])]
+ self.nodes[0].importpubkey(pubkeys[6])
+ uncompressed_solvable_address = [key_to_p2pkh(pubkeys[6])]
+
+ unseen_anytime = [] # These outputs should never be seen
+ solvable_anytime = [] # These outputs should be solvable after importpubkey
+ unseen_anytime = [] # These outputs should never be seen
+
+ uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], compressed_spendable_address[0]])['address'])
+ uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], uncompressed_spendable_address[0]])['address'])
+ compressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_spendable_address[0]])['address'])
+ uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], uncompressed_solvable_address[0]])['address'])
+ compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]])['address'])
+
+ premature_witaddress = []
+
+ for i in compressed_spendable_address:
+ v = self.nodes[0].getaddressinfo(i)
+ if v['isscript']:
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ premature_witaddress.append(script_to_p2sh(p2wsh))
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # P2WPKH, P2SH_P2WPKH are always spendable
+ spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])
+
+ for i in uncompressed_spendable_address + uncompressed_solvable_address:
+ v = self.nodes[0].getaddressinfo(i)
+ if v['isscript']:
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
+ unseen_anytime.extend([p2wsh, p2sh_p2wsh])
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # P2WPKH, P2SH_P2WPKH with uncompressed keys are never seen
+ unseen_anytime.extend([p2wpkh, p2sh_p2wpkh])
+
+ for i in compressed_solvable_address:
+ v = self.nodes[0].getaddressinfo(i)
+ if v['isscript']:
+ [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
+ premature_witaddress.append(script_to_p2sh(p2wsh))
+ else:
+ [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
+ # P2SH_P2PK, P2SH_P2PKH with compressed keys are always solvable
+ solvable_anytime.extend([p2wpkh, p2sh_p2wpkh])
+
+ self.mine_and_test_listunspent(spendable_anytime, 2)
+ self.mine_and_test_listunspent(solvable_anytime, 1)
+ self.mine_and_test_listunspent(unseen_anytime, 0)
+
+ # Check that createrawtransaction/decoderawtransaction with non-v0 Bech32 works
+ v1_addr = program_to_witness(1, [3, 5])
+ v1_tx = self.nodes[0].createrawtransaction([getutxo(spendable_txid[0])], {v1_addr: 1})
+ v1_decoded = self.nodes[1].decoderawtransaction(v1_tx)
+ assert_equal(v1_decoded['vout'][0]['scriptPubKey']['address'], v1_addr)
+ assert_equal(v1_decoded['vout'][0]['scriptPubKey']['hex'], "51020305")
+
+ # Check that spendable outputs are really spendable
+ self.create_and_mine_tx_from_txids(spendable_txid)
+
+ # import all the private keys so solvable addresses become spendable
+ self.nodes[0].importprivkey("cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb")
+ self.nodes[0].importprivkey("cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97")
+ self.nodes[0].importprivkey("91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV")
+ self.nodes[0].importprivkey("cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd")
+ self.nodes[0].importprivkey("cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66")
+ self.nodes[0].importprivkey("cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K")
+ self.create_and_mine_tx_from_txids(solvable_txid)
+
+ # Test that importing native P2WPKH/P2WSH scripts works
+ for use_p2wsh in [False, True]:
+ if use_p2wsh:
+ scriptPubKey = "00203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a"
+ transaction = "01000000000100e1f505000000002200203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a00000000"
+ else:
+ scriptPubKey = "a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d87"
+ transaction = "01000000000100e1f5050000000017a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d8700000000"
+
+ self.nodes[1].importaddress(scriptPubKey, "", False)
+ rawtxfund = self.nodes[1].fundrawtransaction(transaction)['hex']
+ rawtxfund = self.nodes[1].signrawtransactionwithwallet(rawtxfund)["hex"]
+ txid = self.nodes[1].sendrawtransaction(rawtxfund)
+
+ assert_equal(self.nodes[1].gettransaction(txid, True)["txid"], txid)
+ assert_equal(self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"], txid)
+
+ # Assert it is properly saved
+ self.restart_node(1)
+ assert_equal(self.nodes[1].gettransaction(txid, True)["txid"], txid)
+ assert_equal(self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"], txid)
def mine_and_test_listunspent(self, script_list, ismine):
utxo = find_spendable_utxo(self.nodes[0], 50)
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index adc33bd9df..868bb42604 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -318,6 +318,15 @@ class RESTTest (BitcoinTestFramework):
if 'coinbase' not in tx['vin'][0]}
assert_equal(non_coinbase_txs, set(txs))
+ # Verify that the non-coinbase tx has "prevout" key set
+ for tx_obj in json_obj["tx"]:
+ for vin in tx_obj["vin"]:
+ if "coinbase" not in vin:
+ assert "prevout" in vin
+ assert_equal(vin["prevout"]["generated"], False)
+ else:
+ assert "prevout" not in vin
+
# Check the same but without tx details
json_obj = self.test_rest_request(f"/block/notxdetails/{newblockhash[0]}")
for tx in txs:
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index 3943bba489..ff5e45519f 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -65,8 +65,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
value = sent_value
chain.append(txid)
# We need the wtxids to check P2P announcements
- fulltx = self.nodes[0].getrawtransaction(txid)
- witnesstx = self.nodes[0].decoderawtransaction(fulltx, True)
+ witnesstx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
witness_chain.append(witnesstx['hash'])
# Check that listunspent ancestor{count, size, fees} yield the correct results
diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py
index da85ee54be..35274d3500 100755
--- a/test/functional/mining_prioritisetransaction.py
+++ b/test/functional/mining_prioritisetransaction.py
@@ -13,7 +13,7 @@ from test_framework.util import assert_equal, assert_raises_rpc_error, create_co
class PrioritiseTransactionTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
- self.num_nodes = 2
+ self.num_nodes = 1
self.extra_args = [[
"-printpriority=1",
"-acceptnonstdtxn=1",
diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py
index f3b80abb59..82c7e94c59 100755
--- a/test/functional/p2p_invalid_messages.py
+++ b/test/functional/p2p_invalid_messages.py
@@ -209,7 +209,7 @@ class InvalidMessagesTest(BitcoinTestFramework):
self.test_addrv2('unrecognized network',
[
'received: addrv2 (25 bytes)',
- 'IP 9.9.9.9 mapped',
+ '9.9.9.9:8333 mapped',
'Added 1 addresses',
],
bytes.fromhex(
diff --git a/test/functional/p2p_ping.py b/test/functional/p2p_ping.py
index 888e986fba..d67e97acf7 100755
--- a/test/functional/p2p_ping.py
+++ b/test/functional/p2p_ping.py
@@ -30,11 +30,16 @@ class NodeNoPong(P2PInterface):
pass
+TIMEOUT_INTERVAL = 20 * 60
+
+
class PingPongTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
- self.extra_args = [['-peertimeout=3']]
+ # Set the peer connection timeout low. It does not matter for this
+ # test, as long as it is less than TIMEOUT_INTERVAL.
+ self.extra_args = [['-peertimeout=1']]
def check_peer_info(self, *, pingtime, minping, pingwait):
stats = self.nodes[0].getpeerinfo()[0]
@@ -110,8 +115,11 @@ class PingPongTest(BitcoinTestFramework):
self.nodes[0].ping()
no_pong_node.wait_until(lambda: 'ping' in no_pong_node.last_message)
with self.nodes[0].assert_debug_log(['ping timeout: 1201.000000s']):
- self.mock_forward(20 * 60 + 1)
- time.sleep(4) # peertimeout + 1
+ self.mock_forward(TIMEOUT_INTERVAL // 2)
+ # Check that sending a ping does not prevent the disconnect
+ no_pong_node.sync_with_ping()
+ self.mock_forward(TIMEOUT_INTERVAL // 2 + 1)
+ no_pong_node.wait_for_disconnect()
if __name__ == '__main__':
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 4e21d08e5c..5195c9fd04 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -8,7 +8,12 @@ import random
import struct
import time
-from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, WITNESS_COMMITMENT_HEADER
+from test_framework.blocktools import (
+ WITNESS_COMMITMENT_HEADER,
+ add_witness_commitment,
+ create_block,
+ create_coinbase,
+)
from test_framework.key import ECKey
from test_framework.messages import (
BIP125_SEQUENCE_NUMBER,
@@ -194,7 +199,7 @@ class SegWitTest(BitcoinTestFramework):
self.num_nodes = 2
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
self.extra_args = [
- ["-acceptnonstdtxn=1", f"-testactivationheight=segwit@{SEGWIT_HEIGHT}", "-whitelist=noban@127.0.0.1"],
+ ["-acceptnonstdtxn=1", f"-testactivationheight=segwit@{SEGWIT_HEIGHT}", "-whitelist=noban@127.0.0.1", "-par=1"],
["-acceptnonstdtxn=0", f"-testactivationheight=segwit@{SEGWIT_HEIGHT}"],
]
self.supports_cli = False
@@ -505,8 +510,8 @@ class SegWitTest(BitcoinTestFramework):
# 'block-validation-failed' (if script check threads > 1) or
# 'non-mandatory-script-verify-flag (Witness program was passed an
# empty witness)' (otherwise).
- # TODO: support multiple acceptable reject reasons.
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=False,
+ reason='non-mandatory-script-verify-flag (Witness program was passed an empty witness)')
self.utxo.pop(0)
self.utxo.append(UTXO(txid, 2, value))
@@ -786,7 +791,7 @@ class SegWitTest(BitcoinTestFramework):
block_3.rehash()
block_3.solve()
- test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False, reason='bad-witness-merkle-match')
# Add a different commitment with different nonce, but in the
# right location, and with some funds burned(!).
@@ -852,7 +857,7 @@ class SegWitTest(BitcoinTestFramework):
# Change the nonce -- should not cause the block to be permanently
# failed
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(1)]
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, reason='bad-witness-merkle-match')
# Changing the witness reserved value doesn't change the block hash
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)]
@@ -861,7 +866,7 @@ class SegWitTest(BitcoinTestFramework):
@subtest # type: ignore
def test_witness_block_size(self):
# TODO: Test that non-witness carrying blocks can't exceed 1MB
- # Skipping this test for now; this is covered in p2p-fullblocktest.py
+ # Skipping this test for now; this is covered in feature_block.py
# Test that witness-bearing blocks are limited at ceil(base + wit/4) <= 1MB.
block = self.build_next_block()
@@ -917,7 +922,7 @@ class SegWitTest(BitcoinTestFramework):
# limit
assert len(block.serialize()) > 2 * 1024 * 1024
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, reason='bad-blk-weight')
# Now resize the second transaction to make the block fit.
cur_length = len(block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0])
@@ -989,7 +994,8 @@ class SegWitTest(BitcoinTestFramework):
self.update_witness_block_with_transactions(block, [tx])
# Extra witness data should not be allowed.
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
+ reason='non-mandatory-script-verify-flag (Witness provided for non-witness script)')
# Try extra signature data. Ok if we're not spending a witness output.
block.vtx[1].wit.vtxinwit = []
@@ -1014,7 +1020,8 @@ class SegWitTest(BitcoinTestFramework):
self.update_witness_block_with_transactions(block, [tx2])
# This has extra witness data, so it should fail.
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
+ reason='non-mandatory-script-verify-flag (Stack size must be exactly one after execution)')
# Now get rid of the extra witness, but add extra scriptSig data
tx2.vin[0].scriptSig = CScript([OP_TRUE])
@@ -1026,7 +1033,8 @@ class SegWitTest(BitcoinTestFramework):
block.solve()
# This has extra signature data for a witness input, so it should fail.
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
+ reason='non-mandatory-script-verify-flag (Witness requires empty scriptSig)')
# Now get rid of the extra scriptsig on the witness input, and verify
# success (even with extra scriptsig data in the non-witness input)
@@ -1064,7 +1072,8 @@ class SegWitTest(BitcoinTestFramework):
tx2.rehash()
self.update_witness_block_with_transactions(block, [tx, tx2])
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
+ reason='non-mandatory-script-verify-flag (Push value size limit exceeded)')
# Now reduce the length of the stack element
tx2.wit.vtxinwit[0].scriptWitness.stack[0] = b'a' * (MAX_SCRIPT_ELEMENT_SIZE)
@@ -1104,7 +1113,8 @@ class SegWitTest(BitcoinTestFramework):
self.update_witness_block_with_transactions(block, [tx, tx2])
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
+ reason='non-mandatory-script-verify-flag (Script is too big)')
# Try again with one less byte in the witness script
witness_script = CScript([b'a' * MAX_SCRIPT_ELEMENT_SIZE] * 19 + [OP_DROP] * 62 + [OP_TRUE])
@@ -1176,7 +1186,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, reason='bad-txnmrklroot')
# Now try using a too short vtxinwit
tx2.wit.vtxinwit.pop()
@@ -1184,6 +1194,8 @@ class SegWitTest(BitcoinTestFramework):
block.vtx = [block.vtx[0]]
self.update_witness_block_with_transactions(block, [tx2])
+ # This block doesn't result in a specific reject reason, but an iostream exception:
+ # "Exception 'CDataStream::read(): end of data: unspecified iostream_category error' (...) caught"
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now make one of the intermediate witnesses be incorrect
@@ -1193,7 +1205,8 @@ class SegWitTest(BitcoinTestFramework):
block.vtx = [block.vtx[0]]
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
+ reason='non-mandatory-script-verify-flag (Operation not valid with the current stack size)')
# Fix the broken witness and the block should be accepted.
tx2.wit.vtxinwit[5].scriptWitness.stack = [b'a', witness_script]
@@ -1415,7 +1428,7 @@ class SegWitTest(BitcoinTestFramework):
self.sync_blocks()
block2 = self.build_next_block()
self.update_witness_block_with_transactions(block2, [spend_tx])
- test_witness_block(self.nodes[0], self.test_node, block2, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block2, accepted=False, reason='bad-txns-premature-spend-of-coinbase')
# Advancing one more block should allow the spend.
self.generate(self.nodes[0], 1)
@@ -1564,13 +1577,17 @@ class SegWitTest(BitcoinTestFramework):
# Too-large input value
sign_p2pk_witness_input(witness_script, tx, 0, hashtype, prev_utxo.nValue + 1, key)
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
+ reason='non-mandatory-script-verify-flag (Script evaluated without error '
+ 'but finished with a false/empty top stack element')
# Too-small input value
sign_p2pk_witness_input(witness_script, tx, 0, hashtype, prev_utxo.nValue - 1, key)
block.vtx.pop() # remove last tx
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
+ reason='non-mandatory-script-verify-flag (Script evaluated without error '
+ 'but finished with a false/empty top stack element')
# Now try correct value
sign_p2pk_witness_input(witness_script, tx, 0, hashtype, prev_utxo.nValue, key)
@@ -1672,7 +1689,8 @@ class SegWitTest(BitcoinTestFramework):
tx2.vin[0].scriptSig = CScript([signature, pubkey])
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx, tx2])
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
+ reason='non-mandatory-script-verify-flag (Witness requires empty scriptSig)')
# Move the signature to the witness.
block.vtx.pop()
@@ -1918,7 +1936,7 @@ class SegWitTest(BitcoinTestFramework):
block_2 = self.build_next_block()
self.update_witness_block_with_transactions(block_2, [tx2])
- test_witness_block(self.nodes[0], self.test_node, block_2, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block_2, accepted=False, reason='bad-blk-sigops')
# Try dropping the last input in tx2, and add an output that has
# too many sigops (contributing to legacy sigop count).
@@ -1931,7 +1949,7 @@ class SegWitTest(BitcoinTestFramework):
tx2.rehash()
block_3 = self.build_next_block()
self.update_witness_block_with_transactions(block_3, [tx2])
- test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False, reason='bad-blk-sigops')
# If we drop the last checksig in this output, the tx should succeed.
block_4 = self.build_next_block()
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index c3c6ade684..eea9ee26cb 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -434,17 +434,55 @@ class BlockchainTest(BitcoinTestFramework):
miniwallet.send_self_transfer(fee_rate=fee_per_kb, from_node=node)
blockhash = self.generate(node, 1)[0]
- self.log.info("Test getblock with verbosity 1 doesn't include fee")
- block = node.getblock(blockhash, 1)
- assert 'fee' not in block['tx'][1]
-
- self.log.info('Test getblock with verbosity 2 includes expected fee')
- block = node.getblock(blockhash, 2)
- tx = block['tx'][1]
- assert 'fee' in tx
- assert_equal(tx['fee'], tx['vsize'] * fee_per_byte)
-
- self.log.info("Test getblock with verbosity 2 still works with pruned Undo data")
+ def assert_fee_not_in_block(verbosity):
+ block = node.getblock(blockhash, verbosity)
+ assert 'fee' not in block['tx'][1]
+
+ def assert_fee_in_block(verbosity):
+ block = node.getblock(blockhash, verbosity)
+ tx = block['tx'][1]
+ assert 'fee' in tx
+ assert_equal(tx['fee'], tx['vsize'] * fee_per_byte)
+
+ def assert_vin_contains_prevout(verbosity):
+ block = node.getblock(blockhash, verbosity)
+ tx = block["tx"][1]
+ total_vin = Decimal("0.00000000")
+ total_vout = Decimal("0.00000000")
+ for vin in tx["vin"]:
+ assert "prevout" in vin
+ assert_equal(set(vin["prevout"].keys()), set(("value", "height", "generated", "scriptPubKey")))
+ assert_equal(vin["prevout"]["generated"], True)
+ total_vin += vin["prevout"]["value"]
+ for vout in tx["vout"]:
+ total_vout += vout["value"]
+ assert_equal(total_vin, total_vout + tx["fee"])
+
+ def assert_vin_does_not_contain_prevout(verbosity):
+ block = node.getblock(blockhash, verbosity)
+ tx = block["tx"][1]
+ if isinstance(tx, str):
+ # In verbosity level 1, only the transaction hashes are written
+ pass
+ else:
+ for vin in tx["vin"]:
+ assert "prevout" not in vin
+
+ self.log.info("Test that getblock with verbosity 1 doesn't include fee")
+ assert_fee_not_in_block(1)
+
+ self.log.info('Test that getblock with verbosity 2 and 3 includes expected fee')
+ assert_fee_in_block(2)
+ assert_fee_in_block(3)
+
+ self.log.info("Test that getblock with verbosity 1 and 2 does not include prevout")
+ assert_vin_does_not_contain_prevout(1)
+ assert_vin_does_not_contain_prevout(2)
+
+ self.log.info("Test that getblock with verbosity 3 includes prevout")
+ assert_vin_contains_prevout(3)
+
+ self.log.info("Test that getblock with verbosity 2 and 3 still works with pruned Undo data")
datadir = get_datadir_path(self.options.tmpdir, 0)
self.log.info("Test getblock with invalid verbosity type returns proper error message")
@@ -458,8 +496,10 @@ class BlockchainTest(BitcoinTestFramework):
# Move instead of deleting so we can restore chain state afterwards
move_block_file('rev00000.dat', 'rev_wrong')
- block = node.getblock(blockhash, 2)
- assert 'fee' not in block['tx'][1]
+ assert_fee_not_in_block(2)
+ assert_fee_not_in_block(3)
+ assert_vin_does_not_contain_prevout(2)
+ assert_vin_does_not_contain_prevout(3)
# Restore chain state
move_block_file('rev_wrong', 'rev00000.dat')
diff --git a/test/functional/rpc_invalid_address_message.py b/test/functional/rpc_invalid_address_message.py
index 7ab5a5e90d..085f6582b5 100755
--- a/test/functional/rpc_invalid_address_message.py
+++ b/test/functional/rpc_invalid_address_message.py
@@ -90,7 +90,7 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
self.test_validateaddress()
if self.is_wallet_compiled():
- self.init_wallet(0)
+ self.init_wallet(node=0)
self.test_getaddressinfo()
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 727ac6aed9..ec3561b1f2 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -423,12 +423,12 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def import_deterministic_coinbase_privkeys(self):
for i in range(self.num_nodes):
- self.init_wallet(i)
+ self.init_wallet(node=i)
- def init_wallet(self, i):
- wallet_name = self.default_wallet_name if self.wallet_names is None else self.wallet_names[i] if i < len(self.wallet_names) else False
+ def init_wallet(self, *, node):
+ wallet_name = self.default_wallet_name if self.wallet_names is None else self.wallet_names[node] if node < len(self.wallet_names) else False
if wallet_name is not False:
- n = self.nodes[i]
+ n = self.nodes[node]
if wallet_name is not None:
n.createwallet(wallet_name=wallet_name, descriptors=self.options.descriptors, load_on_startup=True)
n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase')
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index b91b294108..916cd94b79 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -100,6 +100,7 @@ BASE_SCRIPTS = [
'p2p_compactblocks.py',
'p2p_compactblocks_blocksonly.py',
'feature_segwit.py --legacy-wallet',
+ 'feature_segwit.py --descriptors',
# vv Tests less than 2m vv
'wallet_basic.py --legacy-wallet',
'wallet_basic.py --descriptors',
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index 4bf3927879..cebaa02524 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -31,8 +31,8 @@ class ToolWalletTest(BitcoinTestFramework):
def bitcoin_wallet_process(self, *args):
binary = self.config["environment"]["BUILDDIR"] + '/src/bitcoin-wallet' + self.config["environment"]["EXEEXT"]
default_args = ['-datadir={}'.format(self.nodes[0].datadir), '-chain=%s' % self.chain]
- if self.options.descriptors and 'create' in args:
- default_args.append('-descriptors')
+ if not self.options.descriptors and 'create' in args:
+ default_args.append('-legacy')
return subprocess.Popen([binary] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
@@ -193,7 +193,7 @@ class ToolWalletTest(BitcoinTestFramework):
locked_dir = os.path.join(self.options.tmpdir, "node0", "regtest", "wallets")
error = 'Error initializing wallet database environment "{}"!'.format(locked_dir)
if self.options.descriptors:
- error = "SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another bitcoind?"
+ error = f"SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another instance of {self.config['environment']['PACKAGE_NAME']}?"
self.assert_raises_tool_error(
error,
'-wallet=' + self.default_wallet_name,
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index d6766097f6..8f54e50598 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -213,7 +213,7 @@ class AbandonConflictTest(BitcoinTestFramework):
#assert_equal(newbalance, balance - Decimal("10"))
self.log.info("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer")
self.log.info("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315")
- self.log.info(str(balance) + " -> " + str(newbalance) + " ?")
+ assert_equal(balance, newbalance)
if __name__ == '__main__':
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index bdee22e62b..7a448e8590 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -204,8 +204,7 @@ class AddressTypeTest(BitcoinTestFramework):
def test_change_output_type(self, node_sender, destinations, expected_type):
txid = self.nodes[node_sender].sendmany(dummy="", amounts=dict.fromkeys(destinations, 0.001))
- raw_tx = self.nodes[node_sender].getrawtransaction(txid)
- tx = self.nodes[node_sender].decoderawtransaction(raw_tx)
+ tx = self.nodes[node_sender].gettransaction(txid=txid, verbose=True)['decoded']
# Make sure the transaction has change:
assert_equal(len(tx["vout"]), len(destinations) + 1)
diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py
index bc6d6206e5..a07c28c8a4 100755
--- a/test/functional/wallet_backup.py
+++ b/test/functional/wallet_backup.py
@@ -124,9 +124,9 @@ class WalletBackupTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Wallet name already exists.", node.restorewallet, wallet_name, wallet_file)
def init_three(self):
- self.init_wallet(0)
- self.init_wallet(1)
- self.init_wallet(2)
+ self.init_wallet(node=0)
+ self.init_wallet(node=1)
+ self.init_wallet(node=2)
def run_test(self):
self.log.info("Generating initial blockchain")
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 599e506f98..92da54d97c 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -666,7 +666,7 @@ class WalletTest(BitcoinTestFramework):
self.generate(self.nodes[0], 1)
destination = self.nodes[1].getnewaddress()
txid = self.nodes[0].sendtoaddress(destination, 0.123)
- tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])
+ tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
output_addresses = [vout['scriptPubKey']['address'] for vout in tx["vout"]]
assert len(output_addresses) > 1
for address in output_addresses:
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index a1676fffa5..46a5df4a8e 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -32,6 +32,8 @@ from test_framework.util import (
assert_greater_than,
assert_raises_rpc_error,
)
+from test_framework.wallet import MiniWallet
+
WALLET_PASSPHRASE = "test"
WALLET_PASSPHRASE_TIMEOUT = 3600
@@ -265,6 +267,14 @@ def test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_ad
tx = rbf_node.signrawtransactionwithwallet(tx)
rbf_node.sendrawtransaction(tx["hex"])
assert_raises_rpc_error(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id)
+
+ # create tx with descendant in the mempool by using MiniWallet
+ miniwallet = MiniWallet(rbf_node)
+ parent_id = spend_one_input(rbf_node, miniwallet.get_address())
+ tx = rbf_node.gettransaction(txid=parent_id, verbose=True)['decoded']
+ miniwallet.scan_tx(tx)
+ miniwallet.send_self_transfer(from_node=rbf_node)
+ assert_raises_rpc_error(-8, "Transaction has descendants in the mempool", rbf_node.bumpfee, parent_id)
self.clear_mempool()
diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py
index c8b92ef1bf..00ee08002e 100755
--- a/test/functional/wallet_create_tx.py
+++ b/test/functional/wallet_create_tx.py
@@ -34,13 +34,13 @@ class CreateTxWalletTest(BitcoinTestFramework):
self.log.info('Check that we have some (old) blocks and that anti-fee-sniping is disabled')
assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200)
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
- tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])
+ tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
assert_equal(tx['locktime'], 0)
self.log.info('Check that anti-fee-sniping is enabled when we mine a recent block')
self.generate(self.nodes[0], 1)
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
- tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])
+ tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
assert 0 < tx['locktime'] <= 201
def test_tx_size_too_large(self):
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index 974ce7f381..f54ae89c04 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -129,7 +129,7 @@ class WalletHDTest(BitcoinTestFramework):
# send a tx and make sure its using the internal chain for the changeoutput
txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
- outs = self.nodes[1].decoderawtransaction(self.nodes[1].gettransaction(txid)['hex'])['vout']
+ outs = self.nodes[1].gettransaction(txid=txid, verbose=True)['decoded']['vout']
keypath = ""
for out in outs:
if out['value'] != 1:
diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py
index cbe3e9bfdd..27a2a42dac 100755
--- a/test/functional/wallet_import_rescan.py
+++ b/test/functional/wallet_import_rescan.py
@@ -99,7 +99,7 @@ class Variant(collections.namedtuple("Variant", "call data address_type rescan p
assert_equal(tx["label"], self.label)
assert_equal(tx["txid"], txid)
assert_equal(tx["confirmations"], 1 + current_height - confirmation_height)
- assert_equal("trusted" not in tx, True)
+ assert "trusted" not in tx
address, = [ad for ad in addresses if txid in ad["txids"]]
assert_equal(address["address"], self.address["address"])
diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py
index c8f9664885..fc9eac1d74 100755
--- a/test/functional/wallet_importdescriptors.py
+++ b/test/functional/wallet_importdescriptors.py
@@ -454,7 +454,7 @@ class ImportDescriptorsTest(BitcoinTestFramework):
self.generate(self.nodes[0], 6)
self.sync_all()
send_txid = wmulti_priv.sendtoaddress(w0.getnewaddress(), 8)
- decoded = wmulti_priv.decoderawtransaction(wmulti_priv.gettransaction(send_txid)['hex'])
+ decoded = wmulti_priv.gettransaction(txid=send_txid, verbose=True)['decoded']
assert_equal(len(decoded['vin'][0]['txinwitness']), 4)
self.generate(self.nodes[0], 6)
self.sync_all()
@@ -586,7 +586,7 @@ class ImportDescriptorsTest(BitcoinTestFramework):
self.sync_all()
# It is standard and would relay.
txid = wmulti_priv_big.sendtoaddress(w0.getnewaddress(), 9.999)
- decoded = wmulti_priv_big.decoderawtransaction(wmulti_priv_big.gettransaction(txid)['hex'])
+ decoded = wmulti_priv_big.gettransaction(txid=txid, verbose=True)['decoded']
# 20 sigs + dummy + witness script
assert_equal(len(decoded['vin'][0]['txinwitness']), 22)
@@ -620,12 +620,8 @@ class ImportDescriptorsTest(BitcoinTestFramework):
self.generate(self.nodes[0], 6)
self.sync_all()
# It is standard and would relay.
- txid = multi_priv_big.sendtoaddress(w0.getnewaddress(), 10, "", "",
- True)
- decoded = multi_priv_big.decoderawtransaction(
- multi_priv_big.gettransaction(txid)['hex']
- )
-
+ txid = multi_priv_big.sendtoaddress(w0.getnewaddress(), 10, "", "", True)
+ decoded = multi_priv_big.gettransaction(txid=txid, verbose=True)['decoded']
self.log.info("Amending multisig with new private keys")
self.nodes[1].createwallet(wallet_name="wmulti_priv3", descriptors=True)
diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py
index 221f5262d9..436bbdcfcc 100755
--- a/test/functional/wallet_listdescriptors.py
+++ b/test/functional/wallet_listdescriptors.py
@@ -23,7 +23,7 @@ class ListDescriptorsTest(BitcoinTestFramework):
self.skip_if_no_sqlite()
# do not create any wallet by default
- def init_wallet(self, i):
+ def init_wallet(self, *, node):
return
def run_test(self):
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index bd3b29c81c..f4a00a8ec8 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -44,6 +44,14 @@ class ListSinceBlockTest(BitcoinTestFramework):
def test_no_blockhash(self):
self.log.info("Test no blockhash")
txid = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+ self.sync_all()
+ assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, {
+ "category": "receive",
+ "amount": 1,
+ "confirmations": 0,
+ "trusted": False,
+ })
+
blockhash, = self.generate(self.nodes[2], 1)
blockheight = self.nodes[2].getblockheader(blockhash)['height']
self.sync_all()
@@ -56,6 +64,9 @@ class ListSinceBlockTest(BitcoinTestFramework):
"blockheight": blockheight,
"confirmations": 1,
})
+ assert_equal(len(txs), 1)
+ assert "trusted" not in txs[0]
+
assert_equal(
self.nodes[0].listsinceblock(),
{"lastblock": blockhash,
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index a14bfe345c..ca6a6ab540 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -31,10 +31,10 @@ class ListTransactionsTest(BitcoinTestFramework):
self.sync_all()
assert_array_result(self.nodes[0].listtransactions(),
{"txid": txid},
- {"category": "send", "amount": Decimal("-0.1"), "confirmations": 0})
+ {"category": "send", "amount": Decimal("-0.1"), "confirmations": 0, "trusted": True})
assert_array_result(self.nodes[1].listtransactions(),
{"txid": txid},
- {"category": "receive", "amount": Decimal("0.1"), "confirmations": 0})
+ {"category": "receive", "amount": Decimal("0.1"), "confirmations": 0, "trusted": False})
self.log.info("Test confirmations change after mining a block")
blockhash = self.generate(self.nodes[0], 1)[0]
blockheight = self.nodes[0].getblockheader(blockhash)['height']
@@ -204,6 +204,15 @@ class ListTransactionsTest(BitcoinTestFramework):
assert_equal(n.gettransaction(txid_3b)["bip125-replaceable"], "yes")
assert_equal(n.gettransaction(txid_4)["bip125-replaceable"], "unknown")
+ self.log.info("Test bip125-replaceable status with listsinceblock")
+ for n in self.nodes[0:2]:
+ txs = {tx['txid']: tx['bip125-replaceable'] for tx in n.listsinceblock()['transactions']}
+ assert_equal(txs[txid_1], "no")
+ assert_equal(txs[txid_2], "no")
+ assert_equal(txs[txid_3], "yes")
+ assert_equal(txs[txid_3b], "yes")
+ assert_equal(txs[txid_4], "unknown")
+
self.log.info("Test mined transactions are no longer bip125-replaceable")
self.generate(self.nodes[0], 1)
assert txid_3b not in self.nodes[0].getrawmempool()
diff --git a/test/functional/wallet_multisig_descriptor_psbt.py b/test/functional/wallet_multisig_descriptor_psbt.py
index 68c206b038..ed855d2525 100755
--- a/test/functional/wallet_multisig_descriptor_psbt.py
+++ b/test/functional/wallet_multisig_descriptor_psbt.py
@@ -104,13 +104,13 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework):
self.log.info("Get a mature utxo to send to the multisig...")
coordinator_wallet = participants["signers"][0]
- coordinator_wallet.generatetoaddress(101, coordinator_wallet.getnewaddress())
+ self.generatetoaddress(self.nodes[0], 101, coordinator_wallet.getnewaddress())
deposit_amount = 6.15
multisig_receiving_address = participants["multisigs"][0].getnewaddress()
self.log.info("Send funds to the resulting multisig receiving address...")
coordinator_wallet.sendtoaddress(multisig_receiving_address, deposit_amount)
- self.nodes[0].generate(1)
+ self.generate(self.nodes[0], 1)
self.sync_all()
for participant in participants["multisigs"]:
assert_approx(participant.getbalance(), deposit_amount, vspan=0.001)
@@ -136,7 +136,7 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework):
coordinator_wallet.sendrawtransaction(finalized["hex"])
self.log.info("Check that balances are correct after the transaction has been included in a block.")
- self.nodes[0].generate(1)
+ self.generate(self.nodes[0], 1)
self.sync_all()
assert_approx(participants["multisigs"][0].getbalance(), deposit_amount - value, vspan=0.001)
assert_equal(participants["signers"][self.N - 1].getbalance(), value)
@@ -153,7 +153,7 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework):
coordinator_wallet.sendrawtransaction(finalized["hex"])
self.log.info("Check that balances are correct after the transaction has been included in a block.")
- self.nodes[0].generate(1)
+ self.generate(self.nodes[0], 1)
self.sync_all()
assert_approx(participants["multisigs"][0].getbalance(), deposit_amount - (value * 2), vspan=0.001)
assert_equal(participants["signers"][self.N - 1].getbalance(), value * 2)
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index d4768f5043..68ca005649 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -202,7 +202,7 @@ class MultiWalletTest(BitcoinTestFramework):
self.restart_node(0, ['-nowallet', '-walletdir=' + competing_wallet_dir])
self.nodes[0].createwallet(self.default_wallet_name)
if self.options.descriptors:
- exp_stderr = r"Error: SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another bitcoind?"
+ exp_stderr = f"Error: SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another instance of {self.config['environment']['PACKAGE_NAME']}?"
else:
exp_stderr = r"Error: Error initializing wallet database environment \"\S+competing_walletdir\S*\"!"
self.nodes[1].assert_start_raises_init_error(['-walletdir=' + competing_wallet_dir], exp_stderr, match=ErrorMatch.PARTIAL_REGEX)
@@ -303,7 +303,7 @@ class MultiWalletTest(BitcoinTestFramework):
# Fail to load duplicate wallets
path = os.path.join(self.options.tmpdir, "node0", "regtest", "wallets", "w1", "wallet.dat")
if self.options.descriptors:
- assert_raises_rpc_error(-4, "Wallet file verification failed. SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another bitcoind?", self.nodes[0].loadwallet, wallet_names[0])
+ assert_raises_rpc_error(-4, f"Wallet file verification failed. SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another instance of {self.config['environment']['PACKAGE_NAME']}?", self.nodes[0].loadwallet, wallet_names[0])
else:
assert_raises_rpc_error(-35, "Wallet file verification failed. Refusing to load database. Data file '{}' is already loaded.".format(path), self.nodes[0].loadwallet, wallet_names[0])
diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py
index 4f84dbd125..80c125df97 100755
--- a/test/functional/wallet_taproot.py
+++ b/test/functional/wallet_taproot.py
@@ -185,7 +185,7 @@ class WalletTaprootTest(BitcoinTestFramework):
def setup_network(self):
self.setup_nodes()
- def init_wallet(self, i):
+ def init_wallet(self, *, node):
pass
@staticmethod