aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional')
-rwxr-xr-xtest/functional/feature_assumevalid.py9
-rwxr-xr-xtest/functional/feature_backwards_compatibility.py5
-rwxr-xr-xtest/functional/feature_cltv.py23
-rwxr-xr-xtest/functional/feature_coinstatsindex.py3
-rwxr-xr-xtest/functional/feature_loadblock.py3
-rwxr-xr-xtest/functional/feature_nulldummy.py17
-rwxr-xr-xtest/functional/feature_proxy.py4
-rwxr-xr-xtest/functional/feature_rbf.py70
-rwxr-xr-xtest/functional/feature_taproot.py3
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py4
-rwxr-xr-xtest/functional/mempool_accept.py3
-rwxr-xr-xtest/functional/mempool_compatibility.py3
-rwxr-xr-xtest/functional/mempool_expiry.py3
-rwxr-xr-xtest/functional/mempool_package_onemore.py3
-rwxr-xr-xtest/functional/mempool_packages.py3
-rwxr-xr-xtest/functional/mempool_reorg.py109
-rwxr-xr-xtest/functional/mempool_resurrect.py3
-rwxr-xr-xtest/functional/mining_getblocktemplate_longpoll.py3
-rwxr-xr-xtest/functional/p2p_blocksonly.py3
-rwxr-xr-xtest/functional/p2p_compactblocks.py13
-rwxr-xr-xtest/functional/p2p_eviction.py8
-rwxr-xr-xtest/functional/p2p_feefilter.py3
-rwxr-xr-xtest/functional/p2p_leak.py6
-rwxr-xr-xtest/functional/p2p_leak_tx.py3
-rwxr-xr-xtest/functional/rpc_createmultisig.py3
-rwxr-xr-xtest/functional/rpc_dumptxoutset.py4
-rwxr-xr-xtest/functional/rpc_getblockstats.py4
-rwxr-xr-xtest/functional/rpc_net.py3
-rwxr-xr-xtest/functional/rpc_packages.py362
-rwxr-xr-xtest/functional/rpc_rawtransaction.py4
-rwxr-xr-xtest/functional/rpc_signrawtransaction.py5
-rwxr-xr-xtest/functional/rpc_txoutproof.py3
-rw-r--r--test/functional/test_framework/blocktools.py8
-rw-r--r--test/functional/test_framework/netutil.py2
-rwxr-xr-xtest/functional/test_framework/test_node.py4
-rw-r--r--test/functional/test_framework/util.py21
-rw-r--r--test/functional/test_framework/wallet.py10
-rwxr-xr-xtest/functional/test_runner.py3
-rwxr-xr-xtest/functional/wallet_abandonconflict.py3
-rwxr-xr-xtest/functional/wallet_address_types.py5
-rwxr-xr-xtest/functional/wallet_backup.py5
-rwxr-xr-xtest/functional/wallet_balance.py3
-rwxr-xr-xtest/functional/wallet_basic.py5
-rwxr-xr-xtest/functional/wallet_bumpfee.py3
-rwxr-xr-xtest/functional/wallet_descriptor.py3
-rwxr-xr-xtest/functional/wallet_fallbackfee.py4
-rwxr-xr-xtest/functional/wallet_groups.py3
-rwxr-xr-xtest/functional/wallet_hd.py3
-rwxr-xr-xtest/functional/wallet_importdescriptors.py3
-rwxr-xr-xtest/functional/wallet_importmulti.py9
-rwxr-xr-xtest/functional/wallet_importprunedfunds.py5
-rwxr-xr-xtest/functional/wallet_keypool_topup.py3
-rwxr-xr-xtest/functional/wallet_labels.py7
-rwxr-xr-xtest/functional/wallet_listsinceblock.py3
-rwxr-xr-xtest/functional/wallet_multiwallet.py3
-rwxr-xr-xtest/functional/wallet_orphanedreward.py62
-rwxr-xr-xtest/functional/wallet_taproot.py272
-rwxr-xr-xtest/functional/wallet_upgradewallet.py7
-rwxr-xr-xtest/functional/wallet_watchonly.py3
59 files changed, 1000 insertions, 157 deletions
diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py
index 1a148f04f4..a4480307a7 100755
--- a/test/functional/feature_assumevalid.py
+++ b/test/functional/feature_assumevalid.py
@@ -31,6 +31,7 @@ Start three nodes:
"""
from test_framework.blocktools import (
+ COINBASE_MATURITY,
create_block,
create_coinbase,
)
@@ -161,8 +162,8 @@ class AssumeValidTest(BitcoinTestFramework):
# Send blocks to node0. Block 102 will be rejected.
self.send_blocks_until_disconnected(p2p0)
- self.wait_until(lambda: self.nodes[0].getblockcount() >= 101)
- assert_equal(self.nodes[0].getblockcount(), 101)
+ self.wait_until(lambda: self.nodes[0].getblockcount() >= COINBASE_MATURITY + 1)
+ assert_equal(self.nodes[0].getblockcount(), COINBASE_MATURITY + 1)
# Send all blocks to node1. All blocks will be accepted.
for i in range(2202):
@@ -173,8 +174,8 @@ class AssumeValidTest(BitcoinTestFramework):
# Send blocks to node2. Block 102 will be rejected.
self.send_blocks_until_disconnected(p2p2)
- self.wait_until(lambda: self.nodes[2].getblockcount() >= 101)
- assert_equal(self.nodes[2].getblockcount(), 101)
+ self.wait_until(lambda: self.nodes[2].getblockcount() >= COINBASE_MATURITY + 1)
+ assert_equal(self.nodes[2].getblockcount(), COINBASE_MATURITY + 1)
if __name__ == '__main__':
diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/feature_backwards_compatibility.py
index e6a53b52db..c712f7141c 100755
--- a/test/functional/feature_backwards_compatibility.py
+++ b/test/functional/feature_backwards_compatibility.py
@@ -22,6 +22,7 @@ needs an older patch version.
import os
import shutil
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.descriptors import descsum_create
@@ -64,13 +65,13 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
self.import_deterministic_coinbase_privkeys()
def run_test(self):
- self.nodes[0].generatetoaddress(101, self.nodes[0].getnewaddress())
+ self.nodes[0].generatetoaddress(COINBASE_MATURITY + 1, self.nodes[0].getnewaddress())
self.sync_blocks()
# Sanity check the test framework:
res = self.nodes[self.num_nodes - 1].getblockchaininfo()
- assert_equal(res['blocks'], 101)
+ assert_equal(res['blocks'], COINBASE_MATURITY + 1)
node_master = self.nodes[self.num_nodes - 5]
node_v19 = self.nodes[self.num_nodes - 4]
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index d25aaa070d..10d2072dba 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -37,7 +37,7 @@ CLTV_HEIGHT = 1351
# Helper function to modify a transaction by
# 1) prepending a given script to the scriptSig of vin 0 and
# 2) (optionally) modify the nSequence of vin 0 and the tx's nLockTime
-def cltv_modify_tx(node, tx, prepend_scriptsig, nsequence=None, nlocktime=None):
+def cltv_modify_tx(tx, prepend_scriptsig, nsequence=None, nlocktime=None):
assert_equal(len(tx.vin), 1)
if nsequence is not None:
tx.vin[0].nSequence = nsequence
@@ -45,10 +45,9 @@ def cltv_modify_tx(node, tx, prepend_scriptsig, nsequence=None, nlocktime=None):
tx.vin[0].scriptSig = CScript(prepend_scriptsig + list(CScript(tx.vin[0].scriptSig)))
tx.rehash()
- return tx
-def cltv_invalidate(node, tx, failure_reason):
+def cltv_invalidate(tx, failure_reason):
# Modify the signature in vin 0 and nSequence/nLockTime of the tx to fail CLTV
#
# According to BIP65, OP_CHECKLOCKTIMEVERIFY can fail due the following reasons:
@@ -69,14 +68,14 @@ def cltv_invalidate(node, tx, failure_reason):
[[CScriptNum(500), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0xffffffff, 500],
][failure_reason]
- return cltv_modify_tx(node, tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
+ cltv_modify_tx(tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
-def cltv_validate(node, tx, height):
+def cltv_validate(tx, height):
# Modify the signature in vin 0 and nSequence/nLockTime of the tx to pass CLTV
scheme = [[CScriptNum(height), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, height]
- return cltv_modify_tx(node, tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
+ cltv_modify_tx(tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
class BIP65Test(BitcoinTestFramework):
@@ -111,17 +110,17 @@ class BIP65Test(BitcoinTestFramework):
self.log.info("Test that invalid-according-to-CLTV transactions can still appear in a block")
# create one invalid tx per CLTV failure reason (5 in total) and collect them
- invalid_ctlv_txs = []
+ invalid_cltv_txs = []
for i in range(5):
spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx']
- spendtx = cltv_invalidate(self.nodes[0], spendtx, i)
- invalid_ctlv_txs.append(spendtx)
+ cltv_invalidate(spendtx, i)
+ invalid_cltv_txs.append(spendtx)
tip = self.nodes[0].getbestblockhash()
block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time)
block.nVersion = 3
- block.vtx.extend(invalid_ctlv_txs)
+ block.vtx.extend(invalid_cltv_txs)
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
@@ -149,7 +148,7 @@ class BIP65Test(BitcoinTestFramework):
# create and test one invalid tx per CLTV failure reason (5 in total)
for i in range(5):
spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx']
- spendtx = cltv_invalidate(self.nodes[0], spendtx, i)
+ cltv_invalidate(spendtx, i)
expected_cltv_reject_reason = [
"non-mandatory-script-verify-flag (Operation not valid with the current stack size)",
@@ -182,7 +181,7 @@ class BIP65Test(BitcoinTestFramework):
peer.sync_with_ping()
self.log.info("Test that a version 4 block with a valid-according-to-CLTV transaction is accepted")
- spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1)
+ cltv_validate(spendtx, CLTV_HEIGHT - 1)
block.vtx.pop(1)
block.vtx.append(spendtx)
diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py
index d3adde5cc5..cf270b25ee 100755
--- a/test/functional/feature_coinstatsindex.py
+++ b/test/functional/feature_coinstatsindex.py
@@ -12,6 +12,7 @@ the index.
from decimal import Decimal
from test_framework.blocktools import (
+ COINBASE_MATURITY,
create_block,
create_coinbase,
)
@@ -68,7 +69,7 @@ class CoinStatsIndexTest(BitcoinTestFramework):
index_hash_options = ['none', 'muhash']
# Generate a normal transaction and mine it
- node.generate(101)
+ node.generate(COINBASE_MATURITY + 1)
address = self.nodes[0].get_deterministic_priv_key().address
node.sendtoaddress(address=address, amount=10, subtractfeefromamount=True)
node.generate(1)
diff --git a/test/functional/feature_loadblock.py b/test/functional/feature_loadblock.py
index 0a457ca17f..14f64d63a2 100755
--- a/test/functional/feature_loadblock.py
+++ b/test/functional/feature_loadblock.py
@@ -16,6 +16,7 @@ import sys
import tempfile
import urllib
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
@@ -28,7 +29,7 @@ class LoadblockTest(BitcoinTestFramework):
def run_test(self):
self.nodes[1].setnetworkactive(state=False)
- self.nodes[0].generate(100)
+ self.nodes[0].generate(COINBASE_MATURITY)
# Parsing the url of our node to get settings for config file
data_dir = self.nodes[0].datadir
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index c7981d31dc..f467626801 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -14,15 +14,21 @@ Generate COINBASE_MATURITY (CB) more blocks to ensure the coinbases are mature.
"""
import time
-from test_framework.blocktools import NORMAL_GBT_REQUEST_PARAMS, create_block, create_transaction, add_witness_commitment
+from test_framework.blocktools import (
+ COINBASE_MATURITY,
+ NORMAL_GBT_REQUEST_PARAMS,
+ add_witness_commitment,
+ create_block,
+ create_transaction,
+)
from test_framework.messages import CTransaction
from test_framework.script import CScript
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
-COINBASE_MATURITY = 100
NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)"
+
def trueDummy(tx):
scriptSig = CScript(tx.vin[0].scriptSig)
newscript = []
@@ -35,18 +41,17 @@ def trueDummy(tx):
tx.vin[0].scriptSig = CScript(newscript)
tx.rehash()
-class NULLDUMMYTest(BitcoinTestFramework):
+class NULLDUMMYTest(BitcoinTestFramework):
def set_test_params(self):
- # Need two nodes so GBT (getblocktemplate) doesn't complain that it's not connected.
- self.num_nodes = 2
+ self.num_nodes = 1
self.setup_clean_chain = True
# This script tests NULLDUMMY activation, which is part of the 'segwit' deployment, so we go through
# normal segwit activation here (and don't use the default always-on behaviour).
self.extra_args = [[
f'-segwitheight={COINBASE_MATURITY + 5}',
'-addresstype=legacy',
- ]] * 2
+ ]]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py
index 8bee43b8ad..162814815e 100755
--- a/test/functional/feature_proxy.py
+++ b/test/functional/feature_proxy.py
@@ -147,13 +147,13 @@ class ProxyTest(BitcoinTestFramework):
self.network_test(node, addr, network=NET_IPV6)
if test_onion:
- addr = "bitcoinostk4e4re.onion:8333"
+ addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:8333"
self.log.debug("Test: outgoing onion connection through node for address {}".format(addr))
node.addnode(addr, "onetry")
cmd = proxies[2].queue.get()
assert isinstance(cmd, Socks5Command)
assert_equal(cmd.atyp, AddressType.DOMAINNAME)
- assert_equal(cmd.addr, b"bitcoinostk4e4re.onion")
+ assert_equal(cmd.addr, b"pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion")
assert_equal(cmd.port, 8333)
if not auth:
assert_equal(cmd.username, None)
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index 945880cc3b..0bb04ae267 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -6,6 +6,7 @@
from decimal import Decimal
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut
from test_framework.script import CScript, OP_DROP
from test_framework.test_framework import BitcoinTestFramework
@@ -27,7 +28,7 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=DUMMY_P2WPKH_SCRIPT):
"""
fee = 1*COIN
while node.getbalance() < satoshi_round((amount + fee)/COIN):
- node.generate(100)
+ node.generate(COINBASE_MATURITY)
new_addr = node.getnewaddress()
txid = node.sendtoaddress(new_addr, satoshi_round((amount+fee)/COIN))
@@ -115,6 +116,9 @@ class ReplaceByFeeTest(BitcoinTestFramework):
self.log.info("Running test prioritised transactions...")
self.test_prioritised_transactions()
+ self.log.info("Running test no inherited signaling...")
+ self.test_no_inherited_signaling()
+
self.log.info("Passed")
def test_simple_doublespend(self):
@@ -563,5 +567,69 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert_equal(json0["vin"][0]["sequence"], 4294967293)
assert_equal(json1["vin"][0]["sequence"], 4294967294)
+ def test_no_inherited_signaling(self):
+ # Send tx from which to conflict outputs later
+ base_txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
+ self.nodes[0].generate(1)
+ self.sync_blocks()
+
+ # Create an explicitly opt-in parent transaction
+ optin_parent_tx = self.nodes[0].createrawtransaction([{
+ 'txid': base_txid,
+ 'vout': 0,
+ "sequence": 0xfffffffd,
+ }], {self.nodes[0].getnewaddress(): Decimal("9.99998")})
+
+ optin_parent_tx = self.nodes[0].signrawtransactionwithwallet(optin_parent_tx)
+
+ # Broadcast parent tx
+ optin_parent_txid = self.nodes[0].sendrawtransaction(hexstring=optin_parent_tx["hex"], maxfeerate=0)
+ assert optin_parent_txid in self.nodes[0].getrawmempool()
+
+ replacement_parent_tx = self.nodes[0].createrawtransaction([{
+ 'txid': base_txid,
+ 'vout': 0,
+ "sequence": 0xfffffffd,
+ }], {self.nodes[0].getnewaddress(): Decimal("9.90000")})
+
+ replacement_parent_tx = self.nodes[0].signrawtransactionwithwallet(replacement_parent_tx)
+
+ # Test if parent tx can be replaced.
+ res = self.nodes[0].testmempoolaccept(rawtxs=[replacement_parent_tx['hex']], maxfeerate=0)[0]
+
+ # Parent can be replaced.
+ assert_equal(res['allowed'], True)
+
+ # Create an opt-out child tx spending the opt-in parent
+ optout_child_tx = self.nodes[0].createrawtransaction([{
+ 'txid': optin_parent_txid,
+ 'vout': 0,
+ "sequence": 0xffffffff,
+ }], {self.nodes[0].getnewaddress(): Decimal("9.99990")})
+
+ optout_child_tx = self.nodes[0].signrawtransactionwithwallet(optout_child_tx)
+
+ # Broadcast child tx
+ optout_child_txid = self.nodes[0].sendrawtransaction(hexstring=optout_child_tx["hex"], maxfeerate=0)
+ assert optout_child_txid in self.nodes[0].getrawmempool()
+
+ replacement_child_tx = self.nodes[0].createrawtransaction([{
+ 'txid': optin_parent_txid,
+ 'vout': 0,
+ "sequence": 0xffffffff,
+ }], {self.nodes[0].getnewaddress(): Decimal("9.00000")})
+
+ replacement_child_tx = self.nodes[0].signrawtransactionwithwallet(replacement_child_tx)
+
+ # Broadcast replacement child tx
+ # BIP 125 :
+ # 1. The original transactions signal replaceability explicitly or through inheritance as described in the above
+ # Summary section.
+ # The original transaction (`optout_child_tx`) doesn't signal RBF but its parent (`optin_parent_txid`) does.
+ # The replacement transaction (`replacement_child_tx`) should be able to replace the original transaction.
+ # See CVE-2021-31876 for further explanations.
+ assert optin_parent_txid in self.nodes[0].getrawmempool()
+ assert_raises_rpc_error(-26, 'txn-mempool-conflict', self.nodes[0].sendrawtransaction, replacement_child_tx["hex"], 0)
+
if __name__ == '__main__':
ReplaceByFeeTest().main()
diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py
index 183a43abd4..fc04853199 100755
--- a/test/functional/feature_taproot.py
+++ b/test/functional/feature_taproot.py
@@ -5,6 +5,7 @@
# Test Taproot softfork (BIPs 340-342)
from test_framework.blocktools import (
+ COINBASE_MATURITY,
create_coinbase,
create_block,
add_witness_commitment,
@@ -1440,7 +1441,7 @@ class TaprootTest(BitcoinTestFramework):
def run_test(self):
# Post-taproot activation tests go first (pre-taproot tests' blocks are invalid post-taproot).
self.log.info("Post-activation tests...")
- self.nodes[1].generate(101)
+ self.nodes[1].generate(COINBASE_MATURITY + 1)
self.test_spenders(self.nodes[1], spenders_taproot_active(), input_counts=[1, 2, 2, 2, 2, 3])
# Re-connect nodes in case they have been disconnected
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index b5ce18a48b..30cd499b3f 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -5,6 +5,8 @@
"""Test bitcoin-cli"""
from decimal import Decimal
+
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -16,7 +18,7 @@ from test_framework.util import (
# The block reward of coinbaseoutput.nValue (50) BTC/block matures after
# COINBASE_MATURITY (100) blocks. Therefore, after mining 101 blocks we expect
# node 0 to have a balance of (BLOCKS - COINBASE_MATURITY) * 50 BTC/block.
-BLOCKS = 101
+BLOCKS = COINBASE_MATURITY + 1
BALANCE = (BLOCKS - 100) * 50
JSON_PARSING_ERROR = 'error: Error parsing JSON: foo'
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index c4002f524a..12aac3ab65 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -67,7 +67,8 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
self.log.info('Should not accept garbage to testmempoolaccept')
assert_raises_rpc_error(-3, 'Expected type array, got string', lambda: node.testmempoolaccept(rawtxs='ff00baar'))
- assert_raises_rpc_error(-8, 'Array must contain exactly one raw transaction for now', lambda: node.testmempoolaccept(rawtxs=['ff00baar', 'ff22']))
+ assert_raises_rpc_error(-8, 'Array must contain between 1 and 25 transactions.', lambda: node.testmempoolaccept(rawtxs=['ff22']*26))
+ assert_raises_rpc_error(-8, 'Array must contain between 1 and 25 transactions.', lambda: node.testmempoolaccept(rawtxs=[]))
assert_raises_rpc_error(-22, 'TX decode failed', lambda: node.testmempoolaccept(rawtxs=['ff00baar']))
self.log.info('A transaction already in the blockchain')
diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py
index eb08765ebf..6de6778909 100755
--- a/test/functional/mempool_compatibility.py
+++ b/test/functional/mempool_compatibility.py
@@ -15,6 +15,7 @@ Only v0.15.2 is required by this test. The rest is used in other backwards compa
import os
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.wallet import MiniWallet
@@ -41,7 +42,7 @@ class MempoolCompatibilityTest(BitcoinTestFramework):
old_node, new_node = self.nodes
new_wallet = MiniWallet(new_node)
new_wallet.generate(1)
- new_node.generate(100)
+ new_node.generate(COINBASE_MATURITY)
# Sync the nodes to ensure old_node has the block that contains the coinbase that new_wallet will spend.
# Otherwise, because coinbases are only valid in a block and not as loose txns, if the nodes aren't synced
# unbroadcasted_tx won't pass old_node's `MemPoolAccept::PreChecks`.
diff --git a/test/functional/mempool_expiry.py b/test/functional/mempool_expiry.py
index 4c46075ae9..7d1bfef333 100755
--- a/test/functional/mempool_expiry.py
+++ b/test/functional/mempool_expiry.py
@@ -12,6 +12,7 @@ definable expiry timeout via the '-mempoolexpiry=<n>' command line argument
from datetime import timedelta
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -36,7 +37,7 @@ class MempoolExpiryTest(BitcoinTestFramework):
# Add enough mature utxos to the wallet so that all txs spend confirmed coins.
self.wallet.generate(4)
- node.generate(100)
+ node.generate(COINBASE_MATURITY)
# Send a parent transaction that will expire.
parent_txid = self.wallet.send_self_transfer(from_node=node)['txid']
diff --git a/test/functional/mempool_package_onemore.py b/test/functional/mempool_package_onemore.py
index 884a2fef11..1e9895e621 100755
--- a/test/functional/mempool_package_onemore.py
+++ b/test/functional/mempool_package_onemore.py
@@ -9,6 +9,7 @@
from decimal import Decimal
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error, satoshi_round
@@ -42,7 +43,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
def run_test(self):
# Mine some blocks and have them mature.
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
utxo = self.nodes[0].listunspent(10)
txid = utxo[0]['txid']
vout = utxo[0]['vout']
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index 461f9237ff..606717d890 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -6,6 +6,7 @@
from decimal import Decimal
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import COIN
from test_framework.p2p import P2PTxInvStore
from test_framework.test_framework import BitcoinTestFramework
@@ -59,7 +60,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
def run_test(self):
# Mine some blocks and have them mature.
peer_inv_store = self.nodes[0].add_p2p_connection(P2PTxInvStore()) # keep track of invs
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
utxo = self.nodes[0].listunspent(10)
txid = utxo[0]['txid']
vout = utxo[0]['vout']
diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py
index 8e1f87e42c..bcc6aa7bcc 100755
--- a/test/functional/mempool_reorg.py
+++ b/test/functional/mempool_reorg.py
@@ -8,10 +8,9 @@ Test re-org scenarios with a mempool that contains transactions
that spend (directly or indirectly) coinbase transactions.
"""
-from test_framework.blocktools import create_raw_transaction
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
-
+from test_framework.wallet import MiniWallet
class MempoolCoinbaseTest(BitcoinTestFramework):
def set_test_params(self):
@@ -23,86 +22,90 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
[]
]
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def run_test(self):
+ wallet = MiniWallet(self.nodes[0])
+
# Start with a 200 block chain
assert_equal(self.nodes[0].getblockcount(), 200)
- # Mine four blocks. After this, nodes[0] blocks
- # 101, 102, and 103 are spend-able.
- new_blocks = self.nodes[1].generate(4)
- self.sync_all()
-
- node0_address = self.nodes[0].getnewaddress()
- node1_address = self.nodes[1].getnewaddress()
+ self.log.info("Add 4 coinbase utxos to the miniwallet")
+ # Block 76 contains the first spendable coinbase txs.
+ first_block = 76
+ wallet.scan_blocks(start=first_block, num=4)
# Three scenarios for re-orging coinbase spends in the memory pool:
- # 1. Direct coinbase spend : spend_101
- # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1
- # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1
- # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase),
+ # 1. Direct coinbase spend : spend_1
+ # 2. Indirect (coinbase spend in chain, child in mempool) : spend_2 and spend_2_1
+ # 3. Indirect (coinbase and child both in chain) : spend_3 and spend_3_1
+ # Use invalidateblock to make all of the above coinbase spends invalid (immature coinbase),
# and make sure the mempool code behaves correctly.
- b = [self.nodes[0].getblockhash(n) for n in range(101, 105)]
+ b = [self.nodes[0].getblockhash(n) for n in range(first_block, first_block+4)]
coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
- spend_101_raw = create_raw_transaction(self.nodes[0], coinbase_txids[1], node1_address, amount=49.99)
- spend_102_raw = create_raw_transaction(self.nodes[0], coinbase_txids[2], node0_address, amount=49.99)
- spend_103_raw = create_raw_transaction(self.nodes[0], coinbase_txids[3], node0_address, amount=49.99)
-
- # Create a transaction which is time-locked to two blocks in the future
- timelock_tx = self.nodes[0].createrawtransaction(
- inputs=[{
- "txid": coinbase_txids[0],
- "vout": 0,
- }],
- outputs={node0_address: 49.99},
- locktime=self.nodes[0].getblockcount() + 2,
- )
- timelock_tx = self.nodes[0].signrawtransactionwithwallet(timelock_tx)["hex"]
- # This will raise an exception because the timelock transaction is too immature to spend
+ utxo_1 = wallet.get_utxo(txid=coinbase_txids[1])
+ utxo_2 = wallet.get_utxo(txid=coinbase_txids[2])
+ utxo_3 = wallet.get_utxo(txid=coinbase_txids[3])
+ self.log.info("Create three transactions spending from coinbase utxos: spend_1, spend_2, spend_3")
+ spend_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_1)
+ spend_2 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_2)
+ spend_3 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_3)
+
+ self.log.info("Create another transaction which is time-locked to two blocks in the future")
+ utxo = wallet.get_utxo(txid=coinbase_txids[0])
+ timelock_tx = wallet.create_self_transfer(
+ from_node=self.nodes[0],
+ utxo_to_spend=utxo,
+ mempool_valid=False,
+ locktime=self.nodes[0].getblockcount() + 2
+ )['hex']
+
+ self.log.info("Check that the time-locked transaction is too immature to spend")
assert_raises_rpc_error(-26, "non-final", self.nodes[0].sendrawtransaction, timelock_tx)
- # Broadcast and mine spend_102 and 103:
- spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw)
- spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw)
+ self.log.info("Broadcast and mine spend_2 and spend_3")
+ wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=spend_2['hex'])
+ wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=spend_3['hex'])
+ self.log.info("Generate a block")
self.nodes[0].generate(1)
- # Time-locked transaction is still too immature to spend
+ self.log.info("Check that time-locked transaction is still too immature to spend")
assert_raises_rpc_error(-26, 'non-final', self.nodes[0].sendrawtransaction, timelock_tx)
- # Create 102_1 and 103_1:
- spend_102_1_raw = create_raw_transaction(self.nodes[0], spend_102_id, node1_address, amount=49.98)
- spend_103_1_raw = create_raw_transaction(self.nodes[0], spend_103_id, node1_address, amount=49.98)
+ self.log.info("Create spend_2_1 and spend_3_1")
+ spend_2_utxo = wallet.get_utxo(txid=spend_2['txid'])
+ spend_2_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=spend_2_utxo)
+ spend_3_utxo = wallet.get_utxo(txid=spend_3['txid'])
+ spend_3_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=spend_3_utxo)
- # Broadcast and mine 103_1:
- spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw)
+ self.log.info("Broadcast and mine spend_3_1")
+ spend_3_1_id = self.nodes[0].sendrawtransaction(spend_3_1['hex'])
+ self.log.info("Generate a block")
last_block = self.nodes[0].generate(1)
# Sync blocks, so that peer 1 gets the block before timelock_tx
# Otherwise, peer 1 would put the timelock_tx in recentRejects
self.sync_all()
- # Time-locked transaction can now be spent
+ self.log.info("The time-locked transaction can now be spent")
timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx)
- # ... now put spend_101 and spend_102_1 in memory pools:
- spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw)
- spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw)
+ self.log.info("Add spend_1 and spend_2_1 to the mempool")
+ spend_1_id = self.nodes[0].sendrawtransaction(spend_1['hex'])
+ spend_2_1_id = self.nodes[0].sendrawtransaction(spend_2_1['hex'])
- assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, timelock_tx_id})
+ assert_equal(set(self.nodes[0].getrawmempool()), {spend_1_id, spend_2_1_id, timelock_tx_id})
self.sync_all()
+ self.log.info("invalidate the last block")
for node in self.nodes:
node.invalidateblock(last_block[0])
- # Time-locked transaction is now too immature and has been removed from the mempool
- # spend_103_1 has been re-orged out of the chain and is back in the mempool
- assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, spend_103_1_id})
+ self.log.info("The time-locked transaction is now too immature and has been removed from the mempool")
+ self.log.info("spend_3_1 has been re-orged out of the chain and is back in the mempool")
+ assert_equal(set(self.nodes[0].getrawmempool()), {spend_1_id, spend_2_1_id, spend_3_1_id})
- # Use invalidateblock to re-org back and make all those coinbase spends
- # immature/invalid:
+ self.log.info("Use invalidateblock to re-org back and make all those coinbase spends immature/invalid")
+ b = self.nodes[0].getblockhash(first_block + 100)
for node in self.nodes:
- node.invalidateblock(new_blocks[0])
+ node.invalidateblock(b)
- # mempool should be empty.
+ self.log.info("Check that the mempool is empty")
assert_equal(set(self.nodes[0].getrawmempool()), set())
self.sync_all()
diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py
index 4aa58270b6..1b5ca7e15a 100755
--- a/test/functional/mempool_resurrect.py
+++ b/test/functional/mempool_resurrect.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test resurrection of mined transactions when the blockchain is re-organized."""
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.wallet import MiniWallet
@@ -20,7 +21,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
# Add enough mature utxos to the wallet so that all txs spend confirmed coins
wallet.generate(3)
- node.generate(100)
+ node.generate(COINBASE_MATURITY)
# Spend block 1/2/3's coinbase transactions
# Mine a block
diff --git a/test/functional/mining_getblocktemplate_longpoll.py b/test/functional/mining_getblocktemplate_longpoll.py
index cc32f78e2e..715b68e04c 100755
--- a/test/functional/mining_getblocktemplate_longpoll.py
+++ b/test/functional/mining_getblocktemplate_longpoll.py
@@ -8,6 +8,7 @@ from decimal import Decimal
import random
import threading
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import get_rpc_proxy
from test_framework.wallet import MiniWallet
@@ -62,7 +63,7 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
assert not thr.is_alive()
# Add enough mature utxos to the wallets, so that all txs spend confirmed coins
- self.nodes[0].generate(100)
+ self.nodes[0].generate(COINBASE_MATURITY)
self.sync_blocks()
self.log.info("Test that introducing a new transaction into the mempool will terminate the longpoll")
diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py
index ab2556cd72..6409d4ea82 100755
--- a/test/functional/p2p_blocksonly.py
+++ b/test/functional/p2p_blocksonly.py
@@ -6,6 +6,7 @@
import time
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import msg_tx
from test_framework.p2p import P2PInterface, P2PTxInvStore
from test_framework.test_framework import BitcoinTestFramework
@@ -23,7 +24,7 @@ class P2PBlocksOnly(BitcoinTestFramework):
self.miniwallet = MiniWallet(self.nodes[0])
# Add enough mature utxos to the wallet, so that all txs spend confirmed coins
self.miniwallet.generate(2)
- self.nodes[0].generate(100)
+ self.nodes[0].generate(COINBASE_MATURITY)
self.blocksonly_mode_tests()
self.blocks_relay_conn_tests()
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index 55573efc06..3e4f2f974d 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -9,7 +9,12 @@ Version 2 compact blocks are post-segwit (wtxids)
"""
import random
-from test_framework.blocktools import create_block, NORMAL_GBT_REQUEST_PARAMS, add_witness_commitment
+from test_framework.blocktools import (
+ COINBASE_MATURITY,
+ NORMAL_GBT_REQUEST_PARAMS,
+ add_witness_commitment,
+ create_block,
+)
from test_framework.messages import BlockTransactions, BlockTransactionsRequest, calculate_shortid, CBlock, CBlockHeader, CInv, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, HeaderAndShortIDs, msg_no_witness_block, msg_no_witness_blocktxn, msg_cmpctblock, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_sendcmpct, msg_sendheaders, msg_tx, msg_block, msg_blocktxn, MSG_BLOCK, MSG_CMPCT_BLOCK, MSG_WITNESS_FLAG, NODE_NETWORK, P2PHeaderAndShortIDs, PrefilledTransaction, ser_uint256, ToHex
from test_framework.p2p import p2p_lock, P2PInterface
from test_framework.script import CScript, OP_TRUE, OP_DROP
@@ -115,7 +120,7 @@ class CompactBlocksTest(BitcoinTestFramework):
block = self.build_block_on_tip(self.nodes[0])
self.segwit_node.send_and_ping(msg_no_witness_block(block))
assert int(self.nodes[0].getbestblockhash(), 16) == block.sha256
- self.nodes[0].generatetoaddress(100, self.nodes[0].getnewaddress(address_type="bech32"))
+ self.nodes[0].generatetoaddress(COINBASE_MATURITY, self.nodes[0].getnewaddress(address_type="bech32"))
total_value = block.vtx[0].vout[0].nValue
out_value = total_value // 10
@@ -226,7 +231,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# This test actually causes bitcoind to (reasonably!) disconnect us, so do this last.
def test_invalid_cmpctblock_message(self):
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
block = self.build_block_on_tip(self.nodes[0])
cmpct_block = P2PHeaderAndShortIDs()
@@ -244,7 +249,7 @@ class CompactBlocksTest(BitcoinTestFramework):
version = test_node.cmpct_version
node = self.nodes[0]
# Generate a bunch of transactions.
- node.generate(101)
+ node.generate(COINBASE_MATURITY + 1)
num_transactions = 25
address = node.getnewaddress()
diff --git a/test/functional/p2p_eviction.py b/test/functional/p2p_eviction.py
index d60aa5b383..a525996493 100755
--- a/test/functional/p2p_eviction.py
+++ b/test/functional/p2p_eviction.py
@@ -15,7 +15,11 @@ Therefore, this test is limited to the remaining protection criteria.
import time
-from test_framework.blocktools import create_block, create_coinbase
+from test_framework.blocktools import (
+ COINBASE_MATURITY,
+ create_block,
+ create_coinbase,
+)
from test_framework.messages import CTransaction, FromHex, msg_pong, msg_tx
from test_framework.p2p import P2PDataStore, P2PInterface
from test_framework.test_framework import BitcoinTestFramework
@@ -45,7 +49,7 @@ class P2PEvict(BitcoinTestFramework):
protected_peers = set() # peers that we expect to be protected from eviction
current_peer = -1
node = self.nodes[0]
- node.generatetoaddress(101, node.get_deterministic_priv_key().address)
+ node.generatetoaddress(COINBASE_MATURITY + 1, node.get_deterministic_priv_key().address)
self.log.info("Create 4 peers and protect them from eviction by sending us a block")
for _ in range(4):
diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py
index 52dc4de3bd..0175b9f6c0 100755
--- a/test/functional/p2p_feefilter.py
+++ b/test/functional/p2p_feefilter.py
@@ -6,6 +6,7 @@
from decimal import Decimal
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import MSG_TX, MSG_WTX, msg_feefilter
from test_framework.p2p import P2PInterface, p2p_lock
from test_framework.test_framework import BitcoinTestFramework
@@ -81,7 +82,7 @@ class FeeFilterTest(BitcoinTestFramework):
miniwallet = MiniWallet(node1)
# Add enough mature utxos to the wallet, so that all txs spend confirmed coins
miniwallet.generate(5)
- node1.generate(100)
+ node1.generate(COINBASE_MATURITY)
conn = self.nodes[0].add_p2p_connection(TestP2PConn())
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index 71d5ca92b3..f1538e8ac7 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -29,6 +29,8 @@ from test_framework.util import (
assert_greater_than_or_equal,
)
+PEER_TIMEOUT = 3
+
class LazyPeer(P2PInterface):
def __init__(self):
@@ -98,7 +100,7 @@ class P2PVersionStore(P2PInterface):
class P2PLeakTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['-peertimeout=4']]
+ self.extra_args = [[f"-peertimeout={PEER_TIMEOUT}"]]
def create_old_version(self, nversion):
old_version_msg = msg_version()
@@ -134,7 +136,7 @@ class P2PLeakTest(BitcoinTestFramework):
self.nodes[0].generate(nblocks=1)
# Give the node enough time to possibly leak out a message
- time.sleep(5)
+ time.sleep(PEER_TIMEOUT + 2)
# Make sure only expected messages came in
assert not no_version_idle_peer.unexpected_msg
diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py
index a45f792e81..9a4ceb86ae 100755
--- a/test/functional/p2p_leak_tx.py
+++ b/test/functional/p2p_leak_tx.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test that we don't leak txs to inbound peers that we haven't yet announced to"""
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import msg_getdata, CInv, MSG_TX
from test_framework.p2p import p2p_lock, P2PDataStore
from test_framework.test_framework import BitcoinTestFramework
@@ -27,7 +28,7 @@ class P2PLeakTxTest(BitcoinTestFramework):
miniwallet = MiniWallet(gen_node)
# Add enough mature utxos to the wallet, so that all txs spend confirmed coins
miniwallet.generate(1)
- gen_node.generate(100)
+ gen_node.generate(COINBASE_MATURITY)
inbound_peer = self.nodes[0].add_p2p_connection(P2PNode()) # An "attacking" inbound peer
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index 19f0d5765a..af515f3a27 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -9,6 +9,7 @@ import itertools
import json
import os
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.authproxy import JSONRPCException
from test_framework.descriptors import descsum_create, drop_origins
from test_framework.key import ECPubKey, ECKey
@@ -109,7 +110,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
def checkbalances(self):
node0, node1, node2 = self.nodes
- node0.generate(100)
+ node0.generate(COINBASE_MATURITY)
self.sync_all()
bal0 = node0.getbalance()
diff --git a/test/functional/rpc_dumptxoutset.py b/test/functional/rpc_dumptxoutset.py
index dc469ba552..3efbdab013 100755
--- a/test/functional/rpc_dumptxoutset.py
+++ b/test/functional/rpc_dumptxoutset.py
@@ -4,6 +4,8 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the generation of UTXO snapshots using `dumptxoutset`.
"""
+
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
@@ -21,7 +23,7 @@ class DumptxoutsetTest(BitcoinTestFramework):
node = self.nodes[0]
mocktime = node.getblockheader(node.getblockhash(0))['time'] + 1
node.setmocktime(mocktime)
- node.generate(100)
+ node.generate(COINBASE_MATURITY)
FILENAME = 'txoutset.dat'
out = node.dumptxoutset(FILENAME)
diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py
index 57794ae973..4af518c870 100755
--- a/test/functional/rpc_getblockstats.py
+++ b/test/functional/rpc_getblockstats.py
@@ -6,6 +6,8 @@
#
# Test getblockstats rpc call
#
+
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -41,7 +43,7 @@ class GetblockstatsTest(BitcoinTestFramework):
def generate_test_data(self, filename):
mocktime = 1525107225
self.nodes[0].setmocktime(mocktime)
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
address = self.nodes[0].get_deterministic_priv_key().address
self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=True)
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
index 9a2817a6ee..6e5ef770d1 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -11,6 +11,7 @@ from decimal import Decimal
from itertools import product
import time
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.p2p import P2PInterface
import test_framework.messages
from test_framework.messages import (
@@ -53,7 +54,7 @@ class NetTest(BitcoinTestFramework):
self.wallet = MiniWallet(self.nodes[0])
self.wallet.generate(1)
# Get out of IBD for the minfeefilter and getpeerinfo tests.
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
# By default, the test framework sets up an addnode connection from
# node 1 --> node0. By connecting node0 --> node 1, we're left with
diff --git a/test/functional/rpc_packages.py b/test/functional/rpc_packages.py
new file mode 100755
index 0000000000..3d8d81d6b8
--- /dev/null
+++ b/test/functional/rpc_packages.py
@@ -0,0 +1,362 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""RPCs that handle raw transaction packages."""
+
+from decimal import Decimal
+from io import BytesIO
+import random
+
+from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.messages import (
+ BIP125_SEQUENCE_NUMBER,
+ COIN,
+ CTransaction,
+ CTxInWitness,
+)
+from test_framework.script import (
+ CScript,
+ OP_TRUE,
+)
+from test_framework.util import (
+ assert_equal,
+ hex_str_to_bytes,
+)
+
+class RPCPackagesTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+
+ def assert_testres_equal(self, package_hex, testres_expected):
+ """Shuffle package_hex and assert that the testmempoolaccept result matches testres_expected. This should only
+ be used to test packages where the order does not matter. The ordering of transactions in package_hex and
+ testres_expected must match.
+ """
+ shuffled_indeces = list(range(len(package_hex)))
+ random.shuffle(shuffled_indeces)
+ shuffled_package = [package_hex[i] for i in shuffled_indeces]
+ shuffled_testres = [testres_expected[i] for i in shuffled_indeces]
+ assert_equal(shuffled_testres, self.nodes[0].testmempoolaccept(shuffled_package))
+
+ def run_test(self):
+ self.log.info("Generate blocks to create UTXOs")
+ node = self.nodes[0]
+ self.privkeys = [node.get_deterministic_priv_key().key]
+ self.address = node.get_deterministic_priv_key().address
+ self.coins = []
+ # The last 100 coinbase transactions are premature
+ for b in node.generatetoaddress(200, self.address)[:100]:
+ coinbase = node.getblock(blockhash=b, verbosity=2)["tx"][0]
+ self.coins.append({
+ "txid": coinbase["txid"],
+ "amount": coinbase["vout"][0]["value"],
+ "scriptPubKey": coinbase["vout"][0]["scriptPubKey"],
+ })
+
+ # Create some transactions that can be reused throughout the test. Never submit these to mempool.
+ self.independent_txns_hex = []
+ self.independent_txns_testres = []
+ for _ in range(3):
+ coin = self.coins.pop()
+ rawtx = node.createrawtransaction([{"txid": coin["txid"], "vout": 0}],
+ {self.address : coin["amount"] - Decimal("0.0001")})
+ signedtx = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=self.privkeys)
+ assert signedtx["complete"]
+ testres = node.testmempoolaccept([signedtx["hex"]])
+ assert testres[0]["allowed"]
+ self.independent_txns_hex.append(signedtx["hex"])
+ # testmempoolaccept returns a list of length one, avoid creating a 2D list
+ self.independent_txns_testres.append(testres[0])
+ self.independent_txns_testres_blank = [{
+ "txid": res["txid"], "wtxid": res["wtxid"]} for res in self.independent_txns_testres]
+
+ self.test_independent()
+ self.test_chain()
+ self.test_multiple_children()
+ self.test_multiple_parents()
+ self.test_conflicting()
+ self.test_rbf()
+
+ def chain_transaction(self, parent_txid, parent_value, n=0, parent_locking_script=None):
+ """Build a transaction that spends parent_txid.vout[n] and produces one output with
+ amount = parent_value with a fee deducted.
+ Return tuple (CTransaction object, raw hex, nValue, scriptPubKey of the output created).
+ """
+ node = self.nodes[0]
+ inputs = [{"txid": parent_txid, "vout": n}]
+ my_value = parent_value - Decimal("0.0001")
+ outputs = {self.address : my_value}
+ rawtx = node.createrawtransaction(inputs, outputs)
+ prevtxs = [{
+ "txid": parent_txid,
+ "vout": n,
+ "scriptPubKey": parent_locking_script,
+ "amount": parent_value,
+ }] if parent_locking_script else None
+ signedtx = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=self.privkeys, prevtxs=prevtxs)
+ tx = CTransaction()
+ assert signedtx["complete"]
+ tx.deserialize(BytesIO(hex_str_to_bytes(signedtx["hex"])))
+ return (tx, signedtx["hex"], my_value, tx.vout[0].scriptPubKey.hex())
+
+ def test_independent(self):
+ self.log.info("Test multiple independent transactions in a package")
+ node = self.nodes[0]
+ # For independent transactions, order doesn't matter.
+ self.assert_testres_equal(self.independent_txns_hex, self.independent_txns_testres)
+
+ self.log.info("Test an otherwise valid package with an extra garbage tx appended")
+ garbage_tx = node.createrawtransaction([{"txid": "00" * 32, "vout": 5}], {self.address: 1})
+ tx = CTransaction()
+ tx.deserialize(BytesIO(hex_str_to_bytes(garbage_tx)))
+ # Only the txid and wtxids are returned because validation is incomplete for the independent txns.
+ # Package validation is atomic: if the node cannot find a UTXO for any single tx in the package,
+ # it terminates immediately to avoid unnecessary, expensive signature verification.
+ package_bad = self.independent_txns_hex + [garbage_tx]
+ testres_bad = self.independent_txns_testres_blank + [{"txid": tx.rehash(), "wtxid": tx.getwtxid(), "allowed": False, "reject-reason": "missing-inputs"}]
+ self.assert_testres_equal(package_bad, testres_bad)
+
+ self.log.info("Check testmempoolaccept tells us when some transactions completed validation successfully")
+ coin = self.coins.pop()
+ tx_bad_sig_hex = node.createrawtransaction([{"txid": coin["txid"], "vout": 0}],
+ {self.address : coin["amount"] - Decimal("0.0001")})
+ tx_bad_sig = CTransaction()
+ tx_bad_sig.deserialize(BytesIO(hex_str_to_bytes(tx_bad_sig_hex)))
+ testres_bad_sig = node.testmempoolaccept(self.independent_txns_hex + [tx_bad_sig_hex])
+ # By the time the signature for the last transaction is checked, all the other transactions
+ # have been fully validated, which is why the node returns full validation results for all
+ # transactions here but empty results in other cases.
+ assert_equal(testres_bad_sig, self.independent_txns_testres + [{
+ "txid": tx_bad_sig.rehash(),
+ "wtxid": tx_bad_sig.getwtxid(), "allowed": False,
+ "reject-reason": "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)"
+ }])
+
+ self.log.info("Check testmempoolaccept reports txns in packages that exceed max feerate")
+ coin = self.coins.pop()
+ tx_high_fee_raw = node.createrawtransaction([{"txid": coin["txid"], "vout": 0}],
+ {self.address : coin["amount"] - Decimal("0.999")})
+ tx_high_fee_signed = node.signrawtransactionwithkey(hexstring=tx_high_fee_raw, privkeys=self.privkeys)
+ assert tx_high_fee_signed["complete"]
+ tx_high_fee = CTransaction()
+ tx_high_fee.deserialize(BytesIO(hex_str_to_bytes(tx_high_fee_signed["hex"])))
+ testres_high_fee = node.testmempoolaccept([tx_high_fee_signed["hex"]])
+ assert_equal(testres_high_fee, [
+ {"txid": tx_high_fee.rehash(), "wtxid": tx_high_fee.getwtxid(), "allowed": False, "reject-reason": "max-fee-exceeded"}
+ ])
+ package_high_fee = [tx_high_fee_signed["hex"]] + self.independent_txns_hex
+ testres_package_high_fee = node.testmempoolaccept(package_high_fee)
+ assert_equal(testres_package_high_fee, testres_high_fee + self.independent_txns_testres_blank)
+
+ def test_chain(self):
+ node = self.nodes[0]
+ first_coin = self.coins.pop()
+
+ # Chain of 25 transactions
+ parent_locking_script = None
+ txid = first_coin["txid"]
+ chain_hex = []
+ chain_txns = []
+ value = first_coin["amount"]
+
+ for _ in range(25):
+ (tx, txhex, value, parent_locking_script) = self.chain_transaction(txid, value, 0, parent_locking_script)
+ txid = tx.rehash()
+ chain_hex.append(txhex)
+ chain_txns.append(tx)
+
+ self.log.info("Check that testmempoolaccept requires packages to be sorted by dependency")
+ assert_equal(node.testmempoolaccept(rawtxs=chain_hex[::-1]),
+ [{"txid": tx.rehash(), "wtxid": tx.getwtxid(), "package-error": "package-not-sorted"} for tx in chain_txns[::-1]])
+
+ self.log.info("Testmempoolaccept a chain of 25 transactions")
+ testres_multiple = node.testmempoolaccept(rawtxs=chain_hex)
+
+ testres_single = []
+ # Test accept and then submit each one individually, which should be identical to package test accept
+ for rawtx in chain_hex:
+ testres = node.testmempoolaccept([rawtx])
+ testres_single.append(testres[0])
+ # Submit the transaction now so its child should have no problem validating
+ node.sendrawtransaction(rawtx)
+ assert_equal(testres_single, testres_multiple)
+
+ # Clean up by clearing the mempool
+ node.generate(1)
+
+ def test_multiple_children(self):
+ node = self.nodes[0]
+
+ self.log.info("Testmempoolaccept a package in which a transaction has two children within the package")
+ first_coin = self.coins.pop()
+ value = (first_coin["amount"] - Decimal("0.0002")) / 2 # Deduct reasonable fee and make 2 outputs
+ inputs = [{"txid": first_coin["txid"], "vout": 0}]
+ outputs = [{self.address : value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE : value}]
+ rawtx = node.createrawtransaction(inputs, outputs)
+
+ parent_signed = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=self.privkeys)
+ parent_tx = CTransaction()
+ assert parent_signed["complete"]
+ parent_tx.deserialize(BytesIO(hex_str_to_bytes(parent_signed["hex"])))
+ parent_txid = parent_tx.rehash()
+ assert node.testmempoolaccept([parent_signed["hex"]])[0]["allowed"]
+
+ parent_locking_script_a = parent_tx.vout[0].scriptPubKey.hex()
+ child_value = value - Decimal("0.0001")
+
+ # Child A
+ (_, tx_child_a_hex, _, _) = self.chain_transaction(parent_txid, child_value, 0, parent_locking_script_a)
+ assert not node.testmempoolaccept([tx_child_a_hex])[0]["allowed"]
+
+ # Child B
+ rawtx_b = node.createrawtransaction([{"txid": parent_txid, "vout": 1}], {self.address : child_value})
+ tx_child_b = CTransaction()
+ tx_child_b.deserialize(BytesIO(hex_str_to_bytes(rawtx_b)))
+ tx_child_b.wit.vtxinwit = [CTxInWitness()]
+ tx_child_b.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
+ tx_child_b_hex = tx_child_b.serialize().hex()
+ assert not node.testmempoolaccept([tx_child_b_hex])[0]["allowed"]
+
+ self.log.info("Testmempoolaccept with entire package, should work with children in either order")
+ testres_multiple_ab = node.testmempoolaccept(rawtxs=[parent_signed["hex"], tx_child_a_hex, tx_child_b_hex])
+ testres_multiple_ba = node.testmempoolaccept(rawtxs=[parent_signed["hex"], tx_child_b_hex, tx_child_a_hex])
+ assert all([testres["allowed"] for testres in testres_multiple_ab + testres_multiple_ba])
+
+ testres_single = []
+ # Test accept and then submit each one individually, which should be identical to package testaccept
+ for rawtx in [parent_signed["hex"], tx_child_a_hex, tx_child_b_hex]:
+ testres = node.testmempoolaccept([rawtx])
+ testres_single.append(testres[0])
+ # Submit the transaction now so its child should have no problem validating
+ node.sendrawtransaction(rawtx)
+ assert_equal(testres_single, testres_multiple_ab)
+
+ def create_child_with_parents(self, parents_tx, values, locking_scripts):
+ """Creates a transaction that spends the first output of each parent in parents_tx."""
+ num_parents = len(parents_tx)
+ total_value = sum(values)
+ inputs = [{"txid": tx.rehash(), "vout": 0} for tx in parents_tx]
+ outputs = {self.address : total_value - num_parents * Decimal("0.0001")}
+ rawtx_child = self.nodes[0].createrawtransaction(inputs, outputs)
+ prevtxs = []
+ for i in range(num_parents):
+ prevtxs.append({"txid": parents_tx[i].rehash(), "vout": 0, "scriptPubKey": locking_scripts[i], "amount": values[i]})
+ signedtx_child = self.nodes[0].signrawtransactionwithkey(hexstring=rawtx_child, privkeys=self.privkeys, prevtxs=prevtxs)
+ assert signedtx_child["complete"]
+ return signedtx_child["hex"]
+
+ def test_multiple_parents(self):
+ node = self.nodes[0]
+
+ self.log.info("Testmempoolaccept a package in which a transaction has multiple parents within the package")
+ for num_parents in [2, 10, 24]:
+ # Test a package with num_parents parents and 1 child transaction.
+ package_hex = []
+ parents_tx = []
+ values = []
+ parent_locking_scripts = []
+ for _ in range(num_parents):
+ parent_coin = self.coins.pop()
+ value = parent_coin["amount"]
+ (tx, txhex, value, parent_locking_script) = self.chain_transaction(parent_coin["txid"], value)
+ package_hex.append(txhex)
+ parents_tx.append(tx)
+ values.append(value)
+ parent_locking_scripts.append(parent_locking_script)
+ child_hex = self.create_child_with_parents(parents_tx, values, parent_locking_scripts)
+ # Package accept should work with the parents in any order (as long as parents come before child)
+ for _ in range(10):
+ random.shuffle(package_hex)
+ testres_multiple = node.testmempoolaccept(rawtxs=package_hex + [child_hex])
+ assert all([testres["allowed"] for testres in testres_multiple])
+
+ testres_single = []
+ # Test accept and then submit each one individually, which should be identical to package testaccept
+ for rawtx in package_hex + [child_hex]:
+ testres_single.append(node.testmempoolaccept([rawtx])[0])
+ # Submit the transaction now so its child should have no problem validating
+ node.sendrawtransaction(rawtx)
+ assert_equal(testres_single, testres_multiple)
+
+ def test_conflicting(self):
+ node = self.nodes[0]
+ prevtx = self.coins.pop()
+ inputs = [{"txid": prevtx["txid"], "vout": 0}]
+ output1 = {node.get_deterministic_priv_key().address: 50 - 0.00125}
+ output2 = {ADDRESS_BCRT1_P2WSH_OP_TRUE: 50 - 0.00125}
+
+ # tx1 and tx2 share the same inputs
+ rawtx1 = node.createrawtransaction(inputs, output1)
+ rawtx2 = node.createrawtransaction(inputs, output2)
+ signedtx1 = node.signrawtransactionwithkey(hexstring=rawtx1, privkeys=self.privkeys)
+ signedtx2 = node.signrawtransactionwithkey(hexstring=rawtx2, privkeys=self.privkeys)
+ tx1 = CTransaction()
+ tx1.deserialize(BytesIO(hex_str_to_bytes(signedtx1["hex"])))
+ tx2 = CTransaction()
+ tx2.deserialize(BytesIO(hex_str_to_bytes(signedtx2["hex"])))
+ assert signedtx1["complete"]
+ assert signedtx2["complete"]
+
+ # Ensure tx1 and tx2 are valid by themselves
+ assert node.testmempoolaccept([signedtx1["hex"]])[0]["allowed"]
+ assert node.testmempoolaccept([signedtx2["hex"]])[0]["allowed"]
+
+ self.log.info("Test duplicate transactions in the same package")
+ testres = node.testmempoolaccept([signedtx1["hex"], signedtx1["hex"]])
+ assert_equal(testres, [
+ {"txid": tx1.rehash(), "wtxid": tx1.getwtxid(), "package-error": "conflict-in-package"},
+ {"txid": tx1.rehash(), "wtxid": tx1.getwtxid(), "package-error": "conflict-in-package"}
+ ])
+
+ self.log.info("Test conflicting transactions in the same package")
+ testres = node.testmempoolaccept([signedtx1["hex"], signedtx2["hex"]])
+ assert_equal(testres, [
+ {"txid": tx1.rehash(), "wtxid": tx1.getwtxid(), "package-error": "conflict-in-package"},
+ {"txid": tx2.rehash(), "wtxid": tx2.getwtxid(), "package-error": "conflict-in-package"}
+ ])
+
+ def test_rbf(self):
+ node = self.nodes[0]
+ coin = self.coins.pop()
+ inputs = [{"txid": coin["txid"], "vout": 0, "sequence": BIP125_SEQUENCE_NUMBER}]
+ fee = Decimal('0.00125000')
+ output = {node.get_deterministic_priv_key().address: 50 - fee}
+ raw_replaceable_tx = node.createrawtransaction(inputs, output)
+ signed_replaceable_tx = node.signrawtransactionwithkey(hexstring=raw_replaceable_tx, privkeys=self.privkeys)
+ testres_replaceable = node.testmempoolaccept([signed_replaceable_tx["hex"]])
+ replaceable_tx = CTransaction()
+ replaceable_tx.deserialize(BytesIO(hex_str_to_bytes(signed_replaceable_tx["hex"])))
+ assert_equal(testres_replaceable, [
+ {"txid": replaceable_tx.rehash(), "wtxid": replaceable_tx.getwtxid(),
+ "allowed": True, "vsize": replaceable_tx.get_vsize(), "fees": { "base": fee }}
+ ])
+
+ # Replacement transaction is identical except has double the fee
+ replacement_tx = CTransaction()
+ replacement_tx.deserialize(BytesIO(hex_str_to_bytes(signed_replaceable_tx["hex"])))
+ replacement_tx.vout[0].nValue -= int(fee * COIN) # Doubled fee
+ signed_replacement_tx = node.signrawtransactionwithkey(replacement_tx.serialize().hex(), self.privkeys)
+ replacement_tx.deserialize(BytesIO(hex_str_to_bytes(signed_replacement_tx["hex"])))
+
+ self.log.info("Test that transactions within a package cannot replace each other")
+ testres_rbf_conflicting = node.testmempoolaccept([signed_replaceable_tx["hex"], signed_replacement_tx["hex"]])
+ assert_equal(testres_rbf_conflicting, [
+ {"txid": replaceable_tx.rehash(), "wtxid": replaceable_tx.getwtxid(), "package-error": "conflict-in-package"},
+ {"txid": replacement_tx.rehash(), "wtxid": replacement_tx.getwtxid(), "package-error": "conflict-in-package"}
+ ])
+
+ self.log.info("Test that packages cannot conflict with mempool transactions, even if a valid BIP125 RBF")
+ node.sendrawtransaction(signed_replaceable_tx["hex"])
+ testres_rbf_single = node.testmempoolaccept([signed_replacement_tx["hex"]])
+ # This transaction is a valid BIP125 replace-by-fee
+ assert testres_rbf_single[0]["allowed"]
+ testres_rbf_package = self.independent_txns_testres_blank + [{
+ "txid": replacement_tx.rehash(), "wtxid": replacement_tx.getwtxid(), "allowed": False, "reject-reason": "txn-mempool-conflict"
+ }]
+ self.assert_testres_equal(self.independent_txns_hex + [signed_replacement_tx["hex"]], testres_rbf_package)
+
+if __name__ == "__main__":
+ RPCPackagesTest().main()
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index 86c7b3fbcc..53ddf24e47 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -15,6 +15,8 @@ Test the following RPCs:
from collections import OrderedDict
from decimal import Decimal
from io import BytesIO
+
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import CTransaction, ToHex
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -66,7 +68,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.log.info('prepare some coins for multiple *rawtransaction commands')
self.nodes[2].generate(1)
self.sync_all()
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
self.sync_all()
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5)
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0)
diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py
index 60b4d1c744..16b0019866 100755
--- a/test/functional/rpc_signrawtransaction.py
+++ b/test/functional/rpc_signrawtransaction.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test transaction signing using the signrawtransaction* RPCs."""
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.address import check_script, script_to_p2sh, script_to_p2wsh
from test_framework.key import ECKey
from test_framework.test_framework import BitcoinTestFramework
@@ -155,7 +156,7 @@ class SignRawTransactionsTest(BitcoinTestFramework):
def test_fully_signed_tx(self):
self.log.info("Test signing a fully signed transaction does nothing")
self.nodes[0].walletpassphrase("password", 9999)
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
rawtx = self.nodes[0].createrawtransaction([], [{self.nodes[0].getnewaddress(): 10}])
fundedtx = self.nodes[0].fundrawtransaction(rawtx)
signedtx = self.nodes[0].signrawtransactionwithwallet(fundedtx["hex"])
@@ -174,7 +175,7 @@ class SignRawTransactionsTest(BitcoinTestFramework):
embedded_pubkey = eckey.get_pubkey().get_bytes().hex()
p2sh_p2wsh_address = self.nodes[1].createmultisig(1, [embedded_pubkey], "p2sh-segwit")
# send transaction to P2SH-P2WSH 1-of-1 multisig address
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
self.nodes[0].sendtoaddress(p2sh_p2wsh_address["address"], 49.999)
self.nodes[0].generate(1)
self.sync_all()
diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py
index 528da0cbfc..bf96b6353c 100755
--- a/test/functional/rpc_txoutproof.py
+++ b/test/functional/rpc_txoutproof.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test gettxoutproof and verifytxoutproof RPCs."""
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import CMerkleBlock, FromHex, ToHex
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
@@ -23,7 +24,7 @@ class MerkleBlockTest(BitcoinTestFramework):
miniwallet = MiniWallet(self.nodes[0])
# Add enough mature utxos to the wallet, so that all txs spend confirmed coins
miniwallet.generate(5)
- self.nodes[0].generate(100)
+ self.nodes[0].generate(COINBASE_MATURITY)
self.sync_all()
chain_height = self.nodes[1].getblockcount()
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index d08e025178..f35ea6c122 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -52,6 +52,9 @@ MAX_BLOCK_SIGOPS_WEIGHT = MAX_BLOCK_SIGOPS * WITNESS_SCALE_FACTOR
# Genesis block time (regtest)
TIME_GENESIS_BLOCK = 1296688602
+# Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
+COINBASE_MATURITY = 100
+
# From BIP141
WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
@@ -178,6 +181,11 @@ def create_raw_transaction(node, txid, to_address, *, amount):
signed_psbt = wrpc.walletprocesspsbt(psbt)
psbt = signed_psbt['psbt']
final_psbt = node.finalizepsbt(psbt)
+ if not final_psbt["complete"]:
+ node.log.info(f'final_psbt={final_psbt}')
+ for w in node.listwallets():
+ wrpc = node.get_wallet_rpc(w)
+ node.log.info(f'listunspent={wrpc.listunspent()}')
assert_equal(final_psbt["complete"], True)
return final_psbt['hex']
diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py
index e047e7fa14..5dc723c1d5 100644
--- a/test/functional/test_framework/netutil.py
+++ b/test/functional/test_framework/netutil.py
@@ -151,7 +151,7 @@ def test_ipv6_local():
have_ipv6 = True
try:
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
- s.connect(('::1', 0))
+ s.connect(('::1', 1))
except socket.error:
have_ipv6 = False
return have_ipv6
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index c17c16f797..ba52abc7dd 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -400,14 +400,14 @@ class TestNode():
self._raise_assertion_error('Expected messages "{}" does not partially match log:\n\n{}\n\n'.format(str(expected_msgs), print_log))
@contextlib.contextmanager
- def profile_with_perf(self, profile_name):
+ def profile_with_perf(self, profile_name: str):
"""
Context manager that allows easy profiling of node activity using `perf`.
See `test/functional/README.md` for details on perf usage.
Args:
- profile_name (str): This string will be appended to the
+ profile_name: This string will be appended to the
profile data filename generated by perf.
"""
subp = self._start_perf(profile_name)
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 55166ba0ad..462019566c 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -20,6 +20,7 @@ import unittest
from . import coverage
from .authproxy import AuthServiceProxy, JSONRPCException
from io import BytesIO
+from typing import Callable, Optional
logger = logging.getLogger("TestFramework.utils")
@@ -80,7 +81,7 @@ def assert_raises_message(exc, message, fun, *args, **kwds):
raise AssertionError("No exception raised")
-def assert_raises_process_error(returncode, output, fun, *args, **kwds):
+def assert_raises_process_error(returncode: int, output: str, fun: Callable, *args, **kwds):
"""Execute a process and asserts the process return code and output.
Calls function `fun` with arguments `args` and `kwds`. Catches a CalledProcessError
@@ -88,9 +89,9 @@ def assert_raises_process_error(returncode, output, fun, *args, **kwds):
no CalledProcessError was raised or if the return code and output are not as expected.
Args:
- returncode (int): the process return code.
- output (string): [a substring of] the process output.
- fun (function): the function to call. This should execute a process.
+ returncode: the process return code.
+ output: [a substring of] the process output.
+ fun: the function to call. This should execute a process.
args*: positional arguments for the function.
kwds**: named arguments for the function.
"""
@@ -105,7 +106,7 @@ def assert_raises_process_error(returncode, output, fun, *args, **kwds):
raise AssertionError("No exception raised")
-def assert_raises_rpc_error(code, message, fun, *args, **kwds):
+def assert_raises_rpc_error(code: Optional[int], message: Optional[str], fun: Callable, *args, **kwds):
"""Run an RPC and verify that a specific JSONRPC exception code and message is raised.
Calls function `fun` with arguments `args` and `kwds`. Catches a JSONRPCException
@@ -113,11 +114,11 @@ def assert_raises_rpc_error(code, message, fun, *args, **kwds):
no JSONRPCException was raised or if the error code/message are not as expected.
Args:
- code (int), optional: the error code returned by the RPC call (defined
- in src/rpc/protocol.h). Set to None if checking the error code is not required.
- message (string), optional: [a substring of] the error string returned by the
- RPC call. Set to None if checking the error string is not required.
- fun (function): the function to call. This should be the name of an RPC.
+ code: the error code returned by the RPC call (defined in src/rpc/protocol.h).
+ Set to None if checking the error code is not required.
+ message: [a substring of] the error string returned by the RPC call.
+ Set to None if checking the error string is not required.
+ fun: the function to call. This should be the name of an RPC.
args*: positional arguments for the function.
kwds**: named arguments for the function.
"""
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 05bda5d899..0962a5cb54 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -6,6 +6,7 @@
from decimal import Decimal
from enum import Enum
+from typing import Optional
from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE
from test_framework.key import ECKey
from test_framework.messages import (
@@ -105,12 +106,12 @@ class MiniWallet:
def get_address(self):
return self._address
- def get_utxo(self, *, txid='', mark_as_spent=True):
+ def get_utxo(self, *, txid: Optional[str]='', mark_as_spent=True):
"""
Returns a utxo and marks it as spent (pops it from the internal list)
Args:
- txid (string), optional: get the first utxo we find from a specific transaction
+ txid: get the first utxo we find from a specific transaction
Note: Can be used to get the change output immediately after a send_self_transfer
"""
@@ -123,13 +124,13 @@ class MiniWallet:
else:
return self._utxos[index]
- def send_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None):
+ def send_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, locktime=0):
"""Create and send a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed."""
tx = self.create_self_transfer(fee_rate=fee_rate, from_node=from_node, utxo_to_spend=utxo_to_spend)
self.sendrawtransaction(from_node=from_node, tx_hex=tx['hex'])
return tx
- def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, mempool_valid=True):
+ def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, mempool_valid=True, locktime=0):
"""Create and return a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed."""
self._utxos = sorted(self._utxos, key=lambda k: k['value'])
utxo_to_spend = utxo_to_spend or self._utxos.pop() # Pick the largest utxo (if none provided) and hope it covers the fee
@@ -141,6 +142,7 @@ class MiniWallet:
tx = CTransaction()
tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']))]
tx.vout = [CTxOut(int(send_value * COIN), self._scriptPubKey)]
+ tx.nLockTime = locktime
if not self._address:
# raw script
if self._priv_key is not None:
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 00527e78f1..c9a8cc5611 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -211,6 +211,7 @@ BASE_SCRIPTS = [
'mempool_package_onemore.py',
'rpc_createmultisig.py --legacy-wallet',
'rpc_createmultisig.py --descriptors',
+ 'rpc_packages.py',
'feature_versionbits_warning.py',
'rpc_preciousblock.py',
'wallet_importprunedfunds.py --legacy-wallet',
@@ -260,6 +261,7 @@ BASE_SCRIPTS = [
'wallet_send.py --legacy-wallet',
'wallet_send.py --descriptors',
'wallet_create_tx.py --descriptors',
+ 'wallet_taproot.py',
'p2p_fingerprint.py',
'feature_uacomment.py',
'wallet_coinbase_category.py --legacy-wallet',
@@ -282,6 +284,7 @@ BASE_SCRIPTS = [
'feature_logging.py',
'feature_anchors.py',
'feature_coinstatsindex.py',
+ 'wallet_orphanedreward.py',
'p2p_node_network_limited.py',
'p2p_permissions.py',
'feature_blocksdir.py',
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index 2e0edcfa38..d24cc802a4 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -12,6 +12,7 @@
"""
from decimal import Decimal
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -28,7 +29,7 @@ class AbandonConflictTest(BitcoinTestFramework):
self.skip_if_no_wallet()
def run_test(self):
- self.nodes[1].generate(100)
+ self.nodes[1].generate(COINBASE_MATURITY)
self.sync_blocks()
balance = self.nodes[0].getbalance()
txA = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index b3bee1876d..6d93cf412f 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -53,6 +53,7 @@ Test that the nodes generate the correct change address type:
from decimal import Decimal
import itertools
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.descriptors import (
descsum_create,
@@ -220,7 +221,7 @@ class AddressTypeTest(BitcoinTestFramework):
def run_test(self):
# Mine 101 blocks on node5 to bring nodes out of IBD and make sure that
# no coinbases are maturing for the nodes-under-test during the test
- self.nodes[5].generate(101)
+ self.nodes[5].generate(COINBASE_MATURITY + 1)
self.sync_blocks()
uncompressed_1 = "0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee"
@@ -258,7 +259,7 @@ class AddressTypeTest(BitcoinTestFramework):
self.log.info("Sending from node {} ({}) with{} multisig using {}".format(from_node, self.extra_args[from_node], "" if multisig else "out", "default" if address_type is None else address_type))
old_balances = self.get_balances()
self.log.debug("Old balances are {}".format(old_balances))
- to_send = (old_balances[from_node] / 101).quantize(Decimal("0.00000001"))
+ to_send = (old_balances[from_node] / (COINBASE_MATURITY + 1)).quantize(Decimal("0.00000001"))
sends = {}
addresses = {}
diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py
index f34c1345e0..05a0ef0ea1 100755
--- a/test/functional/wallet_backup.py
+++ b/test/functional/wallet_backup.py
@@ -35,6 +35,7 @@ import os
from random import randint
import shutil
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -123,7 +124,7 @@ class WalletBackupTest(BitcoinTestFramework):
self.sync_blocks()
self.nodes[2].generate(1)
self.sync_blocks()
- self.nodes[3].generate(100)
+ self.nodes[3].generate(COINBASE_MATURITY)
self.sync_blocks()
assert_equal(self.nodes[0].getbalance(), 50)
@@ -152,7 +153,7 @@ class WalletBackupTest(BitcoinTestFramework):
self.do_one_round()
# Generate 101 more blocks, so any fees paid mature
- self.nodes[3].generate(101)
+ self.nodes[3].generate(COINBASE_MATURITY + 1)
self.sync_all()
balance0 = self.nodes[0].getbalance()
diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py
index 433b40faee..204a866c55 100755
--- a/test/functional/wallet_balance.py
+++ b/test/functional/wallet_balance.py
@@ -7,6 +7,7 @@ from decimal import Decimal
import struct
from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE as ADDRESS_WATCHONLY
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -72,7 +73,7 @@ class WalletTest(BitcoinTestFramework):
self.nodes[0].generate(1)
self.sync_all()
self.nodes[1].generate(1)
- self.nodes[1].generatetoaddress(101, ADDRESS_WATCHONLY)
+ self.nodes[1].generatetoaddress(COINBASE_MATURITY + 1, ADDRESS_WATCHONLY)
self.sync_all()
if not self.options.descriptors:
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 4a1d25bbc5..a052ec7477 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -6,6 +6,7 @@
from decimal import Decimal
from itertools import product
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_array_result,
@@ -65,7 +66,7 @@ class WalletTest(BitcoinTestFramework):
assert_equal(walletinfo['balance'], 0)
self.sync_all(self.nodes[0:3])
- self.nodes[1].generate(101)
+ self.nodes[1].generate(COINBASE_MATURITY + 1)
self.sync_all(self.nodes[0:3])
assert_equal(self.nodes[0].getbalance(), 50)
@@ -158,7 +159,7 @@ class WalletTest(BitcoinTestFramework):
assert_equal(len(self.nodes[1].listlockunspent()), 0)
# Have node1 generate 100 blocks (so node0 can recover the fee)
- self.nodes[1].generate(100)
+ self.nodes[1].generate(COINBASE_MATURITY)
self.sync_all(self.nodes[0:3])
# node0 should end up with 100 btc in block rewards plus fees, but
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index ff5070c1fa..b21461ee7b 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -16,6 +16,7 @@ make assumptions about execution order.
from decimal import Decimal
import io
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.blocktools import add_witness_commitment, create_block, create_coinbase, send_to_witness
from test_framework.messages import BIP125_SEQUENCE_NUMBER, CTransaction
from test_framework.test_framework import BitcoinTestFramework
@@ -265,7 +266,7 @@ def test_small_output_with_feerate_succeeds(self, rbf_node, dest_address):
self.log.info('Testing small output with feerate bump succeeds')
# Make sure additional inputs exist
- rbf_node.generatetoaddress(101, rbf_node.getnewaddress())
+ rbf_node.generatetoaddress(COINBASE_MATURITY + 1, rbf_node.getnewaddress())
rbfid = spend_one_input(rbf_node, dest_address)
input_list = rbf_node.getrawtransaction(rbfid, 1)["vin"]
assert_equal(len(input_list), 1)
diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py
index 1e032bdd6c..c6f5d334f8 100755
--- a/test/functional/wallet_descriptor.py
+++ b/test/functional/wallet_descriptor.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test descriptor wallet function."""
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -83,7 +84,7 @@ class WalletDescriptorTest(BitcoinTestFramework):
send_wrpc = self.nodes[0].get_wallet_rpc("desc1")
# Generate some coins
- send_wrpc.generatetoaddress(101, send_wrpc.getnewaddress())
+ send_wrpc.generatetoaddress(COINBASE_MATURITY + 1, send_wrpc.getnewaddress())
# Make transactions
self.log.info("Test sending and receiving")
diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py
index 78eef4b790..b28f3ecebc 100755
--- a/test/functional/wallet_fallbackfee.py
+++ b/test/functional/wallet_fallbackfee.py
@@ -3,6 +3,8 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test wallet replace-by-fee capabilities in conjunction with the fallbackfee."""
+
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_raises_rpc_error
@@ -15,7 +17,7 @@ class WalletRBFTest(BitcoinTestFramework):
self.skip_if_no_wallet()
def run_test(self):
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
# sending a transaction without fee estimations must be possible by default on regtest
self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py
index c0b76d960f..f32acb8e15 100755
--- a/test/functional/wallet_groups.py
+++ b/test/functional/wallet_groups.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test wallet group functionality."""
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import CTransaction, FromHex, ToHex
from test_framework.util import (
@@ -31,7 +32,7 @@ class WalletGroupTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Setting up")
# Mine some coins
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
# Get some addresses from the two nodes
addr1 = [self.nodes[1].getnewaddress() for _ in range(3)]
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index 23d132df41..d41a389197 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -7,6 +7,7 @@
import os
import shutil
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -48,7 +49,7 @@ class WalletHDTest(BitcoinTestFramework):
# Derive some HD addresses and remember the last
# Also send funds to each add
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
hd_add = None
NUM_HD_ADDS = 10
for i in range(1, NUM_HD_ADDS + 1):
diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py
index 0a3dd56620..a2da16e5a3 100755
--- a/test/functional/wallet_importdescriptors.py
+++ b/test/functional/wallet_importdescriptors.py
@@ -16,6 +16,7 @@ variants.
and test the values returned."""
from test_framework.address import key_to_p2pkh
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.descriptors import descsum_create
from test_framework.util import (
@@ -73,7 +74,7 @@ class ImportDescriptorsTest(BitcoinTestFramework):
assert_equal(wpriv.getwalletinfo()['keypoolsize'], 0)
self.log.info('Mining coins')
- w0.generatetoaddress(101, w0.getnewaddress())
+ w0.generatetoaddress(COINBASE_MATURITY + 1, w0.getnewaddress())
# RPC importdescriptors -----------------------------------------------
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index 13186b9e1d..0a00c5eed9 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -15,6 +15,7 @@ variants.
- `test_address()` is called to call getaddressinfo for an address on node1
and test the values returned."""
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.script import (
CScript,
OP_NOP,
@@ -255,7 +256,7 @@ class ImportMultiTest(BitcoinTestFramework):
# P2SH address
multisig = get_multisig(self.nodes[0])
- self.nodes[1].generate(100)
+ self.nodes[1].generate(COINBASE_MATURITY)
self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)
self.nodes[1].generate(1)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
@@ -276,7 +277,7 @@ class ImportMultiTest(BitcoinTestFramework):
# P2SH + Redeem script
multisig = get_multisig(self.nodes[0])
- self.nodes[1].generate(100)
+ self.nodes[1].generate(COINBASE_MATURITY)
self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)
self.nodes[1].generate(1)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
@@ -297,7 +298,7 @@ class ImportMultiTest(BitcoinTestFramework):
# P2SH + Redeem script + Private Keys + !Watchonly
multisig = get_multisig(self.nodes[0])
- self.nodes[1].generate(100)
+ self.nodes[1].generate(COINBASE_MATURITY)
self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)
self.nodes[1].generate(1)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
@@ -323,7 +324,7 @@ class ImportMultiTest(BitcoinTestFramework):
# P2SH + Redeem script + Private Keys + Watchonly
multisig = get_multisig(self.nodes[0])
- self.nodes[1].generate(100)
+ self.nodes[1].generate(COINBASE_MATURITY)
self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)
self.nodes[1].generate(1)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py
index 7635ce2139..ded0e64b1d 100755
--- a/test/functional/wallet_importprunedfunds.py
+++ b/test/functional/wallet_importprunedfunds.py
@@ -5,6 +5,7 @@
"""Test the importprunedfunds and removeprunedfunds RPCs."""
from decimal import Decimal
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.address import key_to_p2wpkh
from test_framework.key import ECKey
from test_framework.test_framework import BitcoinTestFramework
@@ -24,7 +25,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Mining blocks...")
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
self.sync_all()
@@ -46,7 +47,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
self.sync_all()
# Node 1 sync test
- assert_equal(self.nodes[1].getblockcount(), 101)
+ assert_equal(self.nodes[1].getblockcount(), COINBASE_MATURITY + 1)
# Address Test - before import
address_info = self.nodes[1].getaddressinfo(address1)
diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py
index 5619d57947..1ecf08b9ac 100755
--- a/test/functional/wallet_keypool_topup.py
+++ b/test/functional/wallet_keypool_topup.py
@@ -13,6 +13,7 @@ Two nodes. Node1 is under test. Node0 is providing transactions and generating b
import os
import shutil
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -31,7 +32,7 @@ class KeypoolRestoreTest(BitcoinTestFramework):
def run_test(self):
wallet_path = os.path.join(self.nodes[1].datadir, self.chain, "wallets", self.default_wallet_name, self.wallet_data_filename)
wallet_backup_path = os.path.join(self.nodes[1].datadir, "wallet.bak")
- self.nodes[0].generate(101)
+ self.nodes[0].generate(COINBASE_MATURITY + 1)
self.log.info("Make backup of wallet")
self.stop_node(1)
diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py
index 551eb72720..2d792bac52 100755
--- a/test/functional/wallet_labels.py
+++ b/test/functional/wallet_labels.py
@@ -11,6 +11,7 @@ RPCs tested are:
"""
from collections import defaultdict
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
from test_framework.wallet_util import test_address
@@ -32,7 +33,7 @@ class WalletLabelsTest(BitcoinTestFramework):
# Note each time we call generate, all generated coins go into
# the same address, so we call twice to get two addresses w/50 each
node.generatetoaddress(nblocks=1, address=node.getnewaddress(label='coinbase'))
- node.generatetoaddress(nblocks=101, address=node.getnewaddress(label='coinbase'))
+ node.generatetoaddress(nblocks=COINBASE_MATURITY + 1, address=node.getnewaddress(label='coinbase'))
assert_equal(node.getbalance(), 100)
# there should be 2 address groups
@@ -104,7 +105,7 @@ class WalletLabelsTest(BitcoinTestFramework):
label.verify(node)
assert_equal(node.getreceivedbylabel(label.name), 2)
label.verify(node)
- node.generate(101)
+ node.generate(COINBASE_MATURITY + 1)
# Check that setlabel can assign a label to a new unused address.
for label in labels:
@@ -124,7 +125,7 @@ class WalletLabelsTest(BitcoinTestFramework):
label.add_address(multisig_address)
label.purpose[multisig_address] = "send"
label.verify(node)
- node.generate(101)
+ node.generate(COINBASE_MATURITY + 1)
# Check that setlabel can change the label of an address from a
# different label.
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index 448720530c..3899971bd7 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -5,6 +5,7 @@
"""Test the listsinceblock RPC."""
from test_framework.address import key_to_p2wpkh
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.key import ECKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import BIP125_SEQUENCE_NUMBER
@@ -29,7 +30,7 @@ class ListSinceBlockTest(BitcoinTestFramework):
# All nodes are in IBD from genesis, so they'll need the miner (node2) to be an outbound connection, or have
# only one connection. (See fPreferredDownload in net_processing)
self.connect_nodes(1, 2)
- self.nodes[2].generate(101)
+ self.nodes[2].generate(COINBASE_MATURITY + 1)
self.sync_all()
self.test_no_blockhash()
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index 71d1b96a95..00d2c9ffe4 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -14,6 +14,7 @@ import stat
import time
from test_framework.authproxy import JSONRPCException
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.test_node import ErrorMatch
from test_framework.util import (
@@ -229,7 +230,7 @@ class MultiWalletTest(BitcoinTestFramework):
assert_raises_rpc_error(-19, "Wallet file not specified", node.getwalletinfo)
w1, w2, w3, w4, *_ = wallets
- node.generatetoaddress(nblocks=101, address=w1.getnewaddress())
+ node.generatetoaddress(nblocks=COINBASE_MATURITY + 1, address=w1.getnewaddress())
assert_equal(w1.getbalance(), 100)
assert_equal(w2.getbalance(), 0)
assert_equal(w3.getbalance(), 0)
diff --git a/test/functional/wallet_orphanedreward.py b/test/functional/wallet_orphanedreward.py
new file mode 100755
index 0000000000..097df2cf41
--- /dev/null
+++ b/test/functional/wallet_orphanedreward.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test orphaned block rewards in the wallet."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+class OrphanedBlockRewardTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 2
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ # Generate some blocks and obtain some coins on node 0. We send
+ # some balance to node 1, which will hold it as a single coin.
+ self.nodes[0].generate(150)
+ self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 10)
+ self.nodes[0].generate(1)
+
+ # Get a block reward with node 1 and remember the block so we can orphan
+ # it later.
+ self.sync_blocks()
+ blk = self.nodes[1].generate(1)[0]
+ self.sync_blocks()
+
+ # Let the block reward mature and send coins including both
+ # the existing balance and the block reward.
+ self.nodes[0].generate(150)
+ self.sync_blocks()
+ assert_equal(self.nodes[1].getbalance(), 10 + 25)
+ txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 30)
+
+ # Orphan the block reward and make sure that the original coins
+ # from the wallet can still be spent.
+ self.nodes[0].invalidateblock(blk)
+ self.nodes[0].generate(152)
+ self.sync_blocks()
+ # Without the following abandontransaction call, the coins are
+ # not considered available yet.
+ assert_equal(self.nodes[1].getbalances()["mine"], {
+ "trusted": 0,
+ "untrusted_pending": 0,
+ "immature": 0,
+ })
+ # The following abandontransaction is necessary to make the later
+ # lines succeed, and probably should not be needed; see
+ # https://github.com/bitcoin/bitcoin/issues/14148.
+ self.nodes[1].abandontransaction(txid)
+ assert_equal(self.nodes[1].getbalances()["mine"], {
+ "trusted": 10,
+ "untrusted_pending": 0,
+ "immature": 0,
+ })
+ self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 9)
+
+if __name__ == '__main__':
+ OrphanedBlockRewardTest().main()
diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py
new file mode 100755
index 0000000000..65ca7bdef7
--- /dev/null
+++ b/test/functional/wallet_taproot.py
@@ -0,0 +1,272 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test generation and spending of P2TR addresses."""
+
+import random
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+from test_framework.descriptors import descsum_create
+from test_framework.script import (CScript, OP_CHECKSIG, taproot_construct)
+from test_framework.segwit_addr import encode_segwit_address
+
+# xprvs/xpubs, and m/* derived x-only pubkeys (created using independent implementation)
+KEYS = [
+ {
+ "xprv": "tprv8ZgxMBicQKsPeNLUGrbv3b7qhUk1LQJZAGMuk9gVuKh9sd4BWGp1eMsehUni6qGb8bjkdwBxCbgNGdh2bYGACK5C5dRTaif9KBKGVnSezxV",
+ "xpub": "tpubD6NzVbkrYhZ4XqNGAWGWSzmxGWFwVjVTjZxh2fioKbVYi7Jx8fdbprVWsdW7mHwqjchBVas8TLZG4Xwuz4RKU4iaCqiCvoSkFCzQptqk5Y1",
+ "pubs": [
+ "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18",
+ "a30253b018ea6fca966135bf7dd8026915427f24ccf10d4e03f7870f4128569b",
+ "a61e5749f2f3db9dc871d7b187e30bfd3297eea2557e9be99897ea8ff7a29a21",
+ "8110cf482f66dc37125e619d73075af932521724ffc7108309e88f361efe8c8a",
+ ]
+ },
+ {
+ "xprv": "tprv8ZgxMBicQKsPe98QUPieXy5KFPVjuZNpcC9JY7K7buJEm8nWvJogK4kTda7eLjK9U4PnMNbSjEkpjDJazeBZ4rhYNYD7N6GEdaysj1AYSb5",
+ "xpub": "tpubD6NzVbkrYhZ4XcACN3PEwNjRpR1g4tZjBVk5pdMR2B6dbd3HYhdGVZNKofAiFZd9okBserZvv58A6tBX4pE64UpXGNTSesfUW7PpW36HuKz",
+ "pubs": [
+ "f95886b02a84928c5c15bdca32784993105f73de27fa6ad8c1a60389b999267c",
+ "71522134160685eb779857033bfc84c7626f13556154653a51dd42619064e679",
+ "48957b4158b2c5c3f4c000f51fd2cf0fd5ff8868ebfb194256f5e9131fc74bd8",
+ "086dda8139b3a84944010648d2b674b70447be3ae59322c09a4907bc80be62c1",
+ ]
+ },
+ {
+ "xprv": "tprv8ZgxMBicQKsPe3ZJmcj9aJ2EPZJYYCh6Lp3v82p75wspgaXmtDZ2RBtkAtWcGnW2VQDzMHQPBkCKMoYTqh1RfJKjv4PcmWVR7KqTpjsdboN",
+ "xpub": "tpubD6NzVbkrYhZ4XWb6fGPjyhgLxapUhXszv7ehQYrQWDgDX4nYWcNcbgWcM2RhYo9s2mbZcfZJ8t5LzYcr24FK79zVybsw5Qj3Rtqug8jpJMy",
+ "pubs": [
+ "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7",
+ "8a104c54cd34acba60c97dd8f1f7abc89ba9587afd88dc928e91aca7b1c50d20",
+ "13ba6b252a4eb5ef31d39cb521724cdab19a698323f5c17093f28fb1821d052f",
+ "f6c2b4863fd5ba1ba09e3a890caed8b75ffbe013ebab31a06ab87cd6f72506af",
+ ]
+ },
+ {
+ "xprv": "tprv8ZgxMBicQKsPdKziibn63Rm6aNzp7dSjDnufZMStXr71Huz7iihCRpbZZZ6Voy5HyuHCWx6foHMipzMzUq4tZrtkZ24DJwz5EeNWdsuwX5h",
+ "xpub": "tpubD6NzVbkrYhZ4Wo2WcFSgSqRD9QWkGxddo6WSqsVBx7uQ8QEtM7WncKDRjhFEexK119NigyCsFygA4b7sAPQxqebyFGAZ9XVV1BtcgNzbCRR",
+ "pubs": [
+ "03a669ea926f381582ec4a000b9472ba8a17347f5fb159eddd4a07036a6718eb",
+ "bbf56b14b119bccafb686adec2e3d2a6b51b1626213590c3afa815d1fd36f85d",
+ "2994519e31bbc238a07d82f85c9832b831705d2ee4a2dbb477ecec8a3f570fe5",
+ "68991b5c139a4c479f8c89d6254d288c533aefc0c5b91fac6c89019c4de64988",
+ ]
+ },
+ {
+ "xprv": "tprv8ZgxMBicQKsPen4PGtDwURYnCtVMDejyE8vVwMGhQWfVqB2FBPdekhTacDW4vmsKTsgC1wsncVqXiZdX2YFGAnKoLXYf42M78fQJFzuDYFN",
+ "xpub": "tpubD6NzVbkrYhZ4YF6BAXtXsqCtmv1HNyvsoSXHDsJzpnTtffH1onTEwC5SnLzCHPKPebh2i7Gxvi9kJNADcpuSmH8oM3rCYcHVtdXHjpYoKnX",
+ "pubs": [
+ "aba457d16a8d59151c387f24d1eb887efbe24644c1ee64b261282e7baebdb247",
+ "c8558b7caf198e892032d91f1a48ee9bdc25462b83b4d0ac62bb7fb2a0df630e",
+ "8a4bcaba0e970685858d133a4d0079c8b55bbc755599e212285691eb779ce3dc",
+ "b0d68ada13e0d954b3921b88160d4453e9c151131c2b7c724e08f538a666ceb3",
+ ]
+ },
+ {
+ "xprv": "tprv8ZgxMBicQKsPd91vCgRmbzA13wyip2RimYeVEkAyZvsEN5pUSB3T43SEBxPsytkxb42d64W2EiRE9CewpJQkzR8HKHLV8Uhk4dMF5yRPaTv",
+ "xpub": "tpubD6NzVbkrYhZ4Wc3i6L6N1Pp7cyVeyMcdLrFGXGDGzCfdCa5F4Zs3EY46N72Ws8QDEUYBVwXfDfda2UKSseSdU1fsBegJBhGCZyxkf28bkQ6",
+ "pubs": [
+ "9b4d495b74887815a1ff623c055c6eac6b6b2e07d2a016d6526ebac71dd99744",
+ "8e971b781b7ce7ab742d80278f2dfe7dd330f3efd6d00047f4a2071f2e7553cb",
+ "b811d66739b9f07435ccda907ec5cd225355321c35e0a7c7791232f24cf10632",
+ "4cd27a5552c272bc80ba544e9cc6340bb906969f5e7a1510b6cef9592683fbc9",
+ ]
+ },
+ {
+ "xprv": "tprv8ZgxMBicQKsPdEhLRxxwzTv2t18j7ruoffPeqAwVA2qXJ2P66RaMZLUWQ85SjoA7xPxdSgCB9UZ72m65qbnaLPtFTfHVP3MEmkpZk1Bv8RT",
+ "xpub": "tpubD6NzVbkrYhZ4Whj8KcdYPsa9T2efHC6iExzS7gynaJdv8WdripPwjq6NaH5gQJGrLmvUwHY1smhiakUosXNDTEa6qfKUQdLKV6DJBre6XvQ",
+ "pubs": [
+ "d0c19def28bb1b39451c1a814737615983967780d223b79969ba692182c6006b",
+ "cb1d1b1dc62fec1894d4c3d9a1b6738e5ff9c273a64f74e9ab363095f45e9c47",
+ "245be588f41acfaeb9481aa132717db56ee1e23eb289729fe2b8bde8f9a00830",
+ "5bc4ad6d6187fa82728c85a073b428483295288f8aef5722e47305b5872f7169",
+ ]
+ },
+ {
+ "xprv": "tprv8ZgxMBicQKsPcxbqxzcMAwQpiCD8x6qaZEJTxdKxw4w9GuMzDACTD9yhEsHGfqQcfYX4LivosLDDngTykYEp9JnTdcqY7cHqU8PpeFFKyV3",
+ "xpub": "tpubD6NzVbkrYhZ4WRddreGwaM4wHDj57S2V8XuFF9NGMLjY7PckqZ23PebZR1wGA4w84uX2vZphdZVsnREjij1ibYjEBTaTVQCEZCLs4xUDapx",
+ "pubs": [
+ "065cc1b92bd99e5a3e626e8296a366b2d132688eb43aea19bc14fd8f43bf07fb",
+ "5b95633a7dda34578b6985e6bfd85d83ec38b7ded892a9b74a3d899c85890562",
+ "dc86d434b9a34495c8e845b969d51f80d19a8df03b400353ffe8036a0c22eb60",
+ "06c8ffde238745b29ae8a97ae533e1f3edf214bba6ec58b5e7b9451d1d61ec19",
+ ]
+ },
+ {
+ "xprv": "tprv8ZgxMBicQKsPe6zLoU8MTTXgsdJVNBErrYGpoGwHf5VGvwUzdNc7NHeCSzkJkniCxBhZWujXjmD4HZmBBrnr3URgJjM6GxRgMmEhLdqNTWG",
+ "xpub": "tpubD6NzVbkrYhZ4Xa28h7nwrsBoSepRXWRmRqsc5nyb5MHfmRjmFmRhYnG4d9dC7uxixN5AfsEv1Lz3mCAuWvERyvPgKozHUVjfo8EG6foJGy7",
+ "pubs": [
+ "d826a0a53abb6ffc60df25b9c152870578faef4b2eb5a09bdd672bbe32cdd79b",
+ "939365e0359ff6bc6f6404ee220714c5d4a0d1e36838b9e2081ede217674e2ba",
+ "4e8767edcf7d3d90258cfbbea01b784f4d2de813c4277b51279cf808bac410a2",
+ "d42a2c280940bfc6ede971ae72cde2e1df96c6da7dab06a132900c6751ade208",
+ ]
+ },
+ {
+ "xprv": "tprv8ZgxMBicQKsPeB5o5oCsN2dVxM2mtJiYERQEBRc4JNwC1DFGYaEdNkmh8jJYVPU76YhkFoRoWTdh1p3yQGykG8TfDW34dKgrgSx28gswUyL",
+ "xpub": "tpubD6NzVbkrYhZ4Xe7aySsTmSHcXNYi3duSoj11TweMiejaqhW3Ay4DZFPZJses4sfpk4b9VHRhn8v4cKTMjugMM3hqXcqSSmRdiW8QvASXjfY",
+ "pubs": [
+ "e360564b2e0e8d06681b6336a29d0750210e8f34afd9afb5e6fd5fe6dba26c81",
+ "76b4900f00a1dcce463b6d8e02b768518fce4f9ecd6679a13ad78ea1e4815ad3",
+ "5575556e263c8ed52e99ab02147cc05a738869afe0039911b5a60a780f4e43d2",
+ "593b00e2c8d4bd6dda0fd9e238888acf427bb4e128887fd5a40e0e9da78cbc01",
+ ]
+ },
+ {
+ "xprv": "tprv8ZgxMBicQKsPfEH6jHemkGDjZRnAaKFJVGH8pQU638E6SdbX9hxit1tK2sfFPfL6KS7v8FfUKxstbfEpzSymbdfBM9Y5UkrxErF9fJaKLK3",
+ "xpub": "tpubD6NzVbkrYhZ4YhJtcwKN9fsr8TJ6jeSD4Zsv6vWPTQ2VH7rHn6nK4WWBCzKK7FkdVVwm3iztCU1UmStY4hX6gRbBmp9UzK9C59dQEzeXS12",
+ "pubs": [
+ "7631cacec3343052d87ef4d0065f61dde82d7d2db0c1cc02ef61ef3c982ea763",
+ "c05e44a9e735d1b1bef62e2c0d886e6fb4923b2649b67828290f5cacc51c71b7",
+ "b33198b20701afe933226c92fd0e3d51d3f266f1113d864dbd026ae3166ef7f2",
+ "f99643ac3f4072ee4a949301e86963a9ca0ad57f2ef29f6b84fda037d7cac85b",
+ ]
+ },
+ {
+ "xprv": "tprv8ZgxMBicQKsPdNWU38dT6aGxtqJR4oYS5kPpLVBcuKiiu7gqTYqMMqhUG6DP7pPahzPQu36sWSmeLCP1C4AwqcR5FX2RyRoZfd4B8pAnSdX",
+ "xpub": "tpubD6NzVbkrYhZ4WqYFvnJ3Vyw5TrpME8jLf3zbd1DvKbX7jbwc5wewYLKLSFRzZWV6hZj7XhsXAy7fhE5jB25DiWyNM3ztXbsXHRVCrp5BiPY",
+ "pubs": [
+ "2258b1c3160be0864a541854eec9164a572f094f7562628281a8073bb89173a7",
+ "83df59d0a5c951cdd62b7ab225a62079f48d2a333a86e66c35420d101446e92e",
+ "2a654bf234d819055312f9ca03fad5836f9163b09cdd24d29678f694842b874a",
+ "aa0334ab910047387c912a21ec0dab806a47ffa38365060dbc5d47c18c6e66e7",
+ ]
+ },
+ {
+ "xprv": "tprv8mGPkMVz5mZuJDnC2NjjAv7E9Zqa5LCgX4zawbZu5nzTtLb5kGhPwycX4H1gtW1f5ZdTKTNtQJ61hk71F2TdcQ93EFDTpUcPBr98QRji615",
+ "xpub": "tpubDHxRtmYEE9FaBgoyv2QKaKmLibMWEfPb6NbNE7cCW4nripqrNfWz8UEPEPbHCrakwLvwFfsqoaf4pjX4gWStp4nECRf1QwBKPkLqnY8pHbj",
+ "pubs": [
+ "00a9da96087a72258f83b338ef7f0ea8cbbe05da5f18f091eb397d1ecbf7c3d3",
+ "b2749b74d51a78f5fe3ebb3a7c0ff266a468cade143dfa265c57e325177edf00",
+ "6b8747a6bbe4440d7386658476da51f6e49a220508a7ec77fe7bccc3e7baa916",
+ "4674bf4d9ebbe01bf0aceaca2472f63198655ecf2df810f8d69b38421972318e",
+ ]
+ }
+]
+
+CHANGE_XPRV = "tprv8ZgxMBicQKsPcyDrWwiecVnTtFmfRwbfFqEfR4ZGWvq5aTTwLBWmAm5zrbMcYtb9gQNFfhRfqhhrBG37U3nhmXxEgeEPBJGHAPrHCrAd1WX"
+CHANGE_XPUB = "tpubD6NzVbkrYhZ4WSFeQbPF1uSaTHHbbGnZq8qShabZwCdUQwihxaLMMFhs2kidGF2qrRKiQVqw8VoyuTHj1bZqmMXMeciaU1gBjWA1sim2zUB"
+
+# Point with no known discrete log.
+H_POINT = "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"
+
+
+def key(hex_key):
+ """Construct an x-only pubkey from its hex representation."""
+ return bytes.fromhex(hex_key)
+
+def pk(hex_key):
+ """Construct a script expression for taproot_construct for pk(hex_key)."""
+ return (None, CScript([bytes.fromhex(hex_key), OP_CHECKSIG]))
+
+def compute_taproot_address(pubkey, scripts):
+ """Compute the address for a taproot output with given inner key and scripts."""
+ tap = taproot_construct(pubkey, scripts)
+ assert tap.scriptPubKey[0] == 0x51
+ assert tap.scriptPubKey[1] == 0x20
+ return encode_segwit_address("bcrt", 1, tap.scriptPubKey[2:])
+
+class WalletTaprootTest(BitcoinTestFramework):
+ """Test generation and spending of P2TR address outputs."""
+
+ def set_test_params(self):
+ self.num_nodes = 2
+ self.setup_clean_chain = True
+ self.extra_args = [['-keypool=100'], ['-keypool=100']]
+ self.supports_cli = False
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+ self.skip_if_no_sqlite()
+
+ def setup_network(self):
+ self.setup_nodes()
+
+ def init_wallet(self, i):
+ pass
+
+ @staticmethod
+ def rand_keys(n):
+ ret = []
+ idxes = set()
+ for _ in range(n):
+ while True:
+ i = random.randrange(len(KEYS))
+ if not i in idxes:
+ break
+ idxes.add(i)
+ ret.append(KEYS[i])
+ return ret
+
+ @staticmethod
+ def make_desc(pattern, privmap, keys, pub_only = False):
+ pat = pattern.replace("$H", H_POINT)
+ for i in range(len(privmap)):
+ if privmap[i] and not pub_only:
+ pat = pat.replace("$%i" % (i + 1), keys[i]['xprv'])
+ else:
+ pat = pat.replace("$%i" % (i + 1), keys[i]['xpub'])
+ return descsum_create(pat)
+
+ @staticmethod
+ def make_addr(treefn, keys, i):
+ args = []
+ for j in range(len(keys)):
+ args.append(keys[j]['pubs'][i])
+ return compute_taproot_address(*treefn(*args))
+
+ def do_test_addr(self, comment, pattern, privmap, treefn, keys):
+ self.log.info("Testing %s address derivation" % comment)
+ desc = self.make_desc(pattern, privmap, keys, False)
+ desc_pub = self.make_desc(pattern, privmap, keys, True)
+ assert_equal(self.nodes[0].getdescriptorinfo(desc)['descriptor'], desc_pub)
+ result = self.addr_gen.importdescriptors([{"desc": desc_pub, "active": True, "timestamp": "now"}])
+ assert(result[0]['success'])
+ for i in range(4):
+ addr_g = self.addr_gen.getnewaddress(address_type='bech32')
+ if treefn is not None:
+ addr_r = self.make_addr(treefn, keys, i)
+ assert_equal(addr_g, addr_r)
+
+ def do_test(self, comment, pattern, privmap, treefn, nkeys):
+ keys = self.rand_keys(nkeys)
+ self.do_test_addr(comment, pattern, privmap, treefn, keys)
+
+ def run_test(self):
+ self.log.info("Creating wallets...")
+ self.nodes[0].createwallet(wallet_name="addr_gen", descriptors=True, disable_private_keys=True, blank=True)
+ self.addr_gen = self.nodes[0].get_wallet_rpc("addr_gen")
+
+ self.do_test(
+ "tr(XPRV)",
+ "tr($1/*)",
+ [True],
+ lambda k1: (key(k1), []),
+ 1
+ )
+ self.do_test(
+ "tr(H,XPRV)",
+ "tr($H,pk($1/*))",
+ [True],
+ lambda k1: (key(H_POINT), [pk(k1)]),
+ 1
+ )
+ self.do_test(
+ "tr(XPRV,{H,{H,XPUB}})",
+ "tr($1/*,{pk($H),{pk($H),pk($2/*)}})",
+ [True, False],
+ lambda k1, k2: (key(k1), [pk(H_POINT), [pk(H_POINT), pk(k2)]]),
+ 2
+ )
+ self.do_test(
+ "tr(XPUB,{{H,{H,XPUB}},{H,{H,{H,XPRV}}}})",
+ "tr($1/*,{{pk($H),{pk($H),pk($2/*)}},{pk($H),{pk($H),{pk($H),pk($3/*)}}}})",
+ [False, False, True],
+ lambda k1, k2, k3: (key(k1), [[pk(H_POINT), [pk(H_POINT), pk(k2)]], [pk(H_POINT), [pk(H_POINT), [pk(H_POINT), pk(k3)]]]]),
+ 3
+ )
+
+if __name__ == '__main__':
+ WalletTaprootTest().main()
diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py
index fbc0f995d2..e7dd7592b6 100755
--- a/test/functional/wallet_upgradewallet.py
+++ b/test/functional/wallet_upgradewallet.py
@@ -17,6 +17,7 @@ import struct
from io import BytesIO
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.bdb import dump_bdb_kv
from test_framework.messages import deser_compact_size, deser_string
from test_framework.test_framework import BitcoinTestFramework
@@ -118,11 +119,11 @@ class UpgradeWalletTest(BitcoinTestFramework):
assert_equal(wallet.getwalletinfo()["walletversion"], previous_version)
def run_test(self):
- self.nodes[0].generatetoaddress(101, self.nodes[0].getnewaddress())
+ self.nodes[0].generatetoaddress(COINBASE_MATURITY + 1, self.nodes[0].getnewaddress())
self.dumb_sync_blocks()
# # Sanity check the test framework:
res = self.nodes[0].getblockchaininfo()
- assert_equal(res['blocks'], 101)
+ assert_equal(res['blocks'], COINBASE_MATURITY + 1)
node_master = self.nodes[0]
v16_3_node = self.nodes[1]
v15_2_node = self.nodes[2]
@@ -130,7 +131,7 @@ class UpgradeWalletTest(BitcoinTestFramework):
# Send coins to old wallets for later conversion checks.
v16_3_wallet = v16_3_node.get_wallet_rpc('wallet.dat')
v16_3_address = v16_3_wallet.getnewaddress()
- node_master.generatetoaddress(101, v16_3_address)
+ node_master.generatetoaddress(COINBASE_MATURITY + 1, v16_3_address)
self.dumb_sync_blocks()
v16_3_balance = v16_3_wallet.getbalance()
diff --git a/test/functional/wallet_watchonly.py b/test/functional/wallet_watchonly.py
index c345c382d0..6743c4a49b 100755
--- a/test/functional/wallet_watchonly.py
+++ b/test/functional/wallet_watchonly.py
@@ -5,6 +5,7 @@
"""Test createwallet watchonly arguments.
"""
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -36,7 +37,7 @@ class CreateWalletWatchonlyTest(BitcoinTestFramework):
wo_wallet.importpubkey(pubkey=def_wallet.getaddressinfo(wo_change)['pubkey'])
# generate some btc for testing
- node.generatetoaddress(101, a1)
+ node.generatetoaddress(COINBASE_MATURITY + 1, a1)
# send 1 btc to our watch-only address
txid = def_wallet.sendtoaddress(wo_addr, 1)