aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/functional/README.md2
-rwxr-xr-xtest/functional/feature_addrman.py66
-rwxr-xr-xtest/functional/feature_asmap.py29
-rwxr-xr-xtest/functional/feature_bip68_sequence.py10
-rwxr-xr-xtest/functional/feature_block.py5
-rwxr-xr-xtest/functional/feature_cltv.py5
-rwxr-xr-xtest/functional/feature_coinstatsindex.py12
-rwxr-xr-xtest/functional/feature_csv_activation.py5
-rwxr-xr-xtest/functional/feature_dersig.py10
-rwxr-xr-xtest/functional/feature_fee_estimation.py10
-rwxr-xr-xtest/functional/feature_notifications.py10
-rwxr-xr-xtest/functional/feature_nulldummy.py2
-rwxr-xr-xtest/functional/feature_presegwit_node_upgrade.py6
-rwxr-xr-xtest/functional/feature_rbf.py84
-rwxr-xr-xtest/functional/feature_segwit.py63
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py11
-rwxr-xr-xtest/functional/mempool_packages.py20
-rwxr-xr-xtest/functional/mempool_persist.py62
-rwxr-xr-xtest/functional/mempool_reorg.py2
-rwxr-xr-xtest/functional/mempool_spend_coinbase.py8
-rwxr-xr-xtest/functional/p2p_addr_relay.py14
-rwxr-xr-xtest/functional/p2p_addrfetch.py13
-rwxr-xr-xtest/functional/p2p_addrv2_relay.py9
-rwxr-xr-xtest/functional/p2p_compactblocks_blocksonly.py130
-rwxr-xr-xtest/functional/p2p_filter.py34
-rwxr-xr-xtest/functional/p2p_segwit.py43
-rwxr-xr-xtest/functional/rpc_addresses_deprecation.py56
-rwxr-xr-xtest/functional/rpc_blockchain.py36
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py132
-rwxr-xr-xtest/functional/rpc_net.py47
-rwxr-xr-xtest/functional/rpc_psbt.py50
-rwxr-xr-xtest/functional/rpc_signrawtransaction.py3
-rw-r--r--test/functional/test_framework/authproxy.py4
-rw-r--r--test/functional/test_framework/blocktools.py5
-rwxr-xr-xtest/functional/test_framework/p2p.py4
-rwxr-xr-xtest/functional/test_framework/script_util.py57
-rwxr-xr-xtest/functional/test_framework/test_framework.py25
-rw-r--r--test/functional/test_framework/util.py22
-rw-r--r--test/functional/test_framework/wallet.py46
-rwxr-xr-xtest/functional/test_runner.py8
-rwxr-xr-xtest/functional/wallet_basic.py66
-rwxr-xr-xtest/functional/wallet_hd.py2
-rwxr-xr-xtest/functional/wallet_send.py46
-rwxr-xr-xtest/functional/wallet_transactiontime_rescan.py161
-rwxr-xr-xtest/functional/wallet_txn_clone.py13
-rwxr-xr-xtest/functional/wallet_txn_doublespend.py13
-rwxr-xr-xtest/get_previous_releases.py1
-rw-r--r--test/lint/README.md6
-rwxr-xr-xtest/lint/lint-locale-dependence.sh13
-rwxr-xr-xtest/lint/lint-logs.sh2
-rw-r--r--test/sanitizer_suppressions/ubsan2
51 files changed, 1081 insertions, 404 deletions
diff --git a/test/functional/README.md b/test/functional/README.md
index d830ba0334..926810cf03 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -188,5 +188,5 @@ perf report -i /path/to/datadir/send-big-msgs.perf.data.xxxx --stdio | c++filt |
#### See also:
- [Installing perf](https://askubuntu.com/q/50145)
-- [Perf examples](http://www.brendangregg.com/perf.html)
+- [Perf examples](https://www.brendangregg.com/perf.html)
- [Hotspot](https://github.com/KDAB/hotspot): a GUI for perf output analysis
diff --git a/test/functional/feature_addrman.py b/test/functional/feature_addrman.py
index ee421c89b5..5a8394db2e 100755
--- a/test/functional/feature_addrman.py
+++ b/test/functional/feature_addrman.py
@@ -5,6 +5,7 @@
"""Test addrman functionality"""
import os
+import re
import struct
from test_framework.messages import ser_uint256, hash256
@@ -14,22 +15,31 @@ from test_framework.test_node import ErrorMatch
from test_framework.util import assert_equal
-def serialize_addrman(*, format=1, lowest_compatible=3):
+def serialize_addrman(
+ *,
+ format=1,
+ lowest_compatible=3,
+ net_magic="regtest",
+ bucket_key=1,
+ len_new=None,
+ len_tried=None,
+ mock_checksum=None,
+):
new = []
tried = []
INCOMPATIBILITY_BASE = 32
- r = MAGIC_BYTES["regtest"]
+ r = MAGIC_BYTES[net_magic]
r += struct.pack("B", format)
r += struct.pack("B", INCOMPATIBILITY_BASE + lowest_compatible)
- r += ser_uint256(1)
- r += struct.pack("i", len(new))
- r += struct.pack("i", len(tried))
+ r += ser_uint256(bucket_key)
+ r += struct.pack("i", len_new or len(new))
+ r += struct.pack("i", len_tried or len(tried))
ADDRMAN_NEW_BUCKET_COUNT = 1 << 10
r += struct.pack("i", ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30))
for _ in range(ADDRMAN_NEW_BUCKET_COUNT):
r += struct.pack("i", 0)
checksum = hash256(r)
- r += checksum
+ r += mock_checksum or checksum
return r
@@ -47,7 +57,7 @@ class AddrmanTest(BitcoinTestFramework):
init_error = lambda reason: (
f"Error: Invalid or corrupt peers.dat \\({reason}\\). If you believe this "
f"is a bug, please report it to {self.config['environment']['PACKAGE_BUGREPORT']}. "
- f'As a workaround, you can move the file \\("{peers_dat}"\\) out of the way \\(rename, '
+ f'As a workaround, you can move the file \\("{re.escape(peers_dat)}"\\) out of the way \\(rename, '
"move, or delete\\) to have a new one created on the next start."
)
@@ -70,7 +80,7 @@ class AddrmanTest(BitcoinTestFramework):
match=ErrorMatch.FULL_REGEX,
)
- self.log.info("Check that corrupt addrman cannot be read")
+ self.log.info("Check that corrupt addrman cannot be read (EOF)")
self.stop_node(0)
with open(peers_dat, "wb") as f:
f.write(serialize_addrman()[:-1])
@@ -79,6 +89,46 @@ class AddrmanTest(BitcoinTestFramework):
match=ErrorMatch.FULL_REGEX,
)
+ self.log.info("Check that corrupt addrman cannot be read (magic)")
+ self.stop_node(0)
+ write_addrman(peers_dat, net_magic="signet")
+ self.nodes[0].assert_start_raises_init_error(
+ expected_msg=init_error("Invalid network magic number"),
+ match=ErrorMatch.FULL_REGEX,
+ )
+
+ self.log.info("Check that corrupt addrman cannot be read (checksum)")
+ self.stop_node(0)
+ write_addrman(peers_dat, mock_checksum=b"ab" * 32)
+ self.nodes[0].assert_start_raises_init_error(
+ expected_msg=init_error("Checksum mismatch, data corrupted"),
+ match=ErrorMatch.FULL_REGEX,
+ )
+
+ self.log.info("Check that corrupt addrman cannot be read (len_tried)")
+ self.stop_node(0)
+ write_addrman(peers_dat, len_tried=-1)
+ self.nodes[0].assert_start_raises_init_error(
+ expected_msg=init_error("Corrupt CAddrMan serialization: nTried=-1, should be in \\[0, 16384\\]:.*"),
+ match=ErrorMatch.FULL_REGEX,
+ )
+
+ self.log.info("Check that corrupt addrman cannot be read (len_new)")
+ self.stop_node(0)
+ write_addrman(peers_dat, len_new=-1)
+ self.nodes[0].assert_start_raises_init_error(
+ expected_msg=init_error("Corrupt CAddrMan serialization: nNew=-1, should be in \\[0, 65536\\]:.*"),
+ match=ErrorMatch.FULL_REGEX,
+ )
+
+ self.log.info("Check that corrupt addrman cannot be read (failed check)")
+ self.stop_node(0)
+ write_addrman(peers_dat, bucket_key=0)
+ self.nodes[0].assert_start_raises_init_error(
+ expected_msg=init_error("Corrupt data. Consistency check failed with code -16: .*"),
+ match=ErrorMatch.FULL_REGEX,
+ )
+
self.log.info("Check that missing addrman is recreated")
self.stop_node(0)
os.remove(peers_dat)
diff --git a/test/functional/feature_asmap.py b/test/functional/feature_asmap.py
index 704dd6126b..debd87962f 100755
--- a/test/functional/feature_asmap.py
+++ b/test/functional/feature_asmap.py
@@ -14,9 +14,11 @@ Verify node behaviour and debug log when launching bitcoind in these cases:
4. `bitcoind -asmap/-asmap=` with no file specified, using the default asmap
-5. `bitcoind -asmap` with no file specified and a missing default asmap file
+5. `bitcoind -asmap` restart with an addrman containing new and tried entries
-6. `bitcoind -asmap` with an empty (unparsable) default asmap file
+6. `bitcoind -asmap` with no file specified and a missing default asmap file
+
+7. `bitcoind -asmap` with an empty (unparsable) default asmap file
The tests are order-independent.
@@ -37,6 +39,12 @@ def expected_messages(filename):
class AsmapTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
+ self.extra_args = [["-checkaddrman=1"]] # Do addrman checks on all operations.
+
+ def fill_addrman(self, node_id):
+ """Add 1 tried address to the addrman, followed by 1 new address."""
+ for addr, tried in [[0, True], [1, False]]:
+ self.nodes[node_id].addpeeraddress(address=f"101.{addr}.0.0", tried=tried, port=8333)
def test_without_asmap_arg(self):
self.log.info('Test bitcoind with no -asmap arg passed')
@@ -72,6 +80,22 @@ class AsmapTest(BitcoinTestFramework):
self.start_node(0, [arg])
os.remove(self.default_asmap)
+ def test_asmap_interaction_with_addrman_containing_entries(self):
+ self.log.info("Test bitcoind -asmap restart with addrman containing new and tried entries")
+ self.stop_node(0)
+ shutil.copyfile(self.asmap_raw, self.default_asmap)
+ self.start_node(0, ["-asmap", "-checkaddrman=1"])
+ self.fill_addrman(node_id=0)
+ self.restart_node(0, ["-asmap", "-checkaddrman=1"])
+ with self.node.assert_debug_log(
+ expected_msgs=[
+ "Addrman checks started: new 1, tried 1, total 2",
+ "Addrman checks completed successfully",
+ ]
+ ):
+ self.node.getnodeaddresses() # getnodeaddresses re-runs the addrman checks
+ os.remove(self.default_asmap)
+
def test_default_asmap_with_missing_file(self):
self.log.info('Test bitcoind -asmap with missing default map file')
self.stop_node(0)
@@ -97,6 +121,7 @@ class AsmapTest(BitcoinTestFramework):
self.test_asmap_with_absolute_path()
self.test_asmap_with_relative_path()
self.test_default_asmap()
+ self.test_asmap_interaction_with_addrman_containing_entries()
self.test_default_asmap_with_missing_file()
self.test_empty_asmap()
diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py
index 09cda8444a..ee2c71cd42 100755
--- a/test/functional/feature_bip68_sequence.py
+++ b/test/functional/feature_bip68_sequence.py
@@ -41,8 +41,14 @@ class BIP68Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [
- ["-acceptnonstdtxn=1"],
- ["-acceptnonstdtxn=0"],
+ [
+ '-testactivationheight=csv@432',
+ "-acceptnonstdtxn=1",
+ ],
+ [
+ '-testactivationheight=csv@432',
+ "-acceptnonstdtxn=0",
+ ],
]
def skip_test_if_missing_module(self):
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index 777787ed32..b06ea8542b 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -82,7 +82,10 @@ class FullBlockTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
- self.extra_args = [['-acceptnonstdtxn=1']] # This is a consensus block test, we don't care about tx policy
+ self.extra_args = [[
+ '-acceptnonstdtxn=1', # This is a consensus block test, we don't care about tx policy
+ '-testactivationheight=bip34@2',
+ ]]
def run_test(self):
node = self.nodes[0] # convenience reference to the node
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index 2c3ef9b88b..3dc858f5d2 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -8,7 +8,6 @@ Test that the CHECKLOCKTIMEVERIFY soft-fork activates.
"""
from test_framework.blocktools import (
- CLTV_HEIGHT,
create_block,
create_coinbase,
)
@@ -76,10 +75,14 @@ def cltv_validate(tx, height):
cltv_modify_tx(tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
+CLTV_HEIGHT = 111
+
+
class BIP65Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [[
+ f'-testactivationheight=cltv@{CLTV_HEIGHT}',
'-whitelist=noban@127.0.0.1',
'-par=1', # Use only one script thread to get the exact reject reason for testing
'-acceptnonstdtxn=1', # cltv_invalidate is nonstandard
diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py
index 146e776b07..c592d7bd69 100755
--- a/test/functional/feature_coinstatsindex.py
+++ b/test/functional/feature_coinstatsindex.py
@@ -164,7 +164,7 @@ class CoinStatsIndexTest(BitcoinTestFramework):
# Generate and send another tx with an OP_RETURN output (which is unspendable)
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(int(tx1_txid, 16), n), b''))
- tx2.vout.append(CTxOut(int(20.99 * COIN), CScript([OP_RETURN] + [OP_FALSE]*30)))
+ tx2.vout.append(CTxOut(int(Decimal('20.99') * COIN), CScript([OP_RETURN] + [OP_FALSE]*30)))
tx2_hex = self.nodes[0].signrawtransactionwithwallet(tx2.serialize().hex())['hex']
self.nodes[0].sendrawtransaction(tx2_hex)
@@ -175,16 +175,16 @@ class CoinStatsIndexTest(BitcoinTestFramework):
for hash_option in index_hash_options:
# Check all amounts were registered correctly
res6 = index_node.gettxoutsetinfo(hash_option, 108)
- assert_equal(res6['total_unspendable_amount'], Decimal('70.98999999'))
+ assert_equal(res6['total_unspendable_amount'], Decimal('70.99000000'))
assert_equal(res6['block_info'], {
- 'unspendable': Decimal('20.98999999'),
+ 'unspendable': Decimal('20.99000000'),
'prevout_spent': 111,
'new_outputs_ex_coinbase': Decimal('89.99993620'),
- 'coinbase': Decimal('50.01006381'),
+ 'coinbase': Decimal('50.01006380'),
'unspendables': {
'genesis_block': 0,
'bip30': 0,
- 'scripts': Decimal('20.98999999'),
+ 'scripts': Decimal('20.99000000'),
'unclaimed_rewards': 0
}
})
@@ -206,7 +206,7 @@ class CoinStatsIndexTest(BitcoinTestFramework):
for hash_option in index_hash_options:
res7 = index_node.gettxoutsetinfo(hash_option, 109)
- assert_equal(res7['total_unspendable_amount'], Decimal('80.98999999'))
+ assert_equal(res7['total_unspendable_amount'], Decimal('80.99000000'))
assert_equal(res7['block_info'], {
'unspendable': 10,
'prevout_spent': 0,
diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py
index d2b3fe45d1..5255b13bd1 100755
--- a/test/functional/feature_csv_activation.py
+++ b/test/functional/feature_csv_activation.py
@@ -41,7 +41,6 @@ from itertools import product
import time
from test_framework.blocktools import (
- CSV_ACTIVATION_HEIGHT,
create_block,
create_coinbase,
)
@@ -89,12 +88,16 @@ def all_rlt_txs(txs):
return [tx['tx'] for tx in txs]
+CSV_ACTIVATION_HEIGHT = 432
+
+
class BIP68_112_113Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
self.extra_args = [[
'-whitelist=noban@127.0.0.1',
+ f'-testactivationheight=csv@{CSV_ACTIVATION_HEIGHT}',
'-par=1', # Use only one script thread to get the exact reject reason for testing
]]
self.supports_cli = False
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index 595d26611a..28aff1f2f9 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -8,7 +8,6 @@ Test the DERSIG soft-fork activation on regtest.
"""
from test_framework.blocktools import (
- DERSIG_HEIGHT,
create_block,
create_coinbase,
)
@@ -42,10 +41,14 @@ def unDERify(tx):
tx.vin[0].scriptSig = CScript(newscript)
+DERSIG_HEIGHT = 102
+
+
class BIP66Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [[
+ f'-testactivationheight=dersig@{DERSIG_HEIGHT}',
'-whitelist=noban@127.0.0.1',
'-par=1', # Use only one script thread to get the exact log msg for testing
]]
@@ -83,7 +86,6 @@ class BIP66Test(BitcoinTestFramework):
tip = self.nodes[0].getbestblockhash()
block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
block = create_block(int(tip, 16), create_coinbase(DERSIG_HEIGHT - 1), block_time)
- block.nVersion = 2
block.vtx.append(spendtx)
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
@@ -110,7 +112,7 @@ class BIP66Test(BitcoinTestFramework):
peer.sync_with_ping()
self.log.info("Test that transactions with non-DER signatures cannot appear in a block")
- block.nVersion = 3
+ block.nVersion = 4
spendtx = self.create_tx(self.coinbase_txids[1])
unDERify(spendtx)
@@ -139,7 +141,7 @@ class BIP66Test(BitcoinTestFramework):
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
peer.sync_with_ping()
- self.log.info("Test that a version 3 block with a DERSIG-compliant transaction is accepted")
+ self.log.info("Test that a block with a DERSIG-compliant transaction is accepted")
block.vtx[1] = self.create_tx(self.coinbase_txids[1])
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py
index c4610f98bd..9c225dc687 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -132,9 +132,13 @@ def check_smart_estimates(node, fees_seen):
delta = 1.0e-6 # account for rounding error
last_feerate = float(max(fees_seen))
all_smart_estimates = [node.estimatesmartfee(i) for i in range(1, 26)]
+ mempoolMinFee = node.getmempoolinfo()['mempoolminfee']
+ minRelaytxFee = node.getmempoolinfo()['minrelaytxfee']
for i, e in enumerate(all_smart_estimates): # estimate is for i+1
feerate = float(e["feerate"])
assert_greater_than(feerate, 0)
+ assert_greater_than_or_equal(feerate, float(mempoolMinFee))
+ assert_greater_than_or_equal(feerate, float(minRelaytxFee))
if feerate + delta < min(fees_seen) or feerate - delta > max(fees_seen):
raise AssertionError(f"Estimated fee ({feerate}) out of range ({min(fees_seen)},{max(fees_seen)})")
@@ -275,6 +279,12 @@ class EstimateFeeTest(BitcoinTestFramework):
self.log.info("Final estimates after emptying mempools")
check_estimates(self.nodes[1], self.fees_per_kb)
+ # check that the effective feerate is greater than or equal to the mempoolminfee even for high mempoolminfee
+ self.log.info("Test fee rate estimation after restarting node with high MempoolMinFee")
+ high_val = 3*self.nodes[1].estimatesmartfee(1)['feerate']
+ self.restart_node(1, extra_args=[f'-minrelaytxfee={high_val}'])
+ check_estimates(self.nodes[1], self.fees_per_kb)
+
self.log.info("Testing that fee estimation is disabled in blocksonly.")
self.restart_node(0, ["-blocksonly"])
assert_raises_rpc_error(-32603, "Fee estimation disabled",
diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py
index 48d41432be..2a507c75c4 100755
--- a/test/functional/feature_notifications.py
+++ b/test/functional/feature_notifications.py
@@ -45,7 +45,6 @@ class NotificationsTest(BitcoinTestFramework):
f"-alertnotify=echo > {os.path.join(self.alertnotify_dir, '%s')}",
f"-blocknotify=echo > {os.path.join(self.blocknotify_dir, '%s')}",
], [
- "-rescan",
f"-walletnotify=echo %h_%b > {os.path.join(self.walletnotify_dir, notify_outputname('%w', '%s'))}",
]]
self.wallet_names = [self.default_wallet_name, self.wallet]
@@ -94,16 +93,15 @@ class NotificationsTest(BitcoinTestFramework):
# directory content should equal the generated transaction hashes
tx_details = list(map(lambda t: (t['txid'], t['blockheight'], t['blockhash']), self.nodes[1].listtransactions("*", block_count)))
- self.stop_node(1)
self.expect_wallet_notify(tx_details)
self.log.info("test -walletnotify after rescan")
- # restart node to rescan to force wallet notifications
- self.start_node(1)
- self.connect_nodes(0, 1)
-
+ # rescan to force wallet notifications
+ self.nodes[1].rescanblockchain()
self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10)
+ self.connect_nodes(0, 1)
+
# directory content should equal the generated transaction hashes
tx_details = list(map(lambda t: (t['txid'], t['blockheight'], t['blockhash']), self.nodes[1].listtransactions("*", block_count)))
self.expect_wallet_notify(tx_details)
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index 96984e1e64..217a38050d 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -52,7 +52,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
# 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}',
+ f'-testactivationheight=segwit@{COINBASE_MATURITY + 5}',
'-addresstype=legacy',
'-par=1', # Use only one script thread to get the exact reject reason for testing
]]
diff --git a/test/functional/feature_presegwit_node_upgrade.py b/test/functional/feature_presegwit_node_upgrade.py
index fd6b8620d4..aac42d4dbf 100755
--- a/test/functional/feature_presegwit_node_upgrade.py
+++ b/test/functional/feature_presegwit_node_upgrade.py
@@ -16,7 +16,7 @@ class SegwitUpgradeTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
- self.extra_args = [["-segwitheight=10"]]
+ self.extra_args = [["-testactivationheight=segwit@10"]]
def run_test(self):
"""A pre-segwit node with insufficiently validated blocks needs to redownload blocks"""
@@ -37,14 +37,14 @@ class SegwitUpgradeTest(BitcoinTestFramework):
# Restarting the node (with segwit activation height set to 5) should result in a shutdown
# because the blockchain consists of 3 insufficiently validated blocks per segwit consensus rules.
node.assert_start_raises_init_error(
- extra_args=["-segwitheight=5"],
+ extra_args=["-testactivationheight=segwit@5"],
expected_msg=": Witness data for blocks after height 5 requires "
f"validation. Please restart with -reindex..{os.linesep}"
"Please restart with -reindex or -reindex-chainstate to recover.",
)
# As directed, the user restarts the node with -reindex
- self.start_node(0, extra_args=["-reindex", "-segwitheight=5"])
+ self.start_node(0, extra_args=["-reindex", "-testactivationheight=segwit@5"])
# With the segwit consensus rules, the node is able to validate only up to block 4
assert_equal(node.getblockcount(), 4)
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index cb7556feb4..4eaaf46454 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -7,7 +7,6 @@
from copy import deepcopy
from decimal import Decimal
-from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import (
BIP125_SEQUENCE_NUMBER,
COIN,
@@ -18,9 +17,16 @@ from test_framework.messages import (
)
from test_framework.script import CScript, OP_DROP
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error, satoshi_round
-from test_framework.script_util import DUMMY_P2WPKH_SCRIPT, DUMMY_2_P2WPKH_SCRIPT
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
+from test_framework.script_util import (
+ DUMMY_P2WPKH_SCRIPT,
+ DUMMY_2_P2WPKH_SCRIPT,
+)
from test_framework.wallet import MiniWallet
+from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
MAX_REPLACEMENT_LIMIT = 100
class ReplaceByFeeTest(BitcoinTestFramework):
@@ -38,15 +44,12 @@ class ReplaceByFeeTest(BitcoinTestFramework):
]
self.supports_cli = False
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
# the pre-mined test framework chain contains coinbase outputs to the
# MiniWallet's default address ADDRESS_BCRT1_P2WSH_OP_TRUE in blocks
# 76-100 (see method BitcoinTestFramework._initialize_chain())
- self.wallet.scan_blocks(start=76, num=2)
+ self.wallet.rescan_utxos()
self.log.info("Running test simple doublespend...")
self.test_simple_doublespend()
@@ -89,29 +92,10 @@ class ReplaceByFeeTest(BitcoinTestFramework):
def make_utxo(self, node, amount, confirmed=True, scriptPubKey=DUMMY_P2WPKH_SCRIPT):
"""Create a txout with a given amount and scriptPubKey
- Mines coins as needed.
-
confirmed - txouts created will be confirmed in the blockchain;
unconfirmed otherwise.
"""
- fee = 1 * COIN
- while node.getbalance() < satoshi_round((amount + fee) / COIN):
- self.generate(node, COINBASE_MATURITY)
-
- new_addr = node.getnewaddress()
- txid = node.sendtoaddress(new_addr, satoshi_round((amount + fee) / COIN))
- tx1 = node.getrawtransaction(txid, 1)
- txid = int(txid, 16)
- i, _ = next(filter(lambda vout: new_addr == vout[1]['scriptPubKey']['address'], enumerate(tx1['vout'])))
-
- tx2 = CTransaction()
- tx2.vin = [CTxIn(COutPoint(txid, i))]
- tx2.vout = [CTxOut(amount, scriptPubKey)]
- tx2.rehash()
-
- signed_tx = node.signrawtransactionwithwallet(tx2.serialize().hex())
-
- txid = node.sendrawtransaction(signed_tx['hex'], 0)
+ txid, n = self.wallet.send_to(from_node=node, scriptPubKey=scriptPubKey, amount=amount)
# If requested, ensure txouts are confirmed.
if confirmed:
@@ -124,7 +108,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert new_size < mempool_size
mempool_size = new_size
- return COutPoint(int(txid, 16), 0)
+ return COutPoint(int(txid, 16), n)
def test_simple_doublespend(self):
"""Simple doublespend"""
@@ -161,14 +145,14 @@ class ReplaceByFeeTest(BitcoinTestFramework):
def test_doublespend_chain(self):
"""Doublespend of a long chain"""
- initial_nValue = 50 * COIN
+ initial_nValue = 5 * COIN
tx0_outpoint = self.make_utxo(self.nodes[0], initial_nValue)
prevout = tx0_outpoint
remaining_value = initial_nValue
chain_txids = []
- while remaining_value > 10 * COIN:
- remaining_value -= 1 * COIN
+ while remaining_value > 1 * COIN:
+ remaining_value -= int(0.1 * COIN)
tx = CTransaction()
tx.vin = [CTxIn(prevout, nSequence=0)]
tx.vout = [CTxOut(remaining_value, CScript([1, OP_DROP] * 15 + [1]))]
@@ -178,10 +162,10 @@ class ReplaceByFeeTest(BitcoinTestFramework):
prevout = COutPoint(int(txid, 16), 0)
# Whether the double-spend is allowed is evaluated by including all
- # child fees - 40 BTC - so this attempt is rejected.
+ # child fees - 4 BTC - so this attempt is rejected.
dbl_tx = CTransaction()
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
- dbl_tx.vout = [CTxOut(initial_nValue - 30 * COIN, DUMMY_P2WPKH_SCRIPT)]
+ dbl_tx.vout = [CTxOut(initial_nValue - 3 * COIN, DUMMY_P2WPKH_SCRIPT)]
dbl_tx_hex = dbl_tx.serialize().hex()
# This will raise an exception due to insufficient fee
@@ -190,7 +174,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
# Accepted with sufficient fee
dbl_tx = CTransaction()
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
- dbl_tx.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
+ dbl_tx.vout = [CTxOut(int(0.1 * COIN), DUMMY_P2WPKH_SCRIPT)]
dbl_tx_hex = dbl_tx.serialize().hex()
self.nodes[0].sendrawtransaction(dbl_tx_hex, 0)
@@ -201,10 +185,10 @@ class ReplaceByFeeTest(BitcoinTestFramework):
def test_doublespend_tree(self):
"""Doublespend of a big tree of transactions"""
- initial_nValue = 50 * COIN
+ initial_nValue = 5 * COIN
tx0_outpoint = self.make_utxo(self.nodes[0], initial_nValue)
- def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001 * COIN, _total_txs=None):
+ def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.00001 * COIN, _total_txs=None):
if _total_txs is None:
_total_txs = [0]
if _total_txs[0] >= max_txs:
@@ -235,7 +219,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
_total_txs=_total_txs):
yield x
- fee = int(0.0001 * COIN)
+ fee = int(0.00001 * COIN)
n = MAX_REPLACEMENT_LIMIT
tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
assert_equal(len(tree_txs), n)
@@ -248,10 +232,10 @@ class ReplaceByFeeTest(BitcoinTestFramework):
# This will raise an exception due to insufficient fee
assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)
- # 1 BTC fee is enough
+ # 0.1 BTC fee is enough
dbl_tx = CTransaction()
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
- dbl_tx.vout = [CTxOut(initial_nValue - fee * n - 1 * COIN, DUMMY_P2WPKH_SCRIPT)]
+ dbl_tx.vout = [CTxOut(initial_nValue - fee * n - int(0.1 * COIN), DUMMY_P2WPKH_SCRIPT)]
dbl_tx_hex = dbl_tx.serialize().hex()
self.nodes[0].sendrawtransaction(dbl_tx_hex, 0)
@@ -264,7 +248,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
# Try again, but with more total transactions than the "max txs
# double-spent at once" anti-DoS limit.
for n in (MAX_REPLACEMENT_LIMIT + 1, MAX_REPLACEMENT_LIMIT * 2):
- fee = int(0.0001 * COIN)
+ fee = int(0.00001 * COIN)
tx0_outpoint = self.make_utxo(self.nodes[0], initial_nValue)
tree_txs = list(branch(tx0_outpoint, initial_nValue, n, fee=fee))
assert_equal(len(tree_txs), n)
@@ -544,9 +528,9 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert tx2b_txid in self.nodes[0].getrawmempool()
def test_rpc(self):
- us0 = self.nodes[0].listunspent()[0]
+ us0 = self.wallet.get_utxo()
ins = [us0]
- outs = {self.nodes[0].getnewaddress(): Decimal(1.0000000)}
+ outs = {ADDRESS_BCRT1_UNSPENDABLE: Decimal(1.0000000)}
rawtx0 = self.nodes[0].createrawtransaction(ins, outs, 0, True)
rawtx1 = self.nodes[0].createrawtransaction(ins, outs, 0, False)
json0 = self.nodes[0].decoderawtransaction(rawtx0)
@@ -554,14 +538,16 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert_equal(json0["vin"][0]["sequence"], 4294967293)
assert_equal(json1["vin"][0]["sequence"], 4294967295)
- rawtx2 = self.nodes[0].createrawtransaction([], outs)
- frawtx2a = self.nodes[0].fundrawtransaction(rawtx2, {"replaceable": True})
- frawtx2b = self.nodes[0].fundrawtransaction(rawtx2, {"replaceable": False})
+ if self.is_wallet_compiled():
+ self.init_wallet(0)
+ rawtx2 = self.nodes[0].createrawtransaction([], outs)
+ frawtx2a = self.nodes[0].fundrawtransaction(rawtx2, {"replaceable": True})
+ frawtx2b = self.nodes[0].fundrawtransaction(rawtx2, {"replaceable": False})
- json0 = self.nodes[0].decoderawtransaction(frawtx2a['hex'])
- json1 = self.nodes[0].decoderawtransaction(frawtx2b['hex'])
- assert_equal(json0["vin"][0]["sequence"], 4294967293)
- assert_equal(json1["vin"][0]["sequence"], 4294967294)
+ json0 = self.nodes[0].decoderawtransaction(frawtx2a['hex'])
+ json1 = self.nodes[0].decoderawtransaction(frawtx2b['hex'])
+ assert_equal(json0["vin"][0]["sequence"], 4294967293)
+ assert_equal(json1["vin"][0]["sequence"], 4294967294)
def test_no_inherited_signaling(self):
confirmed_utxo = self.wallet.get_utxo()
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index 2b79b3284c..25d1cb2bf1 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -44,6 +44,7 @@ from test_framework.script_util import (
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
+ assert_greater_than_or_equal,
assert_is_hex_string,
assert_raises_rpc_error,
try_rpc,
@@ -54,12 +55,14 @@ NODE_2 = 2
P2WPKH = 0
P2WSH = 1
+
def getutxo(txid):
utxo = {}
utxo["vout"] = 0
utxo["txid"] = txid
return utxo
+
def find_spendable_utxo(node, min_value):
for utxo in node.listunspent(query_options={'minimumAmount': min_value}):
if utxo['spendable']:
@@ -67,7 +70,9 @@ def find_spendable_utxo(node, min_value):
raise AssertionError(f"Unspent output equal or higher than {min_value} not found")
-txs_mined = {} # txindex from txid to blockhash
+
+txs_mined = {} # txindex from txid to blockhash
+
class SegWitTest(BitcoinTestFramework):
def set_test_params(self):
@@ -78,18 +83,18 @@ class SegWitTest(BitcoinTestFramework):
[
"-acceptnonstdtxn=1",
"-rpcserialversion=0",
- "-segwitheight=432",
+ "-testactivationheight=segwit@432",
"-addresstype=legacy",
],
[
"-acceptnonstdtxn=1",
"-rpcserialversion=1",
- "-segwitheight=432",
+ "-testactivationheight=segwit@432",
"-addresstype=legacy",
],
[
"-acceptnonstdtxn=1",
- "-segwitheight=432",
+ "-testactivationheight=segwit@432",
"-addresstype=legacy",
],
]
@@ -124,18 +129,18 @@ class SegWitTest(BitcoinTestFramework):
self.log.info("Verify sigops are counted in GBT with pre-BIP141 rules before the fork")
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
- assert tmpl['sizelimit'] == 1000000
+ assert_equal(tmpl['sizelimit'], 1000000)
assert 'weightlimit' not in tmpl
- assert tmpl['sigoplimit'] == 20000
- assert tmpl['transactions'][0]['hash'] == txid
- assert tmpl['transactions'][0]['sigops'] == 2
+ assert_equal(tmpl['sigoplimit'], 20000)
+ assert_equal(tmpl['transactions'][0]['hash'], txid)
+ assert_equal(tmpl['transactions'][0]['sigops'], 2)
assert '!segwit' not in tmpl['rules']
self.generate(self.nodes[0], 1) # block 162
balance_presetup = self.nodes[0].getbalance()
self.pubkey = []
- p2sh_ids = [] # p2sh_ids[NODE][TYPE] is an array of txids that spend to P2WPKH (TYPE=0) or P2WSH (TYPE=1) scripts to an address for NODE embedded in p2sh
- wit_ids = [] # wit_ids[NODE][TYPE] is an array of txids that spend to P2WPKH (TYPE=0) or P2WSH (TYPE=1) scripts to an address for NODE via bare witness
+ p2sh_ids = [] # p2sh_ids[NODE][TYPE] is an array of txids that spend to P2WPKH (TYPE=0) or P2WSH (TYPE=1) scripts to an address for NODE embedded in p2sh
+ wit_ids = [] # wit_ids[NODE][TYPE] is an array of txids that spend to P2WPKH (TYPE=0) or P2WSH (TYPE=1) scripts to an address for NODE via bare witness
for i in range(3):
newaddress = self.nodes[i].getnewaddress()
self.pubkey.append(self.nodes[i].getaddressinfo(newaddress)["pubkey"])
@@ -215,7 +220,7 @@ class SegWitTest(BitcoinTestFramework):
witnesses = coinbase_tx["decoded"]["vin"][0]["txinwitness"]
assert_equal(len(witnesses), 1)
assert_is_hex_string(witnesses[0])
- assert_equal(witnesses[0], '00'*32)
+ assert_equal(witnesses[0], '00' * 32)
self.log.info("Verify witness txs without witness data are invalid after the fork")
self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program hash mismatch)', wit_ids[NODE_2][P2WPKH][2], sign=False)
@@ -231,12 +236,14 @@ class SegWitTest(BitcoinTestFramework):
self.log.info("Verify sigops are counted in GBT with BIP141 rules after the fork")
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+ raw_tx = self.nodes[0].getrawtransaction(txid, True)
tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
- assert tmpl['sizelimit'] >= 3999577 # actual maximum size is lower due to minimum mandatory non-witness data
- assert tmpl['weightlimit'] == 4000000
- assert tmpl['sigoplimit'] == 80000
- assert tmpl['transactions'][0]['txid'] == txid
- assert tmpl['transactions'][0]['sigops'] == 8
+ assert_greater_than_or_equal(tmpl['sizelimit'], 3999577) # actual maximum size is lower due to minimum mandatory non-witness data
+ assert_equal(tmpl['weightlimit'], 4000000)
+ assert_equal(tmpl['sigoplimit'], 80000)
+ assert_equal(tmpl['transactions'][0]['txid'], txid)
+ expected_sigops = 9 if 'txinwitness' in raw_tx["vin"][0] else 8
+ assert_equal(tmpl['transactions'][0]['sigops'], expected_sigops)
assert '!segwit' in tmpl['rules']
self.generate(self.nodes[0], 1) # Mine a block to clear the gbt cache
@@ -356,7 +363,7 @@ class SegWitTest(BitcoinTestFramework):
for i in compressed_spendable_address:
v = self.nodes[0].getaddressinfo(i)
- if (v['isscript']):
+ if v['isscript']:
[bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
# p2sh multisig with compressed keys should always be spendable
spendable_anytime.extend([p2sh])
@@ -375,7 +382,7 @@ class SegWitTest(BitcoinTestFramework):
for i in uncompressed_spendable_address:
v = self.nodes[0].getaddressinfo(i)
- if (v['isscript']):
+ if v['isscript']:
[bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
# p2sh multisig with uncompressed keys should always be spendable
spendable_anytime.extend([p2sh])
@@ -394,7 +401,7 @@ class SegWitTest(BitcoinTestFramework):
for i in compressed_solvable_address:
v = self.nodes[0].getaddressinfo(i)
- if (v['isscript']):
+ if v['isscript']:
# Multisig without private is not seen after addmultisigaddress, but seen after importaddress
[bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
solvable_after_importaddress.extend([bare, p2sh, p2wsh, p2sh_p2wsh])
@@ -407,7 +414,7 @@ class SegWitTest(BitcoinTestFramework):
for i in uncompressed_solvable_address:
v = self.nodes[0].getaddressinfo(i)
- if (v['isscript']):
+ if v['isscript']:
[bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
# Base uncompressed multisig without private is not seen after addmultisigaddress, but seen after importaddress
solvable_after_importaddress.extend([bare, p2sh])
@@ -446,7 +453,7 @@ class SegWitTest(BitcoinTestFramework):
importlist = []
for i in compressed_spendable_address + uncompressed_spendable_address + compressed_solvable_address + uncompressed_solvable_address:
v = self.nodes[0].getaddressinfo(i)
- if (v['isscript']):
+ if v['isscript']:
bare = bytes.fromhex(v['hex'])
importlist.append(bare.hex())
importlist.append(script_to_p2wsh_script(bare).hex())
@@ -509,7 +516,7 @@ class SegWitTest(BitcoinTestFramework):
for i in compressed_spendable_address:
v = self.nodes[0].getaddressinfo(i)
- if (v['isscript']):
+ if v['isscript']:
[bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
premature_witaddress.append(script_to_p2sh(p2wsh))
else:
@@ -519,7 +526,7 @@ class SegWitTest(BitcoinTestFramework):
for i in uncompressed_spendable_address + uncompressed_solvable_address:
v = self.nodes[0].getaddressinfo(i)
- if (v['isscript']):
+ if v['isscript']:
[bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
# P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
unseen_anytime.extend([p2wsh, p2sh_p2wsh])
@@ -530,7 +537,7 @@ class SegWitTest(BitcoinTestFramework):
for i in compressed_solvable_address:
v = self.nodes[0].getaddressinfo(i)
- if (v['isscript']):
+ if v['isscript']:
[bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
premature_witaddress.append(script_to_p2sh(p2wsh))
else:
@@ -597,13 +604,13 @@ class SegWitTest(BitcoinTestFramework):
watchcount = 0
spendcount = 0
for i in self.nodes[0].listunspent():
- if (i['txid'] == txid):
+ if i['txid'] == txid:
watchcount += 1
if i['spendable']:
spendcount += 1
- if (ismine == 2):
+ if ismine == 2:
assert_equal(spendcount, len(script_list))
- elif (ismine == 1):
+ elif ismine == 1:
assert_equal(watchcount, len(script_list))
assert_equal(spendcount, 0)
else:
@@ -615,7 +622,7 @@ class SegWitTest(BitcoinTestFramework):
p2sh = CScript(bytes.fromhex(v['scriptPubKey']))
p2wsh = script_to_p2wsh_script(bare)
p2sh_p2wsh = script_to_p2sh_script(p2wsh)
- return([bare, p2sh, p2wsh, p2sh_p2wsh])
+ return [bare, p2sh, p2wsh, p2sh_p2wsh]
def p2pkh_address_to_script(self, v):
pubkey = bytes.fromhex(v['pubkey'])
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index 89503adda3..c28186cde7 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -57,7 +57,7 @@ def cli_get_info_string_to_dict(cli_get_info_string):
if key == 'Wallet' and value == '""':
# Set default wallet("") to empty string
value = ''
- if key == "Proxy" and value == "N/A":
+ if key == "Proxies" and value == "n/a":
# Set N/A to empty string to represent no proxy
value = ''
cli_get_info[key.strip()] = value.strip()
@@ -127,10 +127,17 @@ class TestBitcoinCli(BitcoinTestFramework):
assert_equal(int(cli_get_info['Time offset (s)']), network_info['timeoffset'])
expected_network_info = f"in {network_info['connections_in']}, out {network_info['connections_out']}, total {network_info['connections']}"
assert_equal(cli_get_info["Network"], expected_network_info)
- assert_equal(cli_get_info['Proxy'], network_info['networks'][0]['proxy'])
+ assert_equal(cli_get_info['Proxies'], network_info['networks'][0]['proxy'])
assert_equal(Decimal(cli_get_info['Difficulty']), blockchain_info['difficulty'])
assert_equal(cli_get_info['Chain'], blockchain_info['chain'])
+ self.log.info("Test -getinfo and bitcoin-cli return all proxies")
+ self.restart_node(0, extra_args=["-proxy=127.0.0.1:9050", "-i2psam=127.0.0.1:7656"])
+ network_info = self.nodes[0].getnetworkinfo()
+ cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli()
+ cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
+ assert_equal(cli_get_info["Proxies"], "127.0.0.1:9050 (ipv4, ipv6, onion), 127.0.0.1:7656 (i2p)")
+
if self.is_wallet_compiled():
self.log.info("Test -getinfo and bitcoin-cli getwalletinfo return expected wallet info")
assert_equal(Decimal(cli_get_info['Balance']), BALANCE)
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index b9344ad6da..c042961937 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -51,12 +51,17 @@ class MempoolPackagesTest(BitcoinTestFramework):
txid = utxo[0]['txid']
vout = utxo[0]['vout']
value = utxo[0]['amount']
+ assert 'ancestorcount' not in utxo[0]
+ assert 'ancestorsize' not in utxo[0]
+ assert 'ancestorfees' not in utxo[0]
fee = Decimal("0.0001")
# MAX_ANCESTORS transactions off a confirmed tx should be fine
chain = []
witness_chain = []
- for _ in range(MAX_ANCESTORS):
+ ancestor_vsize = 0
+ ancestor_fees = Decimal(0)
+ for i in range(MAX_ANCESTORS):
(txid, sent_value) = chain_transaction(self.nodes[0], [txid], [0], value, fee, 1)
value = sent_value
chain.append(txid)
@@ -65,6 +70,15 @@ class MempoolPackagesTest(BitcoinTestFramework):
witnesstx = self.nodes[0].decoderawtransaction(fulltx, True)
witness_chain.append(witnesstx['hash'])
+ # Check that listunspent ancestor{count, size, fees} yield the correct results
+ wallet_unspent = self.nodes[0].listunspent(minconf=0)
+ this_unspent = next(utxo_info for utxo_info in wallet_unspent if utxo_info['txid'] == txid)
+ assert_equal(this_unspent['ancestorcount'], i + 1)
+ ancestor_vsize += self.nodes[0].getrawtransaction(txid=txid, verbose=True)['vsize']
+ assert_equal(this_unspent['ancestorsize'], ancestor_vsize)
+ ancestor_fees -= self.nodes[0].gettransaction(txid=txid)['fee']
+ assert_equal(this_unspent['ancestorfees'], ancestor_fees * COIN)
+
# Wait until mempool transactions have passed initial broadcast (sent inv and received getdata)
# Otherwise, getrawmempool may be inconsistent with getmempoolentry if unbroadcast changes in between
peer_inv_store.wait_for_broadcast(witness_chain)
@@ -77,9 +91,9 @@ class MempoolPackagesTest(BitcoinTestFramework):
descendant_fees = 0
descendant_vsize = 0
- ancestor_vsize = sum([mempool[tx]['vsize'] for tx in mempool])
+ assert_equal(ancestor_vsize, sum([mempool[tx]['vsize'] for tx in mempool]))
ancestor_count = MAX_ANCESTORS
- ancestor_fees = sum([mempool[tx]['fee'] for tx in mempool])
+ assert_equal(ancestor_fees, sum([mempool[tx]['fee'] for tx in mempool]))
descendants = []
ancestors = list(chain)
diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py
index 56f7cbe6a5..71a132dca3 100755
--- a/test/functional/mempool_persist.py
+++ b/test/functional/mempool_persist.py
@@ -46,6 +46,7 @@ from test_framework.util import (
assert_greater_than_or_equal,
assert_raises_rpc_error,
)
+from test_framework.wallet import MiniWallet
class MempoolPersistTest(BitcoinTestFramework):
@@ -53,15 +54,26 @@ class MempoolPersistTest(BitcoinTestFramework):
self.num_nodes = 3
self.extra_args = [[], ["-persistmempool=0"], []]
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def run_test(self):
+ self.mini_wallet = MiniWallet(self.nodes[2])
+ self.mini_wallet.rescan_utxos()
+ if self.is_sqlite_compiled():
+ self.nodes[2].createwallet(
+ wallet_name="watch",
+ descriptors=True,
+ disable_private_keys=True,
+ load_on_startup=False,
+ )
+ wallet_watch = self.nodes[2].get_wallet_rpc("watch")
+ assert_equal([{'success': True}], wallet_watch.importdescriptors([{'desc': self.mini_wallet.get_descriptor(), 'timestamp': 0}]))
+
self.log.debug("Send 5 transactions from node2 (to its own address)")
tx_creation_time_lower = int(time.time())
for _ in range(5):
- last_txid = self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(), Decimal("10"))
- node2_balance = self.nodes[2].getbalance()
+ last_txid = self.mini_wallet.send_self_transfer(from_node=self.nodes[2])["txid"]
+ if self.is_sqlite_compiled():
+ self.nodes[2].syncwithvalidationinterfacequeue() # Flush mempool to wallet
+ node2_balance = wallet_watch.getbalance()
self.sync_all()
tx_creation_time_higher = int(time.time())
@@ -82,16 +94,16 @@ class MempoolPersistTest(BitcoinTestFramework):
assert_equal(total_fee_old, self.nodes[0].getmempoolinfo()['total_fee'])
assert_equal(total_fee_old, sum(v['fees']['base'] for k, v in self.nodes[0].getrawmempool(verbose=True).items()))
- tx_creation_time = self.nodes[0].getmempoolentry(txid=last_txid)['time']
+ last_entry = self.nodes[0].getmempoolentry(txid=last_txid)
+ tx_creation_time = last_entry['time']
assert_greater_than_or_equal(tx_creation_time, tx_creation_time_lower)
assert_greater_than_or_equal(tx_creation_time_higher, tx_creation_time)
# disconnect nodes & make a txn that remains in the unbroadcast set.
self.disconnect_nodes(0, 1)
- assert(len(self.nodes[0].getpeerinfo()) == 0)
- assert(len(self.nodes[0].p2ps) == 0)
- self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), Decimal("12"))
- self.connect_nodes(0, 2)
+ assert_equal(len(self.nodes[0].getpeerinfo()), 0)
+ assert_equal(len(self.nodes[0].p2ps), 0)
+ self.mini_wallet.send_self_transfer(from_node=self.nodes[0])
self.log.debug("Stop-start the nodes. Verify that node0 has the transactions in its mempool and node1 does not. Verify that node2 calculates its balance correctly after loading wallet transactions.")
self.stop_nodes()
@@ -111,17 +123,19 @@ class MempoolPersistTest(BitcoinTestFramework):
fees = self.nodes[0].getmempoolentry(txid=last_txid)['fees']
assert_equal(fees['base'] + Decimal('0.00001000'), fees['modified'])
- self.log.debug('Verify time is loaded correctly')
- assert_equal(tx_creation_time, self.nodes[0].getmempoolentry(txid=last_txid)['time'])
+ self.log.debug('Verify all fields are loaded correctly')
+ assert_equal(last_entry, self.nodes[0].getmempoolentry(txid=last_txid))
# Verify accounting of mempool transactions after restart is correct
- self.nodes[2].syncwithvalidationinterfacequeue() # Flush mempool to wallet
- assert_equal(node2_balance, self.nodes[2].getbalance())
+ if self.is_sqlite_compiled():
+ self.nodes[2].loadwallet("watch")
+ wallet_watch = self.nodes[2].get_wallet_rpc("watch")
+ self.nodes[2].syncwithvalidationinterfacequeue() # Flush mempool to wallet
+ assert_equal(node2_balance, wallet_watch.getbalance())
- # start node0 with wallet disabled so wallet transactions don't get resubmitted
self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.")
self.stop_nodes()
- self.start_node(0, extra_args=["-persistmempool=0", "-disablewallet"])
+ self.start_node(0, extra_args=["-persistmempool=0"])
assert self.nodes[0].getmempoolinfo()["loaded"]
assert_equal(len(self.nodes[0].getrawmempool()), 0)
@@ -141,7 +155,7 @@ class MempoolPersistTest(BitcoinTestFramework):
self.log.debug("Stop nodes, make node1 use mempool.dat from node0. Verify it has 6 transactions")
os.rename(mempooldat0, mempooldat1)
self.stop_nodes()
- self.start_node(1, extra_args=[])
+ self.start_node(1, extra_args=["-persistmempool"])
assert self.nodes[1].getmempoolinfo()["loaded"]
assert_equal(len(self.nodes[1].getrawmempool()), 6)
@@ -164,18 +178,18 @@ class MempoolPersistTest(BitcoinTestFramework):
# ensure node0 doesn't have any connections
# make a transaction that will remain in the unbroadcast set
- assert(len(node0.getpeerinfo()) == 0)
- assert(len(node0.p2ps) == 0)
- node0.sendtoaddress(self.nodes[1].getnewaddress(), Decimal("12"))
+ assert_equal(len(node0.getpeerinfo()), 0)
+ assert_equal(len(node0.p2ps), 0)
+ self.mini_wallet.send_self_transfer(from_node=node0)
# shutdown, then startup with wallet disabled
- self.stop_nodes()
- self.start_node(0, extra_args=["-disablewallet"])
+ self.restart_node(0, extra_args=["-disablewallet"])
# check that txn gets broadcast due to unbroadcast logic
conn = node0.add_p2p_connection(P2PTxInvStore())
- node0.mockscheduler(16*60) # 15 min + 1 for buffer
+ node0.mockscheduler(16 * 60) # 15 min + 1 for buffer
self.wait_until(lambda: len(conn.get_invs()) == 1)
-if __name__ == '__main__':
+
+if __name__ == "__main__":
MempoolPersistTest().main()
diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py
index 0ee6af62f6..260b41ef12 100755
--- a/test/functional/mempool_reorg.py
+++ b/test/functional/mempool_reorg.py
@@ -31,7 +31,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
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)
+ wallet.rescan_utxos()
# Three scenarios for re-orging coinbase spends in the memory pool:
# 1. Direct coinbase spend : spend_1
diff --git a/test/functional/mempool_spend_coinbase.py b/test/functional/mempool_spend_coinbase.py
index e97595ed86..4e1dd80ba7 100755
--- a/test/functional/mempool_spend_coinbase.py
+++ b/test/functional/mempool_spend_coinbase.py
@@ -28,14 +28,14 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework):
chain_height = 198
self.nodes[0].invalidateblock(self.nodes[0].getblockhash(chain_height + 1))
assert_equal(chain_height, self.nodes[0].getblockcount())
+ wallet.rescan_utxos()
# Coinbase at height chain_height-100+1 ok in mempool, should
# get mined. Coinbase at height chain_height-100+2 is
# too immature to spend.
- wallet.scan_blocks(start=chain_height - 100 + 1, num=1)
- utxo_mature = wallet.get_utxo()
- wallet.scan_blocks(start=chain_height - 100 + 2, num=1)
- utxo_immature = wallet.get_utxo()
+ coinbase_txid = lambda h: self.nodes[0].getblock(self.nodes[0].getblockhash(h))['tx'][0]
+ utxo_mature = wallet.get_utxo(txid=coinbase_txid(chain_height - 100 + 1))
+ utxo_immature = wallet.get_utxo(txid=coinbase_txid(chain_height - 100 + 2))
spend_mature_id = wallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_mature)["txid"]
diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py
index e93698b08e..15b90fa61f 100755
--- a/test/functional/p2p_addr_relay.py
+++ b/test/functional/p2p_addr_relay.py
@@ -6,22 +6,22 @@
Test addr relay
"""
+import random
+import time
+
from test_framework.messages import (
CAddress,
- NODE_NETWORK,
- NODE_WITNESS,
msg_addr,
msg_getaddr,
- msg_verack
+ msg_verack,
)
from test_framework.p2p import (
P2PInterface,
p2p_lock,
+ P2P_SERVICES,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_greater_than
-import random
-import time
class AddrReceiver(P2PInterface):
@@ -96,7 +96,7 @@ class AddrTest(BitcoinTestFramework):
for i in range(num):
addr = CAddress()
addr.time = self.mocktime + i
- addr.nServices = NODE_NETWORK | NODE_WITNESS
+ addr.nServices = P2P_SERVICES
addr.ip = f"123.123.123.{self.counter % 256}"
addr.port = 8333 + i
addrs.append(addr)
@@ -111,7 +111,7 @@ class AddrTest(BitcoinTestFramework):
for i in range(num):
addr = CAddress()
addr.time = self.mocktime + i
- addr.nServices = NODE_NETWORK | NODE_WITNESS
+ addr.nServices = P2P_SERVICES
addr.ip = f"{random.randrange(128,169)}.{random.randrange(1,255)}.{random.randrange(1,255)}.{random.randrange(1,255)}"
addr.port = 8333
addrs.append(addr)
diff --git a/test/functional/p2p_addrfetch.py b/test/functional/p2p_addrfetch.py
index 2a0f6432a9..25efd50040 100755
--- a/test/functional/p2p_addrfetch.py
+++ b/test/functional/p2p_addrfetch.py
@@ -8,14 +8,21 @@ Test p2p addr-fetch connections
import time
-from test_framework.messages import msg_addr, CAddress, NODE_NETWORK, NODE_WITNESS
-from test_framework.p2p import P2PInterface, p2p_lock
+from test_framework.messages import (
+ CAddress,
+ msg_addr,
+)
+from test_framework.p2p import (
+ P2PInterface,
+ p2p_lock,
+ P2P_SERVICES,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
ADDR = CAddress()
ADDR.time = int(time.time())
-ADDR.nServices = NODE_NETWORK | NODE_WITNESS
+ADDR.nServices = P2P_SERVICES
ADDR.ip = "192.0.0.8"
ADDR.port = 18444
diff --git a/test/functional/p2p_addrv2_relay.py b/test/functional/p2p_addrv2_relay.py
index 32c1d42b1c..3833c58680 100755
--- a/test/functional/p2p_addrv2_relay.py
+++ b/test/functional/p2p_addrv2_relay.py
@@ -11,10 +11,11 @@ import time
from test_framework.messages import (
CAddress,
msg_addrv2,
- NODE_NETWORK,
- NODE_WITNESS,
)
-from test_framework.p2p import P2PInterface
+from test_framework.p2p import (
+ P2PInterface,
+ P2P_SERVICES,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
@@ -24,7 +25,7 @@ ADDRS = []
for i in range(10):
addr = CAddress()
addr.time = int(time.time()) + i
- addr.nServices = NODE_NETWORK | NODE_WITNESS
+ addr.nServices = P2P_SERVICES
# Add one I2P address at an arbitrary position.
if i == 5:
addr.net = addr.NET_I2P
diff --git a/test/functional/p2p_compactblocks_blocksonly.py b/test/functional/p2p_compactblocks_blocksonly.py
new file mode 100755
index 0000000000..4073ec03a6
--- /dev/null
+++ b/test/functional/p2p_compactblocks_blocksonly.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021-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 that a node in blocksonly mode does not request compact blocks."""
+
+from test_framework.messages import (
+ MSG_BLOCK,
+ MSG_CMPCT_BLOCK,
+ MSG_WITNESS_FLAG,
+ CBlock,
+ CBlockHeader,
+ CInv,
+ from_hex,
+ msg_block,
+ msg_getdata,
+ msg_headers,
+ msg_sendcmpct,
+)
+from test_framework.p2p import P2PInterface
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+
+class P2PCompactBlocksBlocksOnly(BitcoinTestFramework):
+ def set_test_params(self):
+ self.extra_args = [["-blocksonly"], [], [], []]
+ self.num_nodes = 4
+
+ def setup_network(self):
+ self.setup_nodes()
+ # Start network with everyone disconnected
+ self.sync_all()
+
+ def build_block_on_tip(self):
+ blockhash = self.nodes[2].generate(1)[0]
+ block_hex = self.nodes[2].getblock(blockhash=blockhash, verbosity=0)
+ block = from_hex(CBlock(), block_hex)
+ block.rehash()
+ return block
+
+ def run_test(self):
+ # Nodes will only request hb compact blocks mode when they're out of IBD
+ for node in self.nodes:
+ assert not node.getblockchaininfo()['initialblockdownload']
+
+ p2p_conn_blocksonly = self.nodes[0].add_p2p_connection(P2PInterface())
+ p2p_conn_high_bw = self.nodes[1].add_p2p_connection(P2PInterface())
+ p2p_conn_low_bw = self.nodes[3].add_p2p_connection(P2PInterface())
+ for conn in [p2p_conn_blocksonly, p2p_conn_high_bw, p2p_conn_low_bw]:
+ assert_equal(conn.message_count['sendcmpct'], 2)
+ conn.send_and_ping(msg_sendcmpct(announce=False, version=2))
+
+ # Nodes:
+ # 0 -> blocksonly
+ # 1 -> high bandwidth
+ # 2 -> miner
+ # 3 -> low bandwidth
+ #
+ # Topology:
+ # p2p_conn_blocksonly ---> node0
+ # p2p_conn_high_bw ---> node1
+ # p2p_conn_low_bw ---> node3
+ # node2 (no connections)
+ #
+ # node2 produces blocks that are passed to the rest of the nodes
+ # through the respective p2p connections.
+
+ self.log.info("Test that -blocksonly nodes do not select peers for BIP152 high bandwidth mode")
+
+ block0 = self.build_block_on_tip()
+
+ # A -blocksonly node should not request BIP152 high bandwidth mode upon
+ # receiving a new valid block at the tip.
+ p2p_conn_blocksonly.send_and_ping(msg_block(block0))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), block0.sha256)
+ assert_equal(p2p_conn_blocksonly.message_count['sendcmpct'], 2)
+ assert_equal(p2p_conn_blocksonly.last_message['sendcmpct'].announce, False)
+
+ # A normal node participating in transaction relay should request BIP152
+ # high bandwidth mode upon receiving a new valid block at the tip.
+ p2p_conn_high_bw.send_and_ping(msg_block(block0))
+ assert_equal(int(self.nodes[1].getbestblockhash(), 16), block0.sha256)
+ p2p_conn_high_bw.wait_until(lambda: p2p_conn_high_bw.message_count['sendcmpct'] == 3)
+ assert_equal(p2p_conn_high_bw.last_message['sendcmpct'].announce, True)
+
+ # Don't send a block from the p2p_conn_low_bw so the low bandwidth node
+ # doesn't select it for BIP152 high bandwidth relay.
+ self.nodes[3].submitblock(block0.serialize().hex())
+
+ self.log.info("Test that -blocksonly nodes send getdata(BLOCK) instead"
+ " of getdata(CMPCT) in BIP152 low bandwidth mode")
+
+ block1 = self.build_block_on_tip()
+
+ p2p_conn_blocksonly.send_message(msg_headers(headers=[CBlockHeader(block1)]))
+ p2p_conn_blocksonly.sync_send_with_ping()
+ assert_equal(p2p_conn_blocksonly.last_message['getdata'].inv, [CInv(MSG_BLOCK | MSG_WITNESS_FLAG, block1.sha256)])
+
+ p2p_conn_high_bw.send_message(msg_headers(headers=[CBlockHeader(block1)]))
+ p2p_conn_high_bw.sync_send_with_ping()
+ assert_equal(p2p_conn_high_bw.last_message['getdata'].inv, [CInv(MSG_CMPCT_BLOCK, block1.sha256)])
+
+ self.log.info("Test that getdata(CMPCT) is still sent on BIP152 low bandwidth connections"
+ " when no -blocksonly nodes are involved")
+
+ p2p_conn_low_bw.send_and_ping(msg_headers(headers=[CBlockHeader(block1)]))
+ p2p_conn_low_bw.sync_with_ping()
+ assert_equal(p2p_conn_low_bw.last_message['getdata'].inv, [CInv(MSG_CMPCT_BLOCK, block1.sha256)])
+
+ self.log.info("Test that -blocksonly nodes still serve compact blocks")
+
+ def test_for_cmpctblock(block):
+ if 'cmpctblock' not in p2p_conn_blocksonly.last_message:
+ return False
+ return p2p_conn_blocksonly.last_message['cmpctblock'].header_and_shortids.header.rehash() == block.sha256
+
+ p2p_conn_blocksonly.send_message(msg_getdata([CInv(MSG_CMPCT_BLOCK, block0.sha256)]))
+ p2p_conn_blocksonly.wait_until(lambda: test_for_cmpctblock(block0))
+
+ # Request BIP152 high bandwidth mode from the -blocksonly node.
+ p2p_conn_blocksonly.send_and_ping(msg_sendcmpct(announce=True, version=2))
+
+ block2 = self.build_block_on_tip()
+ self.nodes[0].submitblock(block1.serialize().hex())
+ self.nodes[0].submitblock(block2.serialize().hex())
+ p2p_conn_blocksonly.wait_until(lambda: test_for_cmpctblock(block2))
+
+if __name__ == '__main__':
+ P2PCompactBlocksBlocksOnly().main()
diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py
index a040665fba..0d8c298bea 100755
--- a/test/functional/p2p_filter.py
+++ b/test/functional/p2p_filter.py
@@ -8,6 +8,7 @@ Test BIP 37
from test_framework.messages import (
CInv,
+ COIN,
MAX_BLOOM_FILTER_SIZE,
MAX_BLOOM_HASH_FUNCS,
MSG_BLOCK,
@@ -28,11 +29,15 @@ from test_framework.p2p import (
)
from test_framework.script import MAX_SCRIPT_ELEMENT_SIZE
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.wallet import (
+ MiniWallet,
+ random_p2wpkh,
+)
class P2PBloomFilter(P2PInterface):
# This is a P2SH watch-only wallet
- watch_script_pubkey = 'a914ffffffffffffffffffffffffffffffffffffffff87'
+ watch_script_pubkey = bytes.fromhex('a914ffffffffffffffffffffffffffffffffffffffff87')
# The initial filter (n=10, fp=0.000001) with just the above scriptPubKey added
watch_filter_init = msg_filterload(
data=
@@ -93,8 +98,9 @@ class FilterTest(BitcoinTestFramework):
'-whitelist=noban@127.0.0.1', # immediate tx relay
]]
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
+ def generatetoscriptpubkey(self, scriptpubkey):
+ """Helper to generate a single block to the given scriptPubKey."""
+ return self.generatetodescriptor(self.nodes[0], 1, f'raw({scriptpubkey.hex()})')[0]
def test_size_limits(self, filter_peer):
self.log.info('Check that too large filter is rejected')
@@ -130,8 +136,7 @@ class FilterTest(BitcoinTestFramework):
filter_peer = P2PBloomFilter()
self.log.debug("Create a tx relevant to the peer before connecting")
- filter_address = self.nodes[0].decodescript(filter_peer.watch_script_pubkey)['address']
- txid = self.nodes[0].sendtoaddress(filter_address, 90)
+ txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=filter_peer.watch_script_pubkey, amount=9 * COIN)
self.log.debug("Send a mempool msg after connecting and check that the tx is received")
self.nodes[0].add_p2p_connection(filter_peer)
@@ -142,8 +147,7 @@ class FilterTest(BitcoinTestFramework):
def test_frelay_false(self, filter_peer):
self.log.info("Check that a node with fRelay set to false does not receive invs until the filter is set")
filter_peer.tx_received = False
- filter_address = self.nodes[0].decodescript(filter_peer.watch_script_pubkey)['address']
- self.nodes[0].sendtoaddress(filter_address, 90)
+ self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=filter_peer.watch_script_pubkey, amount=9 * COIN)
# Sync to make sure the reason filter_peer doesn't receive the tx is not p2p delays
filter_peer.sync_with_ping()
assert not filter_peer.tx_received
@@ -156,45 +160,44 @@ class FilterTest(BitcoinTestFramework):
filter_peer.send_and_ping(filter_peer.watch_filter_init)
# If fRelay is not already True, sending filterload sets it to True
assert self.nodes[0].getpeerinfo()[0]['relaytxes']
- filter_address = self.nodes[0].decodescript(filter_peer.watch_script_pubkey)['address']
self.log.info('Check that we receive merkleblock and tx if the filter matches a tx in a block')
- block_hash = self.generatetoaddress(self.nodes[0], 1, filter_address)[0]
+ block_hash = self.generatetoscriptpubkey(filter_peer.watch_script_pubkey)
txid = self.nodes[0].getblock(block_hash)['tx'][0]
filter_peer.wait_for_merkleblock(block_hash)
filter_peer.wait_for_tx(txid)
self.log.info('Check that we only receive a merkleblock if the filter does not match a tx in a block')
filter_peer.tx_received = False
- block_hash = self.generatetoaddress(self.nodes[0], 1, self.nodes[0].getnewaddress())[0]
+ block_hash = self.generatetoscriptpubkey(random_p2wpkh())
filter_peer.wait_for_merkleblock(block_hash)
assert not filter_peer.tx_received
self.log.info('Check that we not receive a tx if the filter does not match a mempool tx')
filter_peer.merkleblock_received = False
filter_peer.tx_received = False
- self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 90)
+ self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=random_p2wpkh(), amount=7 * COIN)
filter_peer.sync_send_with_ping()
assert not filter_peer.merkleblock_received
assert not filter_peer.tx_received
self.log.info('Check that we receive a tx if the filter matches a mempool tx')
filter_peer.merkleblock_received = False
- txid = self.nodes[0].sendtoaddress(filter_address, 90)
+ txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=filter_peer.watch_script_pubkey, amount=9 * COIN)
filter_peer.wait_for_tx(txid)
assert not filter_peer.merkleblock_received
self.log.info('Check that after deleting filter all txs get relayed again')
filter_peer.send_and_ping(msg_filterclear())
for _ in range(5):
- txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 7)
+ txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=random_p2wpkh(), amount=7 * COIN)
filter_peer.wait_for_tx(txid)
self.log.info('Check that request for filtered blocks is ignored if no filter is set')
filter_peer.merkleblock_received = False
filter_peer.tx_received = False
with self.nodes[0].assert_debug_log(expected_msgs=['received getdata']):
- block_hash = self.generatetoaddress(self.nodes[0], 1, self.nodes[0].getnewaddress())[0]
+ block_hash = self.generatetoscriptpubkey(random_p2wpkh())
filter_peer.wait_for_inv([CInv(MSG_BLOCK, int(block_hash, 16))])
filter_peer.sync_with_ping()
assert not filter_peer.merkleblock_received
@@ -210,6 +213,9 @@ class FilterTest(BitcoinTestFramework):
self.nodes[0].disconnect_p2ps()
def run_test(self):
+ self.wallet = MiniWallet(self.nodes[0])
+ self.wallet.rescan_utxos()
+
filter_peer = self.nodes[0].add_p2p_connection(P2PBloomFilter())
self.log.info('Test filter size limits')
self.test_size_limits(filter_peer)
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index a71f736bd6..aa3b95fc4f 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -43,6 +43,7 @@ from test_framework.messages import (
from test_framework.p2p import (
P2PInterface,
p2p_lock,
+ P2P_SERVICES,
)
from test_framework.script import (
CScript,
@@ -83,10 +84,6 @@ from test_framework.util import (
assert_raises_rpc_error,
)
-# The versionbit bit used to signal activation of SegWit
-VB_WITNESS_BIT = 1
-VB_TOP_BITS = 0x20000000
-
MAX_SIGOP_COST = 80000
SEGWIT_HEIGHT = 120
@@ -196,8 +193,8 @@ class SegWitTest(BitcoinTestFramework):
self.num_nodes = 2
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
self.extra_args = [
- ["-acceptnonstdtxn=1", "-segwitheight={}".format(SEGWIT_HEIGHT), "-whitelist=noban@127.0.0.1"],
- ["-acceptnonstdtxn=0", "-segwitheight={}".format(SEGWIT_HEIGHT)],
+ ["-acceptnonstdtxn=1", f"-testactivationheight=segwit@{SEGWIT_HEIGHT}", "-whitelist=noban@127.0.0.1"],
+ ["-acceptnonstdtxn=0", f"-testactivationheight=segwit@{SEGWIT_HEIGHT}"],
]
self.supports_cli = False
@@ -206,13 +203,13 @@ class SegWitTest(BitcoinTestFramework):
# Helper functions
- def build_next_block(self, version=4):
+ def build_next_block(self):
"""Build a block on top of node0's tip."""
tip = self.nodes[0].getbestblockhash()
height = self.nodes[0].getblockcount() + 1
block_time = self.nodes[0].getblockheader(tip)["mediantime"] + 1
block = create_block(int(tip, 16), create_coinbase(height), block_time)
- block.nVersion = version
+ block.nVersion = 4
block.rehash()
return block
@@ -224,14 +221,14 @@ class SegWitTest(BitcoinTestFramework):
def run_test(self):
# Setup the p2p connections
- # self.test_node sets NODE_WITNESS|NODE_NETWORK
- self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK | NODE_WITNESS)
+ # self.test_node sets P2P_SERVICES, i.e. NODE_WITNESS | NODE_NETWORK
+ self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=P2P_SERVICES)
# self.old_node sets only NODE_NETWORK
self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)
# self.std_node is for testing node1 (fRequireStandard=true)
- self.std_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK | NODE_WITNESS)
+ self.std_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=P2P_SERVICES)
# self.std_wtx_node is for testing node1 with wtxid relay
- self.std_wtx_node = self.nodes[1].add_p2p_connection(TestP2PConn(wtxidrelay=True), services=NODE_NETWORK | NODE_WITNESS)
+ self.std_wtx_node = self.nodes[1].add_p2p_connection(TestP2PConn(wtxidrelay=True), services=P2P_SERVICES)
assert self.test_node.nServices & NODE_WITNESS != 0
@@ -298,7 +295,7 @@ class SegWitTest(BitcoinTestFramework):
# Mine a block with an anyone-can-spend coinbase,
# let it mature, then try to spend it.
- block = self.build_next_block(version=1)
+ block = self.build_next_block()
block.solve()
self.test_node.send_and_ping(msg_no_witness_block(block)) # make sure the block was processed
txid = block.vtx[0].sha256
@@ -336,8 +333,8 @@ class SegWitTest(BitcoinTestFramework):
tx.rehash()
assert tx.sha256 != tx.calc_sha256(with_witness=True)
- # Construct a segwit-signaling block that includes the transaction.
- block = self.build_next_block(version=(VB_TOP_BITS | (1 << VB_WITNESS_BIT)))
+ # Construct a block that includes the transaction.
+ block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
# Sending witness data before activation is not allowed (anti-spam
# rule).
@@ -364,7 +361,7 @@ class SegWitTest(BitcoinTestFramework):
# test_node has set NODE_WITNESS, so all getdata requests should be for
# witness blocks.
# Test announcing a block via inv results in a getdata, and that
- # announcing a version 4 or random VB block with a header results in a getdata
+ # announcing a block with a header results in a getdata
block1 = self.build_next_block()
block1.solve()
@@ -372,19 +369,13 @@ class SegWitTest(BitcoinTestFramework):
assert self.test_node.last_message["getdata"].inv[0].type == blocktype
test_witness_block(self.nodes[0], self.test_node, block1, True)
- block2 = self.build_next_block(version=4)
+ block2 = self.build_next_block()
block2.solve()
self.test_node.announce_block_and_wait_for_getdata(block2, use_header=True)
assert self.test_node.last_message["getdata"].inv[0].type == blocktype
test_witness_block(self.nodes[0], self.test_node, block2, True)
- block3 = self.build_next_block(version=(VB_TOP_BITS | (1 << 15)))
- block3.solve()
- self.test_node.announce_block_and_wait_for_getdata(block3, use_header=True)
- assert self.test_node.last_message["getdata"].inv[0].type == blocktype
- test_witness_block(self.nodes[0], self.test_node, block3, True)
-
# Check that we can getdata for witness blocks or regular blocks,
# and the right thing happens.
if not self.segwit_active:
@@ -429,7 +420,7 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(rpc_details["weight"], block.get_weight())
# Upgraded node should not ask for blocks from unupgraded
- block4 = self.build_next_block(version=4)
+ block4 = self.build_next_block()
block4.solve()
self.old_node.getdataset = set()
@@ -2017,8 +2008,8 @@ class SegWitTest(BitcoinTestFramework):
@subtest # type: ignore
def test_wtxid_relay(self):
# Use brand new nodes to avoid contamination from earlier tests
- self.wtx_node = self.nodes[0].add_p2p_connection(TestP2PConn(wtxidrelay=True), services=NODE_NETWORK | NODE_WITNESS)
- self.tx_node = self.nodes[0].add_p2p_connection(TestP2PConn(wtxidrelay=False), services=NODE_NETWORK | NODE_WITNESS)
+ self.wtx_node = self.nodes[0].add_p2p_connection(TestP2PConn(wtxidrelay=True), services=P2P_SERVICES)
+ self.tx_node = self.nodes[0].add_p2p_connection(TestP2PConn(wtxidrelay=False), services=P2P_SERVICES)
# Check wtxidrelay feature negotiation message through connecting a new peer
def received_wtxidrelay():
diff --git a/test/functional/rpc_addresses_deprecation.py b/test/functional/rpc_addresses_deprecation.py
deleted file mode 100755
index e566fb0aa7..0000000000
--- a/test/functional/rpc_addresses_deprecation.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2020 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 deprecation of reqSigs and addresses RPC fields."""
-
-from test_framework.messages import (
- tx_from_hex,
-)
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import (
- assert_equal,
-)
-
-
-class AddressesDeprecationTest(BitcoinTestFramework):
- def set_test_params(self):
- self.num_nodes = 2
- self.extra_args = [[], ["-deprecatedrpc=addresses"]]
-
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
- def run_test(self):
- self.test_addresses_deprecation()
-
- def test_addresses_deprecation(self):
- node = self.nodes[0]
- coin = node.listunspent().pop()
-
- inputs = [{'txid': coin['txid'], 'vout': coin['vout']}]
- outputs = {node.getnewaddress(): 0.99}
- raw = node.createrawtransaction(inputs, outputs)
- signed = node.signrawtransactionwithwallet(raw)['hex']
-
- # This transaction is derived from test/util/data/txcreatemultisig1.json
- tx = tx_from_hex(signed)
- tx.vout[0].scriptPubKey = bytes.fromhex("522102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff39721021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d2102df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb48553ae")
- tx_signed = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
- txid = node.sendrawtransaction(hexstring=tx_signed, maxfeerate=0)
-
- self.log.info("Test RPCResult scriptPubKey no longer returns the fields addresses or reqSigs by default")
- hash = self.generateblock(node, output=node.getnewaddress(), transactions=[txid])['hash']
- # Ensure both nodes have the newly generated block on disk.
- self.sync_blocks()
- script_pub_key = node.getblock(blockhash=hash, verbose=2)['tx'][-1]['vout'][0]['scriptPubKey']
- assert 'addresses' not in script_pub_key and 'reqSigs' not in script_pub_key
-
- self.log.info("Test RPCResult scriptPubKey returns the addresses field with -deprecatedrpc=addresses")
- script_pub_key = self.nodes[1].getblock(blockhash=hash, verbose=2)['tx'][-1]['vout'][0]['scriptPubKey']
- assert_equal(script_pub_key['addresses'], ['mvKDK6D54HU8wQumJBLHY95eq5iHFqXSBz', 'mv3rHCQSwKp2BLSuMHD8uCS32LW5xiNAA5', 'mirrsyhAQYzo5CwVhcaYJKwUJu1WJRCRJe'])
- assert_equal(script_pub_key['reqSigs'], 2)
-
-
-if __name__ == "__main__":
- AddressesDeprecationTest().main()
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index e13de4395b..c3c6ade684 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -27,8 +27,6 @@ import subprocess
from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE
from test_framework.blocktools import (
- CLTV_HEIGHT,
- DERSIG_HEIGHT,
create_block,
create_coinbase,
TIME_GENESIS_BLOCK,
@@ -129,7 +127,29 @@ class BlockchainTest(BitcoinTestFramework):
# should have exact keys
assert_equal(sorted(res.keys()), keys)
- self.restart_node(0, ['-stopatheight=207', '-prune=550'])
+ self.stop_node(0)
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=['-testactivationheight=name@2'],
+ expected_msg='Error: Invalid name (name@2) for -testactivationheight=name@height.',
+ )
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=['-testactivationheight=bip34@-2'],
+ expected_msg='Error: Invalid height value (bip34@-2) for -testactivationheight=name@height.',
+ )
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=['-testactivationheight='],
+ expected_msg='Error: Invalid format () for -testactivationheight=name@height.',
+ )
+ self.start_node(0, extra_args=[
+ '-stopatheight=207',
+ '-prune=550',
+ '-testactivationheight=bip34@2',
+ '-testactivationheight=dersig@3',
+ '-testactivationheight=cltv@4',
+ '-testactivationheight=csv@5',
+ '-testactivationheight=segwit@6',
+ ])
+
res = self.nodes[0].getblockchaininfo()
# result should have these additional pruning keys if prune=550
assert_equal(sorted(res.keys()), sorted(['pruneheight', 'automatic_pruning', 'prune_target_size'] + keys))
@@ -143,10 +163,10 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(res['softforks'], {
'bip34': {'type': 'buried', 'active': True, 'height': 2},
- 'bip66': {'type': 'buried', 'active': True, 'height': DERSIG_HEIGHT},
- 'bip65': {'type': 'buried', 'active': True, 'height': CLTV_HEIGHT},
- 'csv': {'type': 'buried', 'active': False, 'height': 432},
- 'segwit': {'type': 'buried', 'active': True, 'height': 0},
+ 'bip66': {'type': 'buried', 'active': True, 'height': 3},
+ 'bip65': {'type': 'buried', 'active': True, 'height': 4},
+ 'csv': {'type': 'buried', 'active': True, 'height': 5},
+ 'segwit': {'type': 'buried', 'active': True, 'height': 6},
'testdummy': {
'type': 'bip9',
'bip9': {
@@ -406,7 +426,7 @@ class BlockchainTest(BitcoinTestFramework):
node = self.nodes[0]
miniwallet = MiniWallet(node)
- miniwallet.scan_blocks(num=5)
+ miniwallet.rescan_utxos()
fee_per_byte = Decimal('0.00000010')
fee_per_kb = 1000 * fee_per_byte
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 56312dc6e5..3b01506986 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -8,6 +8,7 @@ from decimal import Decimal
from itertools import product
from test_framework.descriptors import descsum_create
+from test_framework.key import ECKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_approx,
@@ -19,6 +20,7 @@ from test_framework.util import (
count_bytes,
find_vout_for_address,
)
+from test_framework.wallet_util import bytes_to_wif
def get_unspent(listunspent, amount):
@@ -47,7 +49,40 @@ class RawTransactionsTest(BitcoinTestFramework):
self.connect_nodes(0, 2)
self.connect_nodes(0, 3)
+ def lock_outputs_type(self, wallet, outputtype):
+ """
+ Only allow UTXOs of the given type
+ """
+ if outputtype in ["legacy", "p2pkh", "pkh"]:
+ prefixes = ["pkh(", "sh(multi("]
+ elif outputtype in ["p2sh-segwit", "sh_wpkh"]:
+ prefixes = ["sh(wpkh(", "sh(wsh("]
+ elif outputtype in ["bech32", "wpkh"]:
+ prefixes = ["wpkh(", "wsh("]
+ else:
+ assert False, f"Unknown output type {outputtype}"
+
+ to_lock = []
+ for utxo in wallet.listunspent():
+ if "desc" in utxo:
+ for prefix in prefixes:
+ if utxo["desc"].startswith(prefix):
+ to_lock.append({"txid": utxo["txid"], "vout": utxo["vout"]})
+ wallet.lockunspent(False, to_lock)
+
+ def unlock_utxos(self, wallet):
+ """
+ Unlock all UTXOs except the watchonly one
+ """
+ to_keep = []
+ if self.watchonly_txid is not None and self.watchonly_vout is not None:
+ to_keep.append({"txid": self.watchonly_txid, "vout": self.watchonly_vout})
+ wallet.lockunspent(True)
+ wallet.lockunspent(False, to_keep)
+
def run_test(self):
+ self.watchonly_txid = None
+ self.watchonly_vout = None
self.log.info("Connect nodes, set fees, generate blocks, and sync")
self.min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']
# This test is not meant to test fee estimation and we'd like
@@ -99,6 +134,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.test_subtract_fee_with_presets()
self.test_transaction_too_large()
self.test_include_unsafe()
+ self.test_external_inputs()
self.test_22670()
def test_change_position(self):
@@ -373,6 +409,7 @@ class RawTransactionsTest(BitcoinTestFramework):
def test_fee_p2pkh(self):
"""Compare fee of a standard pubkeyhash transaction."""
self.log.info("Test fundrawtxn p2pkh fee")
+ self.lock_outputs_type(self.nodes[0], "p2pkh")
inputs = []
outputs = {self.nodes[1].getnewaddress():1.1}
rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
@@ -386,9 +423,12 @@ class RawTransactionsTest(BitcoinTestFramework):
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
assert feeDelta >= 0 and feeDelta <= self.fee_tolerance
+ self.unlock_utxos(self.nodes[0])
+
def test_fee_p2pkh_multi_out(self):
"""Compare fee of a standard pubkeyhash transaction with multiple outputs."""
self.log.info("Test fundrawtxn p2pkh fee with multiple outputs")
+ self.lock_outputs_type(self.nodes[0], "p2pkh")
inputs = []
outputs = {
self.nodes[1].getnewaddress():1.1,
@@ -409,8 +449,11 @@ class RawTransactionsTest(BitcoinTestFramework):
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
assert feeDelta >= 0 and feeDelta <= self.fee_tolerance
+ self.unlock_utxos(self.nodes[0])
+
def test_fee_p2sh(self):
"""Compare fee of a 2-of-2 multisig p2sh transaction."""
+ self.lock_outputs_type(self.nodes[0], "p2pkh")
# Create 2-of-2 addr.
addr1 = self.nodes[1].getnewaddress()
addr2 = self.nodes[1].getnewaddress()
@@ -433,9 +476,12 @@ class RawTransactionsTest(BitcoinTestFramework):
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
assert feeDelta >= 0 and feeDelta <= self.fee_tolerance
+ self.unlock_utxos(self.nodes[0])
+
def test_fee_4of5(self):
"""Compare fee of a standard pubkeyhash transaction."""
self.log.info("Test fundrawtxn fee with 4-of-5 addresses")
+ self.lock_outputs_type(self.nodes[0], "p2pkh")
# Create 4-of-5 addr.
addr1 = self.nodes[1].getnewaddress()
@@ -474,6 +520,8 @@ class RawTransactionsTest(BitcoinTestFramework):
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
assert feeDelta >= 0 and feeDelta <= self.fee_tolerance
+ self.unlock_utxos(self.nodes[0])
+
def test_spend_2of2(self):
"""Spend a 2-of-2 multisig transaction over fundraw."""
self.log.info("Test fundpsbt spending 2-of-2 multisig")
@@ -542,15 +590,18 @@ class RawTransactionsTest(BitcoinTestFramework):
# Drain the keypool.
self.nodes[1].getnewaddress()
self.nodes[1].getrawchangeaddress()
- inputs = []
- outputs = {self.nodes[0].getnewaddress():1.19999500}
+
+ # Choose 2 inputs
+ inputs = self.nodes[1].listunspent()[0:2]
+ value = sum(inp["amount"] for inp in inputs) - Decimal("0.00000500") # Pay a 500 sat fee
+ outputs = {self.nodes[0].getnewaddress():value}
rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
# fund a transaction that does not require a new key for the change output
self.nodes[1].fundrawtransaction(rawtx)
# fund a transaction that requires a new key for the change output
# creating the key must be impossible because the wallet is locked
- outputs = {self.nodes[0].getnewaddress():1.1}
+ outputs = {self.nodes[0].getnewaddress():value - Decimal("0.1")}
rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
assert_raises_rpc_error(-4, "Transaction needs a change address, but we can't generate it.", self.nodes[1].fundrawtransaction, rawtx)
@@ -935,6 +986,56 @@ class RawTransactionsTest(BitcoinTestFramework):
wallet.sendmany("", outputs)
self.generate(self.nodes[0], 10)
assert_raises_rpc_error(-4, "Transaction too large", recipient.fundrawtransaction, rawtx)
+ self.nodes[0].unloadwallet("large")
+
+ def test_external_inputs(self):
+ self.log.info("Test funding with external inputs")
+
+ eckey = ECKey()
+ eckey.generate()
+ privkey = bytes_to_wif(eckey.get_bytes())
+
+ self.nodes[2].createwallet("extfund")
+ wallet = self.nodes[2].get_wallet_rpc("extfund")
+
+ # Make a weird but signable script. sh(pkh()) descriptor accomplishes this
+ desc = descsum_create("sh(pkh({}))".format(privkey))
+ if self.options.descriptors:
+ res = self.nodes[0].importdescriptors([{"desc": desc, "timestamp": "now"}])
+ else:
+ res = self.nodes[0].importmulti([{"desc": desc, "timestamp": "now"}])
+ assert res[0]["success"]
+ addr = self.nodes[0].deriveaddresses(desc)[0]
+ addr_info = self.nodes[0].getaddressinfo(addr)
+
+ self.nodes[0].sendtoaddress(addr, 10)
+ self.nodes[0].sendtoaddress(wallet.getnewaddress(), 10)
+ self.nodes[0].generate(6)
+ ext_utxo = self.nodes[0].listunspent(addresses=[addr])[0]
+
+ # An external input without solving data should result in an error
+ raw_tx = wallet.createrawtransaction([ext_utxo], {self.nodes[0].getnewaddress(): 15})
+ assert_raises_rpc_error(-4, "Insufficient funds", wallet.fundrawtransaction, raw_tx)
+
+ # Error conditions
+ assert_raises_rpc_error(-5, "'not a pubkey' is not hex", wallet.fundrawtransaction, raw_tx, {"solving_data": {"pubkeys":["not a pubkey"]}})
+ assert_raises_rpc_error(-5, "'01234567890a0b0c0d0e0f' is not a valid public key", wallet.fundrawtransaction, raw_tx, {"solving_data": {"pubkeys":["01234567890a0b0c0d0e0f"]}})
+ assert_raises_rpc_error(-5, "'not a script' is not hex", wallet.fundrawtransaction, raw_tx, {"solving_data": {"scripts":["not a script"]}})
+ assert_raises_rpc_error(-8, "Unable to parse descriptor 'not a descriptor'", wallet.fundrawtransaction, raw_tx, {"solving_data": {"descriptors":["not a descriptor"]}})
+
+ # But funding should work when the solving data is provided
+ funded_tx = wallet.fundrawtransaction(raw_tx, {"solving_data": {"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]}})
+ signed_tx = wallet.signrawtransactionwithwallet(funded_tx['hex'])
+ assert not signed_tx['complete']
+ signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx['hex'])
+ assert signed_tx['complete']
+
+ funded_tx = wallet.fundrawtransaction(raw_tx, {"solving_data": {"descriptors": [desc]}})
+ signed_tx = wallet.signrawtransactionwithwallet(funded_tx['hex'])
+ assert not signed_tx['complete']
+ signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx['hex'])
+ assert signed_tx['complete']
+ self.nodes[2].unloadwallet("extfund")
def test_include_unsafe(self):
self.log.info("Test fundrawtxn with unsafe inputs")
@@ -944,31 +1045,32 @@ class RawTransactionsTest(BitcoinTestFramework):
# We receive unconfirmed funds from external keys (unsafe outputs).
addr = wallet.getnewaddress()
- txid1 = self.nodes[2].sendtoaddress(addr, 6)
- txid2 = self.nodes[2].sendtoaddress(addr, 4)
- self.sync_all()
- vout1 = find_vout_for_address(wallet, txid1, addr)
- vout2 = find_vout_for_address(wallet, txid2, addr)
+ inputs = []
+ for i in range(0, 2):
+ txid = self.nodes[2].sendtoaddress(addr, 5)
+ self.sync_mempools()
+ vout = find_vout_for_address(wallet, txid, addr)
+ inputs.append((txid, vout))
# Unsafe inputs are ignored by default.
- rawtx = wallet.createrawtransaction([], [{self.nodes[2].getnewaddress(): 5}])
+ rawtx = wallet.createrawtransaction([], [{self.nodes[2].getnewaddress(): 7.5}])
assert_raises_rpc_error(-4, "Insufficient funds", wallet.fundrawtransaction, rawtx)
# But we can opt-in to use them for funding.
fundedtx = wallet.fundrawtransaction(rawtx, {"include_unsafe": True})
tx_dec = wallet.decoderawtransaction(fundedtx['hex'])
- assert any([txin['txid'] == txid1 and txin['vout'] == vout1 for txin in tx_dec['vin']])
+ assert all((txin["txid"], txin["vout"]) in inputs for txin in tx_dec["vin"])
signedtx = wallet.signrawtransactionwithwallet(fundedtx['hex'])
- wallet.sendrawtransaction(signedtx['hex'])
+ assert wallet.testmempoolaccept([signedtx['hex']])[0]["allowed"]
# And we can also use them once they're confirmed.
self.generate(self.nodes[0], 1)
- rawtx = wallet.createrawtransaction([], [{self.nodes[2].getnewaddress(): 3}])
- fundedtx = wallet.fundrawtransaction(rawtx, {"include_unsafe": True})
+ fundedtx = wallet.fundrawtransaction(rawtx, {"include_unsafe": False})
tx_dec = wallet.decoderawtransaction(fundedtx['hex'])
- assert any([txin['txid'] == txid2 and txin['vout'] == vout2 for txin in tx_dec['vin']])
+ assert all((txin["txid"], txin["vout"]) in inputs for txin in tx_dec["vin"])
signedtx = wallet.signrawtransactionwithwallet(fundedtx['hex'])
- wallet.sendrawtransaction(signedtx['hex'])
+ assert wallet.testmempoolaccept([signedtx['hex']])[0]["allowed"]
+ self.nodes[0].unloadwallet("unsafe")
def test_22670(self):
# In issue #22670, it was observed that ApproximateBestSubset may
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
index aa53e354a3..0f3bbce54c 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -12,11 +12,10 @@ 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 (
- NODE_NETWORK,
- NODE_WITNESS,
+from test_framework.p2p import (
+ P2PInterface,
+ P2P_SERVICES,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -189,7 +188,6 @@ class NetTest(BitcoinTestFramework):
def test_getnodeaddresses(self):
self.log.info("Test getnodeaddresses")
self.nodes[0].add_p2p_connection(P2PInterface())
- services = NODE_NETWORK | NODE_WITNESS
# Add an IPv6 address to the address manager.
ipv6_addr = "1233:3432:2434:2343:3234:2345:6546:4534"
@@ -217,7 +215,7 @@ class NetTest(BitcoinTestFramework):
assert_greater_than(10000, len(node_addresses))
for a in node_addresses:
assert_greater_than(a["time"], 1527811200) # 1st June 2018
- assert_equal(a["services"], services)
+ assert_equal(a["services"], P2P_SERVICES)
assert a["address"] in imported_addrs
assert_equal(a["port"], 8333)
assert_equal(a["network"], "ipv4")
@@ -228,7 +226,7 @@ class NetTest(BitcoinTestFramework):
assert_equal(res[0]["address"], ipv6_addr)
assert_equal(res[0]["network"], "ipv6")
assert_equal(res[0]["port"], 8333)
- assert_equal(res[0]["services"], services)
+ assert_equal(res[0]["services"], P2P_SERVICES)
# Test for the absence of onion and I2P addresses.
for network in ["onion", "i2p"]:
@@ -239,7 +237,16 @@ class NetTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Network not recognized: Foo", self.nodes[0].getnodeaddresses, 1, "Foo")
def test_addpeeraddress(self):
+ """RPC addpeeraddress sets the source address equal to the destination address.
+ If an address with the same /16 as an existing new entry is passed, it will be
+ placed in the same new bucket and have a 1/64 chance of the bucket positions
+ colliding (depending on the value of nKey in the addrman), in which case the
+ new address won't be added. The probability of collision can be reduced to
+ 1/2^16 = 1/65536 by using an address from a different /16. We avoid this here
+ by first testing adding a tried table entry before testing adding a new table one.
+ """
self.log.info("Test addpeeraddress")
+ self.restart_node(1, ["-checkaddrman=1"])
node = self.nodes[1]
self.log.debug("Test that addpeerinfo is a hidden RPC")
@@ -251,17 +258,25 @@ class NetTest(BitcoinTestFramework):
assert_equal(node.addpeeraddress(address="", port=8333), {"success": False})
assert_equal(node.getnodeaddresses(count=0), [])
- self.log.debug("Test that adding a valid address succeeds")
- assert_equal(node.addpeeraddress(address="1.2.3.4", port=8333), {"success": True})
- addrs = node.getnodeaddresses(count=0)
- assert_equal(len(addrs), 1)
- assert_equal(addrs[0]["address"], "1.2.3.4")
- assert_equal(addrs[0]["port"], 8333)
-
- self.log.debug("Test that adding the same address again when already present fails")
- assert_equal(node.addpeeraddress(address="1.2.3.4", port=8333), {"success": False})
+ self.log.debug("Test that adding a valid address to the tried table succeeds")
+ assert_equal(node.addpeeraddress(address="1.2.3.4", tried=True, port=8333), {"success": True})
+ with node.assert_debug_log(expected_msgs=["Addrman checks started: new 0, tried 1, total 1"]):
+ addrs = node.getnodeaddresses(count=0) # getnodeaddresses re-runs the addrman checks
+ assert_equal(len(addrs), 1)
+ assert_equal(addrs[0]["address"], "1.2.3.4")
+ assert_equal(addrs[0]["port"], 8333)
+
+ self.log.debug("Test that adding an already-present tried address to the new and tried tables fails")
+ for value in [True, False]:
+ assert_equal(node.addpeeraddress(address="1.2.3.4", tried=value, port=8333), {"success": False})
assert_equal(len(node.getnodeaddresses(count=0)), 1)
+ self.log.debug("Test that adding a second address, this time to the new table, succeeds")
+ assert_equal(node.addpeeraddress(address="2.0.0.0", port=8333), {"success": True})
+ with node.assert_debug_log(expected_msgs=["Addrman checks started: new 1, tried 1, total 2"]):
+ addrs = node.getnodeaddresses(count=0) # getnodeaddresses re-runs the addrman checks
+ assert_equal(len(addrs), 2)
+
if __name__ == '__main__':
NetTest().main()
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 2b1892c121..6b5b2c6a0f 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -8,6 +8,8 @@
from decimal import Decimal
from itertools import product
+from test_framework.descriptors import descsum_create
+from test_framework.key import ECKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_approx,
@@ -16,6 +18,7 @@ from test_framework.util import (
assert_raises_rpc_error,
find_output,
)
+from test_framework.wallet_util import bytes_to_wif
import json
import os
@@ -108,6 +111,16 @@ class PSBTTest(BitcoinTestFramework):
psbtx = self.nodes[1].walletprocesspsbt(psbtx1)['psbt']
assert_equal(psbtx1, psbtx)
+ # Node 0 should not be able to sign the transaction with the wallet is locked
+ self.nodes[0].encryptwallet("password")
+ assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].walletprocesspsbt, psbtx)
+
+ # Node 0 should be able to process without signing though
+ unsigned_tx = self.nodes[0].walletprocesspsbt(psbtx, False)
+ assert_equal(unsigned_tx['complete'], False)
+
+ self.nodes[0].walletpassphrase(passphrase="password", timeout=1000000)
+
# Sign the transaction and send
signed_tx = self.nodes[0].walletprocesspsbt(psbtx)['psbt']
final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex']
@@ -598,5 +611,42 @@ class PSBTTest(BitcoinTestFramework):
assert_raises_rpc_error(-25, 'Inputs missing or spent', self.nodes[0].walletprocesspsbt, 'cHNidP8BAJoCAAAAAkvEW8NnDtdNtDpsmze+Ht2LH35IJcKv00jKAlUs21RrAwAAAAD/////S8Rbw2cO1020OmybN74e3Ysffkglwq/TSMoCVSzbVGsBAAAAAP7///8CwLYClQAAAAAWABSNJKzjaUb3uOxixsvh1GGE3fW7zQD5ApUAAAAAFgAUKNw0x8HRctAgmvoevm4u1SbN7XIAAAAAAAEAnQIAAAACczMa321tVHuN4GKWKRncycI22aX3uXgwSFUKM2orjRsBAAAAAP7///9zMxrfbW1Ue43gYpYpGdzJwjbZpfe5eDBIVQozaiuNGwAAAAAA/v///wIA+QKVAAAAABl2qRT9zXUVA8Ls5iVqynLHe5/vSe1XyYisQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAAAAAQEfQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAA==')
+ # Test that we can fund psbts with external inputs specified
+ eckey = ECKey()
+ eckey.generate()
+ privkey = bytes_to_wif(eckey.get_bytes())
+
+ # Make a weird but signable script. sh(pkh()) descriptor accomplishes this
+ desc = descsum_create("sh(pkh({}))".format(privkey))
+ if self.options.descriptors:
+ res = self.nodes[0].importdescriptors([{"desc": desc, "timestamp": "now"}])
+ else:
+ res = self.nodes[0].importmulti([{"desc": desc, "timestamp": "now"}])
+ assert res[0]["success"]
+ addr = self.nodes[0].deriveaddresses(desc)[0]
+ addr_info = self.nodes[0].getaddressinfo(addr)
+
+ self.nodes[0].sendtoaddress(addr, 10)
+ self.nodes[0].generate(6)
+ ext_utxo = self.nodes[0].listunspent(addresses=[addr])[0]
+
+ # An external input without solving data should result in an error
+ assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[1].walletcreatefundedpsbt, [ext_utxo], {self.nodes[0].getnewaddress(): 10 + ext_utxo['amount']}, 0, {'add_inputs': True})
+
+ # But funding should work when the solving data is provided
+ psbt = self.nodes[1].walletcreatefundedpsbt([ext_utxo], {self.nodes[0].getnewaddress(): 15}, 0, {'add_inputs': True, "solving_data": {"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]}})
+ signed = self.nodes[1].walletprocesspsbt(psbt['psbt'])
+ assert not signed['complete']
+ signed = self.nodes[0].walletprocesspsbt(signed['psbt'])
+ assert signed['complete']
+ self.nodes[0].finalizepsbt(signed['psbt'])
+
+ psbt = self.nodes[1].walletcreatefundedpsbt([ext_utxo], {self.nodes[0].getnewaddress(): 15}, 0, {'add_inputs': True, "solving_data":{"descriptors": [desc]}})
+ signed = self.nodes[1].walletprocesspsbt(psbt['psbt'])
+ assert not signed['complete']
+ signed = self.nodes[0].walletprocesspsbt(signed['psbt'])
+ assert signed['complete']
+ self.nodes[0].finalizepsbt(signed['psbt'])
+
if __name__ == '__main__':
PSBTTest().main()
diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py
index 8f17b29ff4..18abece253 100755
--- a/test/functional/rpc_signrawtransaction.py
+++ b/test/functional/rpc_signrawtransaction.py
@@ -6,7 +6,6 @@
from test_framework.blocktools import (
COINBASE_MATURITY,
- CSV_ACTIVATION_HEIGHT,
)
from test_framework.address import (
script_to_p2sh,
@@ -18,7 +17,6 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
find_vout_for_address,
- generate_to_height,
)
from test_framework.messages import (
CTxInWitness,
@@ -273,7 +271,6 @@ class SignRawTransactionsTest(BitcoinTestFramework):
getcontext().prec = 8
# Make sure CSV is active
- generate_to_height(self, self.nodes[0], CSV_ACTIVATION_HEIGHT)
assert self.nodes[0].getblockchaininfo()['softforks']['csv']['active']
# Create a P2WSH script with CSV
diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py
index 81eb881234..c4ffd1fbf6 100644
--- a/test/functional/test_framework/authproxy.py
+++ b/test/functional/test_framework/authproxy.py
@@ -113,10 +113,8 @@ class AuthServiceProxy():
self.__conn.request(method, path, postdata, headers)
return self._get_response()
except OSError as e:
- retry = (
- '[WinError 10053] An established connection was aborted by the software in your host machine' in str(e))
# Workaround for a bug on macOS. See https://bugs.python.org/issue33450
- retry = retry or ('[Errno 41] Protocol wrong type for socket' in str(e))
+ retry = '[Errno 41] Protocol wrong type for socket' in str(e)
if retry:
self.__conn.close()
self.__conn.request(method, path, postdata, headers)
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 25b36b6a91..6de372cd8e 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -53,11 +53,6 @@ TIME_GENESIS_BLOCK = 1296688602
# Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
COINBASE_MATURITY = 100
-# Soft-fork activation heights
-DERSIG_HEIGHT = 102 # BIP 66
-CLTV_HEIGHT = 111 # BIP 65
-CSV_ACTIVATION_HEIGHT = 432
-
# From BIP141
WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py
index b7d5bd8fab..78c63b57a1 100755
--- a/test/functional/test_framework/p2p.py
+++ b/test/functional/test_framework/p2p.py
@@ -356,7 +356,7 @@ class P2PInterface(P2PConnection):
return create_conn
- def peer_accept_connection(self, *args, services=NODE_NETWORK | NODE_WITNESS, **kwargs):
+ def peer_accept_connection(self, *args, services=P2P_SERVICES, **kwargs):
create_conn = super().peer_accept_connection(*args, **kwargs)
self.peer_connect_send_version(services)
@@ -577,6 +577,8 @@ class NetworkThread(threading.Thread):
NetworkThread.listeners = {}
NetworkThread.protos = {}
+ if sys.platform == 'win32':
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
NetworkThread.network_event_loop = asyncio.new_event_loop()
def run(self):
diff --git a/test/functional/test_framework/script_util.py b/test/functional/test_framework/script_util.py
index 5d1d7ea45c..e0dfce4c2f 100755
--- a/test/functional/test_framework/script_util.py
+++ b/test/functional/test_framework/script_util.py
@@ -3,7 +3,17 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Useful Script constants and utils."""
-from test_framework.script import CScript, hash160, sha256, OP_0, OP_DUP, OP_HASH160, OP_CHECKSIG, OP_EQUAL, OP_EQUALVERIFY
+from test_framework.script import (
+ CScript,
+ hash160,
+ sha256,
+ OP_0,
+ OP_DUP,
+ OP_HASH160,
+ OP_CHECKSIG,
+ OP_EQUAL,
+ OP_EQUALVERIFY,
+)
# To prevent a "tx-size-small" policy rule error, a transaction has to have a
# non-witness size of at least 82 bytes (MIN_STANDARD_TX_NONWITNESS_SIZE in
@@ -25,28 +35,34 @@ from test_framework.script import CScript, hash160, sha256, OP_0, OP_DUP, OP_HAS
DUMMY_P2WPKH_SCRIPT = CScript([b'a' * 21])
DUMMY_2_P2WPKH_SCRIPT = CScript([b'b' * 21])
-def keyhash_to_p2pkh_script(hash, main = False):
+
+def keyhash_to_p2pkh_script(hash):
assert len(hash) == 20
return CScript([OP_DUP, OP_HASH160, hash, OP_EQUALVERIFY, OP_CHECKSIG])
-def scripthash_to_p2sh_script(hash, main = False):
+
+def scripthash_to_p2sh_script(hash):
assert len(hash) == 20
return CScript([OP_HASH160, hash, OP_EQUAL])
-def key_to_p2pkh_script(key, main = False):
+
+def key_to_p2pkh_script(key):
key = check_key(key)
- return keyhash_to_p2pkh_script(hash160(key), main)
+ return keyhash_to_p2pkh_script(hash160(key))
-def script_to_p2sh_script(script, main = False):
+
+def script_to_p2sh_script(script):
script = check_script(script)
- return scripthash_to_p2sh_script(hash160(script), main)
+ return scripthash_to_p2sh_script(hash160(script))
+
-def key_to_p2sh_p2wpkh_script(key, main = False):
+def key_to_p2sh_p2wpkh_script(key):
key = check_key(key)
p2shscript = CScript([OP_0, hash160(key)])
- return script_to_p2sh_script(p2shscript, main)
+ return script_to_p2sh_script(p2shscript)
+
-def program_to_witness_script(version, program, main = False):
+def program_to_witness_script(version, program):
if isinstance(program, str):
program = bytes.fromhex(program)
assert 0 <= version <= 16
@@ -54,29 +70,34 @@ def program_to_witness_script(version, program, main = False):
assert version > 0 or len(program) in [20, 32]
return CScript([version, program])
-def script_to_p2wsh_script(script, main = False):
+
+def script_to_p2wsh_script(script):
script = check_script(script)
- return program_to_witness_script(0, sha256(script), main)
+ return program_to_witness_script(0, sha256(script))
+
-def key_to_p2wpkh_script(key, main = False):
+def key_to_p2wpkh_script(key):
key = check_key(key)
- return program_to_witness_script(0, hash160(key), main)
+ return program_to_witness_script(0, hash160(key))
+
-def script_to_p2sh_p2wsh_script(script, main = False):
+def script_to_p2sh_p2wsh_script(script):
script = check_script(script)
p2shscript = CScript([OP_0, sha256(script)])
- return script_to_p2sh_script(p2shscript, main)
+ return script_to_p2sh_script(p2shscript)
+
def check_key(key):
if isinstance(key, str):
- key = bytes.fromhex(key) # Assuming this is hex string
+ key = bytes.fromhex(key) # Assuming this is hex string
if isinstance(key, bytes) and (len(key) == 33 or len(key) == 65):
return key
assert False
+
def check_script(script):
if isinstance(script, str):
- script = bytes.fromhex(script) # Assuming this is hex string
+ script = bytes.fromhex(script) # Assuming this is hex string
if isinstance(script, bytes) or isinstance(script, CScript):
return script
assert False
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 0fad4071e2..d87d0cacfd 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -567,18 +567,19 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.nodes[i].process.wait(timeout)
def connect_nodes(self, a, b):
- def connect_nodes_helper(from_connection, node_num):
- ip_port = "127.0.0.1:" + str(p2p_port(node_num))
- from_connection.addnode(ip_port, "onetry")
- # poll until version handshake complete to avoid race conditions
- # with transaction relaying
- # See comments in net_processing:
- # * Must have a version message before anything else
- # * Must have a verack message before anything else
- wait_until_helper(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo()))
- wait_until_helper(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in from_connection.getpeerinfo()))
-
- connect_nodes_helper(self.nodes[a], b)
+ from_connection = self.nodes[a]
+ to_connection = self.nodes[b]
+ ip_port = "127.0.0.1:" + str(p2p_port(b))
+ from_connection.addnode(ip_port, "onetry")
+ # poll until version handshake complete to avoid race conditions
+ # with transaction relaying
+ # See comments in net_processing:
+ # * Must have a version message before anything else
+ # * Must have a verack message before anything else
+ wait_until_helper(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo()))
+ wait_until_helper(lambda: all(peer['version'] != 0 for peer in to_connection.getpeerinfo()))
+ wait_until_helper(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in from_connection.getpeerinfo()))
+ wait_until_helper(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in to_connection.getpeerinfo()))
def disconnect_nodes(self, a, b):
def disconnect_nodes_helper(from_connection, node_num):
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index d66499dbcb..9f5bca6884 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -34,13 +34,14 @@ def assert_approx(v, vexp, vspan=0.00001):
raise AssertionError("%s > [%s..%s]" % (str(v), str(vexp - vspan), str(vexp + vspan)))
-def assert_fee_amount(fee, tx_size, fee_per_kB):
- """Assert the fee was in range"""
- target_fee = round(tx_size * fee_per_kB / 1000, 8)
+def assert_fee_amount(fee, tx_size, feerate_BTC_kvB):
+ """Assert the fee is in range."""
+ feerate_BTC_vB = feerate_BTC_kvB / 1000
+ target_fee = satoshi_round(tx_size * feerate_BTC_vB)
if fee < target_fee:
raise AssertionError("Fee of %s BTC too low! (Should be %s BTC)" % (str(fee), str(target_fee)))
# allow the wallet's estimation to be at most 2 bytes off
- if fee > (tx_size + 2) * fee_per_kB / 1000:
+ if fee > (tx_size + 2) * feerate_BTC_vB:
raise AssertionError("Fee of %s BTC too high! (Should be %s BTC)" % (str(fee), str(target_fee)))
@@ -366,7 +367,7 @@ def write_config(config_path, *, n, chain, extra_config="", disable_autoconnect=
f.write("listenonion=0\n")
# Increase peertimeout to avoid disconnects while using mocktime.
# peertimeout is measured in wall clock time, so setting it to the
- # duration of the longest test is sufficient. It can be overriden in
+ # duration of the longest test is sufficient. It can be overridden in
# tests.
f.write("peertimeout=999999\n")
f.write("printtoconsole=0\n")
@@ -560,17 +561,6 @@ def mine_large_block(test_framework, node, utxos=None):
test_framework.generate(node, 1)
-def generate_to_height(test_framework, node, target_height):
- """Generates blocks until a given target block height has been reached.
- To prevent timeouts, only up to 200 blocks are generated per RPC call.
- Can be used to activate certain soft-forks (e.g. CSV, CLTV)."""
- current_height = node.getblockcount()
- while current_height < target_height:
- nblocks = min(200, target_height - current_height)
- current_height += len(test_framework.generate(node, nblocks))
- assert_equal(node.getblockcount(), target_height)
-
-
def find_vout_for_address(node, txid, addr):
"""
Locate the vout index of the given transaction sending to the
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 08086bc0b9..ef27cb3221 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -28,6 +28,7 @@ from test_framework.script import (
OP_NOP,
SIGHASH_ALL,
)
+from test_framework.script_util import key_to_p2wpkh_script
from test_framework.util import (
assert_equal,
assert_greater_than_or_equal,
@@ -82,18 +83,11 @@ class MiniWallet:
def rescan_utxos(self):
"""Drop all utxos and rescan the utxo set"""
self._utxos = []
- res = self._test_node.scantxoutset(action="start", scanobjects=[f'raw({self._scriptPubKey.hex()})'])
+ res = self._test_node.scantxoutset(action="start", scanobjects=[self.get_descriptor()])
assert_equal(True, res['success'])
for utxo in res['unspents']:
self._utxos.append({'txid': utxo['txid'], 'vout': utxo['vout'], 'value': utxo['amount']})
- def scan_blocks(self, *, start=1, num):
- """Scan the blocks for self._address outputs and add them to self._utxos"""
- for i in range(start, start + num):
- block = self._test_node.getblock(blockhash=self._test_node.getblockhash(i), verbosity=2)
- for tx in block['tx']:
- self.scan_tx(tx)
-
def scan_tx(self, tx):
"""Scan the tx for self._scriptPubKey outputs and add them to self._utxos"""
for out in tx['vout']:
@@ -117,12 +111,15 @@ class MiniWallet:
def generate(self, num_blocks):
"""Generate blocks with coinbase outputs to the internal address, and append the outputs to the internal list"""
- blocks = self._test_node.generatetodescriptor(num_blocks, f'raw({self._scriptPubKey.hex()})')
+ blocks = self._test_node.generatetodescriptor(num_blocks, self.get_descriptor())
for b in blocks:
cb_tx = self._test_node.getblock(blockhash=b, verbosity=2)['tx'][0]
self._utxos.append({'txid': cb_tx['txid'], 'vout': 0, 'value': cb_tx['vout'][0]['value']})
return blocks
+ def get_descriptor(self):
+ return self._test_node.getdescriptorinfo(f'raw({self._scriptPubKey.hex()})')['descriptor']
+
def get_address(self):
return self._address
@@ -150,6 +147,25 @@ class MiniWallet:
self.sendrawtransaction(from_node=kwargs['from_node'], tx_hex=tx['hex'])
return tx
+ def send_to(self, *, from_node, scriptPubKey, amount, fee=1000):
+ """
+ Create and send a tx with an output to a given scriptPubKey/amount,
+ plus a change output to our internal address. To keep things simple, a
+ fixed fee given in Satoshi is used.
+
+ Note that this method fails if there is no single internal utxo
+ available that can cover the cost for the amount and the fixed fee
+ (the utxo with the largest value is taken).
+
+ Returns a tuple (txid, n) referring to the created external utxo outpoint.
+ """
+ tx = self.create_self_transfer(from_node=from_node, fee_rate=0, mempool_valid=False)['tx']
+ assert_greater_than_or_equal(tx.vout[0].nValue, amount + fee)
+ tx.vout[0].nValue -= (amount + fee) # change output -> MiniWallet
+ tx.vout.append(CTxOut(amount, scriptPubKey)) # arbitrary output -> to be returned
+ txid = self.sendrawtransaction(from_node=from_node, tx_hex=tx.serialize().hex())
+ return txid, 1
+
def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, mempool_valid=True, locktime=0, sequence=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'])
@@ -187,8 +203,18 @@ class MiniWallet:
return {'txid': tx_info['txid'], 'wtxid': tx_info['wtxid'], 'hex': tx_hex, 'tx': tx}
def sendrawtransaction(self, *, from_node, tx_hex):
- from_node.sendrawtransaction(tx_hex)
+ txid = from_node.sendrawtransaction(tx_hex)
self.scan_tx(from_node.decoderawtransaction(tx_hex))
+ return txid
+
+
+def random_p2wpkh():
+ """Generate a random P2WPKH scriptPubKey. Can be used when a random destination is needed,
+ but no compiled wallet is available (e.g. as replacement to the getnewaddress RPC)."""
+ key = ECKey()
+ key.generate()
+ return key_to_p2wpkh_script(key.get_pubkey().get_bytes())
+
def make_chain(node, address, privkeys, parent_txid, parent_value, n=0, parent_locking_script=None, fee=DEFAULT_FEE):
"""Build a transaction that spends parent_txid.vout[n] and produces one output with
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index c5af10430c..c5f08b27f2 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -98,6 +98,7 @@ BASE_SCRIPTS = [
'rpc_fundrawtransaction.py --legacy-wallet',
'rpc_fundrawtransaction.py --descriptors',
'p2p_compactblocks.py',
+ 'p2p_compactblocks_blocksonly.py',
'feature_segwit.py --legacy-wallet',
# vv Tests less than 2m vv
'wallet_basic.py --legacy-wallet',
@@ -176,6 +177,7 @@ BASE_SCRIPTS = [
'rpc_rawtransaction.py --legacy-wallet',
'rpc_rawtransaction.py --descriptors',
'wallet_groups.py --legacy-wallet',
+ 'wallet_transactiontime_rescan.py',
'p2p_addrv2_relay.py',
'wallet_groups.py --descriptors',
'p2p_compactblocks_hb.py',
@@ -305,7 +307,6 @@ BASE_SCRIPTS = [
'feature_presegwit_node_upgrade.py',
'feature_settings.py',
'rpc_getdescriptorinfo.py',
- 'rpc_addresses_deprecation.py',
'rpc_help.py',
'feature_help.py',
'feature_shutdown.py',
@@ -402,8 +403,9 @@ def main():
for test in tests:
script = test.split("/")[-1]
script = script + ".py" if ".py" not in script else script
- if script in ALL_SCRIPTS:
- test_list.append(script)
+ matching_scripts = [s for s in ALL_SCRIPTS if s.startswith(script)]
+ if matching_scripts:
+ test_list.extend(matching_scripts)
else:
print("{}WARNING!{} Test '{}' not found in full test list.".format(BOLD[1], BOLD[0], test))
elif args.extended:
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 6372e1acd7..599e506f98 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -13,6 +13,7 @@ from test_framework.util import (
assert_equal,
assert_fee_amount,
assert_raises_rpc_error,
+ find_vout_for_address,
)
from test_framework.wallet_util import test_address
@@ -121,13 +122,49 @@ class WalletTest(BitcoinTestFramework):
# Exercise locking of unspent outputs
unspent_0 = self.nodes[2].listunspent()[0]
unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]}
+ # Trying to unlock an output which isn't locked should error
assert_raises_rpc_error(-8, "Invalid parameter, expected locked output", self.nodes[2].lockunspent, True, [unspent_0])
+
+ # Locking an already-locked output should error
self.nodes[2].lockunspent(False, [unspent_0])
assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0])
+
+ # Restarting the node should clear the lock
+ self.restart_node(2)
+ self.nodes[2].lockunspent(False, [unspent_0])
+
+ # Unloading and reloating the wallet should clear the lock
+ assert_equal(self.nodes[0].listwallets(), [self.default_wallet_name])
+ self.nodes[2].unloadwallet(self.default_wallet_name)
+ self.nodes[2].loadwallet(self.default_wallet_name)
+ assert_equal(len(self.nodes[2].listlockunspent()), 0)
+
+ # Locking non-persistently, then re-locking persistently, is allowed
+ self.nodes[2].lockunspent(False, [unspent_0])
+ self.nodes[2].lockunspent(False, [unspent_0], True)
+
+ # Restarting the node with the lock written to the wallet should keep the lock
+ self.restart_node(2)
+ assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0])
+
+ # Unloading and reloading the wallet with a persistent lock should keep the lock
+ self.nodes[2].unloadwallet(self.default_wallet_name)
+ self.nodes[2].loadwallet(self.default_wallet_name)
+ assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0])
+
+ # Locked outputs should not be used, even if they are the only available funds
assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20)
assert_equal([unspent_0], self.nodes[2].listlockunspent())
+
+ # Unlocking should remove the persistent lock
self.nodes[2].lockunspent(True, [unspent_0])
+ self.restart_node(2)
assert_equal(len(self.nodes[2].listlockunspent()), 0)
+
+ # Reconnect node 2 after restarts
+ self.connect_nodes(1, 2)
+ self.connect_nodes(0, 2)
+
assert_raises_rpc_error(-8, "txid must be of length 64 (not 34, for '0000000000000000000000000000000000')",
self.nodes[2].lockunspent, False,
[{"txid": "0000000000000000000000000000000000", "vout": 0}])
@@ -427,6 +464,9 @@ class WalletTest(BitcoinTestFramework):
# 1. Send some coins to generate new UTXO
address_to_import = self.nodes[2].getnewaddress()
txid = self.nodes[0].sendtoaddress(address_to_import, 1)
+ self.sync_mempools(self.nodes[0:3])
+ vout = find_vout_for_address(self.nodes[2], txid, address_to_import)
+ self.nodes[2].lockunspent(False, [{"txid": txid, "vout": vout}])
self.generate(self.nodes[0], 1)
self.sync_all(self.nodes[0:3])
@@ -542,23 +582,17 @@ class WalletTest(BitcoinTestFramework):
assert label in self.nodes[0].listlabels()
self.nodes[0].rpc.ensure_ascii = True # restore to default
- # maintenance tests
- maintenance = [
- '-rescan',
- '-reindex',
- ]
+ # -reindex tests
chainlimit = 6
- for m in maintenance:
- self.log.info("Test " + m)
- self.stop_nodes()
- # set lower ancestor limit for later
- self.start_node(0, [m, "-limitancestorcount=" + str(chainlimit)])
- self.start_node(1, [m, "-limitancestorcount=" + str(chainlimit)])
- self.start_node(2, [m, "-limitancestorcount=" + str(chainlimit)])
- if m == '-reindex':
- # reindex will leave rpc warm up "early"; Wait for it to finish
- self.wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)])
- assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)])
+ self.log.info("Test -reindex")
+ self.stop_nodes()
+ # set lower ancestor limit for later
+ self.start_node(0, ['-reindex', "-limitancestorcount=" + str(chainlimit)])
+ self.start_node(1, ['-reindex', "-limitancestorcount=" + str(chainlimit)])
+ self.start_node(2, ['-reindex', "-limitancestorcount=" + str(chainlimit)])
+ # reindex will leave rpc warm up "early"; Wait for it to finish
+ self.wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)])
+ assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)])
# Exercise listsinceblock with the last two blocks
coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0])
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index 74f584f2cd..974ce7f381 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -103,7 +103,7 @@ class WalletHDTest(BitcoinTestFramework):
self.sync_all()
# Needs rescan
- self.restart_node(1, extra_args=self.extra_args[1] + ['-rescan'])
+ self.nodes[1].rescanblockchain()
assert_equal(self.nodes[1].getbalance(), NUM_HD_ADDS + 1)
# Try a RPC based rescan
diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py
index aecdaf821f..7b23235945 100755
--- a/test/functional/wallet_send.py
+++ b/test/functional/wallet_send.py
@@ -9,6 +9,7 @@ from itertools import product
from test_framework.authproxy import JSONRPCException
from test_framework.descriptors import descsum_create
+from test_framework.key import ECKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -16,6 +17,7 @@ from test_framework.util import (
assert_greater_than,
assert_raises_rpc_error,
)
+from test_framework.wallet_util import bytes_to_wif
class WalletSendTest(BitcoinTestFramework):
def set_test_params(self):
@@ -35,7 +37,7 @@ class WalletSendTest(BitcoinTestFramework):
conf_target=None, estimate_mode=None, fee_rate=None, add_to_wallet=None, psbt=None,
inputs=None, add_inputs=None, include_unsafe=None, change_address=None, change_position=None, change_type=None,
include_watching=None, locktime=None, lock_unspents=None, replaceable=None, subtract_fee_from_outputs=None,
- expect_error=None):
+ expect_error=None, solving_data=None):
assert (amount is None) != (data is None)
from_balance_before = from_wallet.getbalances()["mine"]["trusted"]
@@ -94,6 +96,8 @@ class WalletSendTest(BitcoinTestFramework):
options["replaceable"] = replaceable
if subtract_fee_from_outputs is not None:
options["subtract_fee_from_outputs"] = subtract_fee_from_outputs
+ if solving_data is not None:
+ options["solving_data"] = solving_data
if len(options.keys()) == 0:
options = None
@@ -476,6 +480,46 @@ class WalletSendTest(BitcoinTestFramework):
res = self.test_send(from_wallet=w5, to_wallet=w0, amount=1, include_unsafe=True)
assert res["complete"]
+ self.log.info("External outputs")
+ eckey = ECKey()
+ eckey.generate()
+ privkey = bytes_to_wif(eckey.get_bytes())
+
+ self.nodes[1].createwallet("extsend")
+ ext_wallet = self.nodes[1].get_wallet_rpc("extsend")
+ self.nodes[1].createwallet("extfund")
+ ext_fund = self.nodes[1].get_wallet_rpc("extfund")
+
+ # Make a weird but signable script. sh(pkh()) descriptor accomplishes this
+ desc = descsum_create("sh(pkh({}))".format(privkey))
+ if self.options.descriptors:
+ res = ext_fund.importdescriptors([{"desc": desc, "timestamp": "now"}])
+ else:
+ res = ext_fund.importmulti([{"desc": desc, "timestamp": "now"}])
+ assert res[0]["success"]
+ addr = self.nodes[0].deriveaddresses(desc)[0]
+ addr_info = ext_fund.getaddressinfo(addr)
+
+ self.nodes[0].sendtoaddress(addr, 10)
+ self.nodes[0].sendtoaddress(ext_wallet.getnewaddress(), 10)
+ self.nodes[0].generate(6)
+ ext_utxo = ext_fund.listunspent(addresses=[addr])[0]
+
+ # An external input without solving data should result in an error
+ self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, include_watching=True, expect_error=(-4, "Insufficient funds"))
+
+ # But funding should work when the solving data is provided
+ res = self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, include_watching=True, solving_data={"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]})
+ signed = ext_wallet.walletprocesspsbt(res["psbt"])
+ signed = ext_fund.walletprocesspsbt(res["psbt"])
+ assert signed["complete"]
+ self.nodes[0].finalizepsbt(signed["psbt"])
+
+ res = self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, include_watching=True, solving_data={"descriptors": [desc]})
+ signed = ext_wallet.walletprocesspsbt(res["psbt"])
+ signed = ext_fund.walletprocesspsbt(res["psbt"])
+ assert signed["complete"]
+ self.nodes[0].finalizepsbt(signed["psbt"])
if __name__ == '__main__':
WalletSendTest().main()
diff --git a/test/functional/wallet_transactiontime_rescan.py b/test/functional/wallet_transactiontime_rescan.py
new file mode 100755
index 0000000000..78859e6131
--- /dev/null
+++ b/test/functional/wallet_transactiontime_rescan.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018-2019 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 transaction time during old block rescanning
+"""
+
+import time
+
+from test_framework.blocktools import COINBASE_MATURITY
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal
+)
+
+
+class TransactionTimeRescanTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = False
+ self.num_nodes = 3
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ self.log.info('Prepare nodes and wallet')
+
+ minernode = self.nodes[0] # node used to mine BTC and create transactions
+ usernode = self.nodes[1] # user node with correct time
+ restorenode = self.nodes[2] # node used to restore user wallet and check time determination in ComputeSmartTime (wallet.cpp)
+
+ # time constant
+ cur_time = int(time.time())
+ ten_days = 10 * 24 * 60 * 60
+
+ # synchronize nodes and time
+ self.sync_all()
+ minernode.setmocktime(cur_time)
+ usernode.setmocktime(cur_time)
+ restorenode.setmocktime(cur_time)
+
+ # prepare miner wallet
+ minernode.createwallet(wallet_name='default')
+ miner_wallet = minernode.get_wallet_rpc('default')
+ m1 = miner_wallet.getnewaddress()
+
+ # prepare the user wallet with 3 watch only addresses
+ wo1 = usernode.getnewaddress()
+ wo2 = usernode.getnewaddress()
+ wo3 = usernode.getnewaddress()
+
+ usernode.createwallet(wallet_name='wo', disable_private_keys=True)
+ wo_wallet = usernode.get_wallet_rpc('wo')
+
+ wo_wallet.importaddress(wo1)
+ wo_wallet.importaddress(wo2)
+ wo_wallet.importaddress(wo3)
+
+ self.log.info('Start transactions')
+
+ # check blockcount
+ assert_equal(minernode.getblockcount(), 200)
+
+ # generate some btc to create transactions and check blockcount
+ initial_mine = COINBASE_MATURITY + 1
+ minernode.generatetoaddress(initial_mine, m1)
+ assert_equal(minernode.getblockcount(), initial_mine + 200)
+
+ # synchronize nodes and time
+ self.sync_all()
+ minernode.setmocktime(cur_time + ten_days)
+ usernode.setmocktime(cur_time + ten_days)
+ restorenode.setmocktime(cur_time + ten_days)
+ # send 10 btc to user's first watch-only address
+ self.log.info('Send 10 btc to user')
+ miner_wallet.sendtoaddress(wo1, 10)
+
+ # generate blocks and check blockcount
+ minernode.generatetoaddress(COINBASE_MATURITY, m1)
+ assert_equal(minernode.getblockcount(), initial_mine + 300)
+
+ # synchronize nodes and time
+ self.sync_all()
+ minernode.setmocktime(cur_time + ten_days + ten_days)
+ usernode.setmocktime(cur_time + ten_days + ten_days)
+ restorenode.setmocktime(cur_time + ten_days + ten_days)
+ # send 5 btc to our second watch-only address
+ self.log.info('Send 5 btc to user')
+ miner_wallet.sendtoaddress(wo2, 5)
+
+ # generate blocks and check blockcount
+ minernode.generatetoaddress(COINBASE_MATURITY, m1)
+ assert_equal(minernode.getblockcount(), initial_mine + 400)
+
+ # synchronize nodes and time
+ self.sync_all()
+ minernode.setmocktime(cur_time + ten_days + ten_days + ten_days)
+ usernode.setmocktime(cur_time + ten_days + ten_days + ten_days)
+ restorenode.setmocktime(cur_time + ten_days + ten_days + ten_days)
+ # send 1 btc to our third watch-only address
+ self.log.info('Send 1 btc to user')
+ miner_wallet.sendtoaddress(wo3, 1)
+
+ # generate more blocks and check blockcount
+ minernode.generatetoaddress(COINBASE_MATURITY, m1)
+ assert_equal(minernode.getblockcount(), initial_mine + 500)
+
+ self.log.info('Check user\'s final balance and transaction count')
+ assert_equal(wo_wallet.getbalance(), 16)
+ assert_equal(len(wo_wallet.listtransactions()), 3)
+
+ self.log.info('Check transaction times')
+ for tx in wo_wallet.listtransactions():
+ if tx['address'] == wo1:
+ assert_equal(tx['blocktime'], cur_time + ten_days)
+ assert_equal(tx['time'], cur_time + ten_days)
+ elif tx['address'] == wo2:
+ assert_equal(tx['blocktime'], cur_time + ten_days + ten_days)
+ assert_equal(tx['time'], cur_time + ten_days + ten_days)
+ elif tx['address'] == wo3:
+ assert_equal(tx['blocktime'], cur_time + ten_days + ten_days + ten_days)
+ assert_equal(tx['time'], cur_time + ten_days + ten_days + ten_days)
+
+ # restore user wallet without rescan
+ self.log.info('Restore user wallet on another node without rescan')
+ restorenode.createwallet(wallet_name='wo', disable_private_keys=True)
+ restorewo_wallet = restorenode.get_wallet_rpc('wo')
+
+ restorewo_wallet.importaddress(wo1, rescan=False)
+ restorewo_wallet.importaddress(wo2, rescan=False)
+ restorewo_wallet.importaddress(wo3, rescan=False)
+
+ # check user has 0 balance and no transactions
+ assert_equal(restorewo_wallet.getbalance(), 0)
+ assert_equal(len(restorewo_wallet.listtransactions()), 0)
+
+ # proceed to rescan, first with an incomplete one, then with a full rescan
+ self.log.info('Rescan last history part')
+ restorewo_wallet.rescanblockchain(initial_mine + 350)
+ self.log.info('Rescan all history')
+ restorewo_wallet.rescanblockchain()
+
+ self.log.info('Check user\'s final balance and transaction count after restoration')
+ assert_equal(restorewo_wallet.getbalance(), 16)
+ assert_equal(len(restorewo_wallet.listtransactions()), 3)
+
+ self.log.info('Check transaction times after restoration')
+ for tx in restorewo_wallet.listtransactions():
+ if tx['address'] == wo1:
+ assert_equal(tx['blocktime'], cur_time + ten_days)
+ assert_equal(tx['time'], cur_time + ten_days)
+ elif tx['address'] == wo2:
+ assert_equal(tx['blocktime'], cur_time + ten_days + ten_days)
+ assert_equal(tx['time'], cur_time + ten_days + ten_days)
+ elif tx['address'] == wo3:
+ assert_equal(tx['blocktime'], cur_time + ten_days + ten_days + ten_days)
+ assert_equal(tx['time'], cur_time + ten_days + ten_days + ten_days)
+
+
+if __name__ == '__main__':
+ TransactionTimeRescanTest().main()
diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py
index 3eb525a9bc..7f178d7d46 100755
--- a/test/functional/wallet_txn_clone.py
+++ b/test/functional/wallet_txn_clone.py
@@ -7,6 +7,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
+ find_vout_for_address
)
from test_framework.messages import (
COIN,
@@ -33,6 +34,13 @@ class TxnMallTest(BitcoinTestFramework):
super().setup_network()
self.disconnect_nodes(1, 2)
+ def spend_txid(self, txid, vout, outputs):
+ inputs = [{"txid": txid, "vout": vout}]
+ tx = self.nodes[0].createrawtransaction(inputs, outputs)
+ tx = self.nodes[0].fundrawtransaction(tx)
+ tx = self.nodes[0].signrawtransactionwithwallet(tx['hex'])
+ return self.nodes[0].sendrawtransaction(tx['hex'])
+
def run_test(self):
if self.options.segwit:
output_type = "p2sh-segwit"
@@ -49,6 +57,7 @@ class TxnMallTest(BitcoinTestFramework):
node0_address1 = self.nodes[0].getnewaddress(address_type=output_type)
node0_txid1 = self.nodes[0].sendtoaddress(node0_address1, 1219)
node0_tx1 = self.nodes[0].gettransaction(node0_txid1)
+ self.nodes[0].lockunspent(False, [{"txid":node0_txid1, "vout": find_vout_for_address(self.nodes[0], node0_txid1, node0_address1)}])
node0_address2 = self.nodes[0].getnewaddress(address_type=output_type)
node0_txid2 = self.nodes[0].sendtoaddress(node0_address2, 29)
@@ -61,8 +70,8 @@ class TxnMallTest(BitcoinTestFramework):
node1_address = self.nodes[1].getnewaddress()
# Send tx1, and another transaction tx2 that won't be cloned
- txid1 = self.nodes[0].sendtoaddress(node1_address, 40)
- txid2 = self.nodes[0].sendtoaddress(node1_address, 20)
+ txid1 = self.spend_txid(node0_txid1, find_vout_for_address(self.nodes[0], node0_txid1, node0_address1), {node1_address: 40})
+ txid2 = self.spend_txid(node0_txid2, find_vout_for_address(self.nodes[0], node0_txid2, node0_address2), {node1_address: 20})
# Construct a clone of tx1, to be malleated
rawtx1 = self.nodes[0].getrawtransaction(txid1, 1)
diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py
index bfa171d913..150e4083b9 100755
--- a/test/functional/wallet_txn_doublespend.py
+++ b/test/functional/wallet_txn_doublespend.py
@@ -9,6 +9,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
find_output,
+ find_vout_for_address
)
@@ -29,6 +30,13 @@ class TxnMallTest(BitcoinTestFramework):
super().setup_network()
self.disconnect_nodes(1, 2)
+ def spend_txid(self, txid, vout, outputs):
+ inputs = [{"txid": txid, "vout": vout}]
+ tx = self.nodes[0].createrawtransaction(inputs, outputs)
+ tx = self.nodes[0].fundrawtransaction(tx)
+ tx = self.nodes[0].signrawtransactionwithwallet(tx['hex'])
+ return self.nodes[0].sendrawtransaction(tx['hex'])
+
def run_test(self):
# All nodes should start with 1,250 BTC:
starting_balance = 1250
@@ -47,6 +55,7 @@ class TxnMallTest(BitcoinTestFramework):
node0_address_foo = self.nodes[0].getnewaddress()
fund_foo_txid = self.nodes[0].sendtoaddress(node0_address_foo, 1219)
fund_foo_tx = self.nodes[0].gettransaction(fund_foo_txid)
+ self.nodes[0].lockunspent(False, [{"txid":fund_foo_txid, "vout": find_vout_for_address(self.nodes[0], fund_foo_txid, node0_address_foo)}])
node0_address_bar = self.nodes[0].getnewaddress()
fund_bar_txid = self.nodes[0].sendtoaddress(node0_address_bar, 29)
@@ -77,8 +86,8 @@ class TxnMallTest(BitcoinTestFramework):
assert_equal(doublespend["complete"], True)
# Create two spends using 1 50 BTC coin each
- txid1 = self.nodes[0].sendtoaddress(node1_address, 40)
- txid2 = self.nodes[0].sendtoaddress(node1_address, 20)
+ txid1 = self.spend_txid(fund_foo_txid, find_vout_for_address(self.nodes[0], fund_foo_txid, node0_address_foo), {node1_address: 40})
+ txid2 = self.spend_txid(fund_bar_txid, find_vout_for_address(self.nodes[0], fund_bar_txid, node0_address_bar), {node1_address: 20})
# Have node0 mine a block:
if (self.options.mine_block):
diff --git a/test/get_previous_releases.py b/test/get_previous_releases.py
index e92bb402b5..62fcad04b3 100755
--- a/test/get_previous_releases.py
+++ b/test/get_previous_releases.py
@@ -190,6 +190,7 @@ def check_host(args) -> int:
'aarch64-*-linux*': 'aarch64-linux-gnu',
'x86_64-*-linux*': 'x86_64-linux-gnu',
'x86_64-apple-darwin*': 'osx64',
+ 'aarch64-apple-darwin*': 'osx64',
}
args.platform = ''
for pattern, target in platforms.items():
diff --git a/test/lint/README.md b/test/lint/README.md
index 7e06308347..c4d76eac94 100644
--- a/test/lint/README.md
+++ b/test/lint/README.md
@@ -27,10 +27,10 @@ Usage: test/lint/git-subtree-check.sh [-r] DIR [COMMIT]
To do a full check with `-r`, make sure that you have fetched the upstream repository branch in which the subtree is
maintained:
* for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master)
-* for `src/leveldb`: https://github.com/bitcoin-core/leveldb.git (branch bitcoin-fork)
-* for `src/univalue`: https://github.com/bitcoin-core/univalue.git (branch master)
+* for `src/leveldb`: https://github.com/bitcoin-core/leveldb-subtree.git (branch bitcoin-fork)
+* for `src/univalue`: https://github.com/bitcoin-core/univalue-subtree.git (branch master)
* for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master)
-* for `src/crc32c`: https://github.com/google/crc32c.git (branch master)
+* for `src/crc32c`: https://github.com/bitcoin-core/crc32c-subtree.git (branch bitcoin-fork)
To do so, add the upstream repository as remote:
diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh
index d6312270e7..3015c4f9b9 100755
--- a/test/lint/lint-locale-dependence.sh
+++ b/test/lint/lint-locale-dependence.sh
@@ -37,23 +37,18 @@ export LC_ALL=C
# See https://doc.qt.io/qt-5/qcoreapplication.html#locale-settings and
# https://stackoverflow.com/a/34878283 for more details.
+# TODO: Reduce KNOWN_VIOLATIONS by replacing uses of locale dependent stoul/strtol with locale
+# independent ToIntegral<T>(...).
+# TODO: Reduce KNOWN_VIOLATIONS by replacing uses of locale dependent snprintf with strprintf.
KNOWN_VIOLATIONS=(
"src/bitcoin-tx.cpp.*stoul"
"src/dbwrapper.cpp.*stoul"
"src/dbwrapper.cpp:.*vsnprintf"
- "src/node/blockstorage.cpp:.*atoi"
- "src/qt/rpcconsole.cpp:.*atoi"
"src/rest.cpp:.*strtol"
"src/test/dbwrapper_tests.cpp:.*snprintf"
"src/test/fuzz/locale.cpp"
- "src/test/fuzz/parse_numbers.cpp:.*atoi"
- "src/torcontrol.cpp:.*atoi"
+ "src/test/fuzz/string.cpp"
"src/torcontrol.cpp:.*strtol"
- "src/util/strencodings.cpp:.*atoi"
- "src/util/strencodings.cpp:.*strtol"
- "src/util/strencodings.cpp:.*strtoul"
- "src/util/strencodings.h:.*atoi"
- "src/util/system.cpp:.*atoi"
)
REGEXP_IGNORE_EXTERNAL_DEPENDENCIES="^src/(crypto/ctaes/|leveldb/|secp256k1/|tinyformat.h|univalue/)"
diff --git a/test/lint/lint-logs.sh b/test/lint/lint-logs.sh
index 2fbb4a38e7..d6c53e8ff3 100755
--- a/test/lint/lint-logs.sh
+++ b/test/lint/lint-logs.sh
@@ -7,7 +7,7 @@
# Check that all logs are terminated with '\n'
#
# Some logs are continued over multiple lines. They should be explicitly
-# commented with \* Continued *\
+# commented with /* Continued */
#
# There are some instances of LogPrintf() in comments. Those can be
# ignored
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index 63e7c57ddb..b52e105a33 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -5,8 +5,6 @@
# names can be used.
# See https://github.com/google/sanitizers/issues/1364
signed-integer-overflow:txmempool.cpp
-# nLastSuccess read from peers.dat might cause an overflow in IsTerrible
-signed-integer-overflow:addrman.cpp
# https://github.com/bitcoin/bitcoin/pull/21798#issuecomment-829180719
signed-integer-overflow:policy/feerate.cpp