aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/functional/data/invalid_txs.py7
-rw-r--r--test/functional/data/rpc_decodescript.json85
-rw-r--r--test/functional/data/rpc_psbt.json13
-rwxr-xr-xtest/functional/feature_anchors.py8
-rwxr-xr-xtest/functional/feature_assumevalid.py5
-rwxr-xr-xtest/functional/feature_bind_extra.py2
-rwxr-xr-xtest/functional/feature_bip68_sequence.py4
-rwxr-xr-xtest/functional/feature_block.py18
-rwxr-xr-xtest/functional/feature_blockfilterindex_prune.py25
-rwxr-xr-xtest/functional/feature_cltv.py17
-rwxr-xr-xtest/functional/feature_coinstatsindex.py12
-rwxr-xr-xtest/functional/feature_csv_activation.py7
-rwxr-xr-xtest/functional/feature_dersig.py9
-rwxr-xr-xtest/functional/feature_fee_estimation.py200
-rwxr-xr-xtest/functional/feature_init.py162
-rwxr-xr-xtest/functional/feature_maxuploadtarget.py2
-rwxr-xr-xtest/functional/feature_pruning.py22
-rwxr-xr-xtest/functional/feature_rbf.py17
-rwxr-xr-xtest/functional/feature_startupnotify.py41
-rwxr-xr-xtest/functional/feature_taproot.py46
-rwxr-xr-xtest/functional/feature_utxo_set_hash.py4
-rwxr-xr-xtest/functional/feature_versionbits_warning.py3
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py9
-rwxr-xr-xtest/functional/interface_rest.py31
-rwxr-xr-xtest/functional/interface_zmq.py9
-rwxr-xr-xtest/functional/mempool_accept.py81
-rwxr-xr-xtest/functional/mempool_packages.py25
-rwxr-xr-xtest/functional/mempool_reorg.py11
-rwxr-xr-xtest/functional/mempool_spend_coinbase.py2
-rwxr-xr-xtest/functional/mining_basic.py12
-rwxr-xr-xtest/functional/mocks/invalid_signer.py65
-rwxr-xr-xtest/functional/p2p_add_connections.py32
-rwxr-xr-xtest/functional/p2p_addr_relay.py37
-rwxr-xr-xtest/functional/p2p_blocksonly.py2
-rwxr-xr-xtest/functional/p2p_compactblocks.py14
-rwxr-xr-xtest/functional/p2p_disconnect_ban.py13
-rwxr-xr-xtest/functional/p2p_filter.py10
-rwxr-xr-xtest/functional/p2p_ibd_txrelay.py52
-rwxr-xr-xtest/functional/p2p_invalid_block.py38
-rwxr-xr-xtest/functional/p2p_segwit.py1
-rwxr-xr-xtest/functional/p2p_timeouts.py43
-rwxr-xr-xtest/functional/p2p_unrequested_blocks.py5
-rwxr-xr-xtest/functional/rpc_blockchain.py20
-rwxr-xr-xtest/functional/rpc_createmultisig.py16
-rwxr-xr-xtest/functional/rpc_decodescript.py13
-rwxr-xr-xtest/functional/rpc_dumptxoutset.py4
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py10
-rwxr-xr-xtest/functional/rpc_generate.py6
-rwxr-xr-xtest/functional/rpc_generateblock.py34
-rwxr-xr-xtest/functional/rpc_getblockfrompeer.py76
-rwxr-xr-xtest/functional/rpc_getblockstats.py8
-rwxr-xr-xtest/functional/rpc_getdescriptorinfo.py4
-rwxr-xr-xtest/functional/rpc_invalid_address_message.py99
-rwxr-xr-xtest/functional/rpc_mempool_entry_fee_fields_deprecation.py67
-rwxr-xr-xtest/functional/rpc_misc.py2
-rwxr-xr-xtest/functional/rpc_psbt.py8
-rwxr-xr-xtest/functional/rpc_scantxoutset.py156
-rw-r--r--test/functional/test_framework/blocktools.py7
-rwxr-xr-xtest/functional/test_framework/messages.py9
-rwxr-xr-xtest/functional/test_framework/p2p.py2
-rw-r--r--test/functional/test_framework/ripemd160.py130
-rw-r--r--test/functional/test_framework/script.py5
-rwxr-xr-xtest/functional/test_framework/test_framework.py10
-rwxr-xr-xtest/functional/test_framework/test_node.py72
-rw-r--r--test/functional/test_framework/util.py15
-rw-r--r--test/functional/test_framework/wallet.py55
-rwxr-xr-xtest/functional/test_runner.py79
-rwxr-xr-xtest/functional/tool_wallet.py13
-rwxr-xr-xtest/functional/wallet_address_types.py41
-rwxr-xr-xtest/functional/wallet_backup.py24
-rwxr-xr-xtest/functional/wallet_bumpfee.py6
-rwxr-xr-xtest/functional/wallet_createwallet.py2
-rwxr-xr-xtest/functional/wallet_descriptor.py6
-rwxr-xr-xtest/functional/wallet_groups.py11
-rwxr-xr-xtest/functional/wallet_importmulti.py5
-rwxr-xr-xtest/functional/wallet_keypool.py8
-rwxr-xr-xtest/functional/wallet_listdescriptors.py6
-rwxr-xr-xtest/functional/wallet_listreceivedby.py123
-rwxr-xr-xtest/functional/wallet_listtransactions.py72
-rwxr-xr-xtest/functional/wallet_multiwallet.py2
-rwxr-xr-xtest/functional/wallet_signer.py17
-rwxr-xr-xtest/functional/wallet_taproot.py24
-rwxr-xr-xtest/functional/wallet_transactiontime_rescan.py27
-rwxr-xr-xtest/lint/git-subtree-check.sh2
-rwxr-xr-xtest/lint/lint-circular-dependencies.sh2
-rwxr-xr-xtest/lint/lint-files.sh3
-rwxr-xr-xtest/lint/lint-git-commit-check.sh2
-rwxr-xr-xtest/lint/lint-include-guards.sh2
-rwxr-xr-xtest/lint/lint-locale-dependence.sh4
-rwxr-xr-xtest/lint/lint-shell-locale.sh2
-rwxr-xr-xtest/lint/lint-shell.sh5
-rw-r--r--test/sanitizer_suppressions/lsan3
-rw-r--r--test/sanitizer_suppressions/ubsan71
-rw-r--r--test/util/data/bitcoin-util-test.json23
-rw-r--r--test/util/data/txcreatesignsegwit1.hex1
95 files changed, 1861 insertions, 754 deletions
diff --git a/test/functional/data/invalid_txs.py b/test/functional/data/invalid_txs.py
index 33d6282961..3747b2a98d 100644
--- a/test/functional/data/invalid_txs.py
+++ b/test/functional/data/invalid_txs.py
@@ -28,6 +28,7 @@ from test_framework.messages import (
CTxIn,
CTxOut,
MAX_MONEY,
+ SEQUENCE_FINAL,
)
from test_framework.blocktools import create_tx_with_script, MAX_BLOCK_SIGOPS
from test_framework.script import (
@@ -77,7 +78,7 @@ class BadTxTemplate:
def __init__(self, *, spend_tx=None, spend_block=None):
self.spend_tx = spend_block.vtx[0] if spend_block else spend_tx
self.spend_avail = sum(o.nValue for o in self.spend_tx.vout)
- self.valid_txin = CTxIn(COutPoint(self.spend_tx.sha256, 0), b"", 0xffffffff)
+ self.valid_txin = CTxIn(COutPoint(self.spend_tx.sha256, 0), b"", SEQUENCE_FINAL)
@abc.abstractmethod
def get_tx(self, *args, **kwargs):
@@ -137,7 +138,7 @@ class BadInputOutpointIndex(BadTxTemplate):
bad_idx = num_indices + 100
tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256, bad_idx), b"", 0xffffffff))
+ tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256, bad_idx), b"", SEQUENCE_FINAL))
tx.vout.append(CTxOut(0, basic_p2sh))
tx.calc_sha256()
return tx
@@ -175,7 +176,7 @@ class NonexistentInput(BadTxTemplate):
def get_tx(self):
tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256 + 1, 0), b"", 0xffffffff))
+ tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256 + 1, 0), b"", SEQUENCE_FINAL))
tx.vin.append(self.valid_txin)
tx.vout.append(CTxOut(1, basic_p2sh))
tx.calc_sha256()
diff --git a/test/functional/data/rpc_decodescript.json b/test/functional/data/rpc_decodescript.json
new file mode 100644
index 0000000000..d1aa9ab00d
--- /dev/null
+++ b/test/functional/data/rpc_decodescript.json
@@ -0,0 +1,85 @@
+[
+ [
+ "5120eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
+ {
+ "asm": "1 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
+ "address": "bcrt1pamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhqz6nvlh",
+ "type": "witness_v1_taproot"
+ }
+ ],
+ [
+ "5102eeee",
+ {
+ "asm": "1 -28398",
+ "address": "bcrt1pamhqk96edn",
+ "type": "witness_unknown"
+ }
+ ],
+ [
+ "0020eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
+ {
+ "asm": "0 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
+ "address": "bcrt1qamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhqgdn98t",
+ "type": "witness_v0_scripthash",
+ "p2sh": "2MwGk8mw1GBP6U9D5X8gTvgvXpuknmAK3fo"
+ }
+ ],
+ [
+ "a914eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee87",
+ {
+ "asm": "OP_HASH160 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee OP_EQUAL",
+ "address": "2NF2b3KS8xXb9XHvbRMXdZh8s5g92rUZHtp",
+ "type": "scripthash"
+ }
+ ],
+ [
+ "6a00",
+ {
+ "asm": "OP_RETURN 0",
+ "type": "nulldata"
+ }
+ ],
+ [
+ "6aee",
+ {
+ "asm": "OP_RETURN OP_UNKNOWN",
+ "type": "nonstandard"
+ }
+ ],
+ [
+ "6a02ee",
+ {
+ "asm": "OP_RETURN [error]",
+ "type": "nonstandard"
+ }
+ ],
+ [
+ "02eeee",
+ {
+ "asm": "-28398",
+ "type": "nonstandard",
+ "p2sh": "2N34iiGoUUkVSPiaaTFpJjB1FR9TXQu3PGM",
+ "segwit": {
+ "asm": "0 96c2368fc30514a438a8bd909f93c49a1549d77198ccbdb792043b666cb24f42",
+ "hex": "002096c2368fc30514a438a8bd909f93c49a1549d77198ccbdb792043b666cb24f42",
+ "address": "bcrt1qjmprdr7rq522gw9ghkgfly7yng25n4m3nrxtmdujqsakvm9jfapqk795l5",
+ "type": "witness_v0_scripthash",
+ "p2sh-segwit": "2MtoejEictTQ6XtmHYzoYttt35Ec6krqFKN"
+ }
+ }
+ ],
+ [
+ "ba",
+ {
+ "asm": "OP_CHECKSIGADD",
+ "type": "nonstandard"
+ }
+ ],
+ [
+ "50",
+ {
+ "asm": "OP_RESERVED",
+ "type": "nonstandard"
+ }
+ ]
+]
diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json
index 0f6cd97fd8..8672400a92 100644
--- a/test/functional/data/rpc_psbt.json
+++ b/test/functional/data/rpc_psbt.json
@@ -19,6 +19,7 @@
"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",
@@ -34,7 +35,15 @@
"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",
- "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"
+ "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"
],
"creator" : [
{
@@ -136,4 +145,4 @@
"result" : "0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000"
}
]
-} \ No newline at end of file
+}
diff --git a/test/functional/feature_anchors.py b/test/functional/feature_anchors.py
index 01b6c5f9eb..713c0826d3 100755
--- a/test/functional/feature_anchors.py
+++ b/test/functional/feature_anchors.py
@@ -8,18 +8,12 @@ import os
from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
+from test_framework.util import check_node_connections
INBOUND_CONNECTIONS = 5
BLOCK_RELAY_CONNECTIONS = 2
-def check_node_connections(*, node, num_in, num_out):
- info = node.getnetworkinfo()
- assert_equal(info["connections_in"], num_in)
- assert_equal(info["connections_out"], num_out)
-
-
class AnchorsTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py
index 952401c94c..67cacaa9ce 100755
--- a/test/functional/feature_assumevalid.py
+++ b/test/functional/feature_assumevalid.py
@@ -122,10 +122,8 @@ class AssumeValidTest(BitcoinTestFramework):
tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE])))
tx.calc_sha256()
- block102 = create_block(self.tip, create_coinbase(height), self.block_time)
+ block102 = create_block(self.tip, create_coinbase(height), self.block_time, txlist=[tx])
self.block_time += 1
- block102.vtx.extend([tx])
- block102.hashMerkleRoot = block102.calc_merkle_root()
block102.solve()
self.blocks.append(block102)
self.tip = block102.sha256
@@ -135,7 +133,6 @@ class AssumeValidTest(BitcoinTestFramework):
# Bury the assumed valid block 2100 deep
for _ in range(2100):
block = create_block(self.tip, create_coinbase(height), self.block_time)
- block.nVersion = 4
block.solve()
self.blocks.append(block)
self.tip = block.sha256
diff --git a/test/functional/feature_bind_extra.py b/test/functional/feature_bind_extra.py
index af26f94033..6802da8d48 100755
--- a/test/functional/feature_bind_extra.py
+++ b/test/functional/feature_bind_extra.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""
diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py
index e9e8db7a16..05d274a9fe 100755
--- a/test/functional/feature_bip68_sequence.py
+++ b/test/functional/feature_bip68_sequence.py
@@ -388,9 +388,7 @@ class BIP68Test(BitcoinTestFramework):
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, tx3.serialize().hex())
# make a block that violates bip68; ensure that the tip updates
- block = create_block(tmpl=self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS))
- block.vtx.extend([tx1, tx2, tx3])
- block.hashMerkleRoot = block.calc_merkle_root()
+ block = create_block(tmpl=self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS), txlist=[tx1, tx2, tx3])
add_witness_commitment(block)
block.solve()
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index 883e15dda3..462deeae32 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -23,6 +23,7 @@ from test_framework.messages import (
CTxIn,
CTxOut,
MAX_BLOCK_WEIGHT,
+ SEQUENCE_FINAL,
uint256_from_compact,
uint256_from_str,
)
@@ -50,9 +51,13 @@ from test_framework.script_util import (
script_to_p2sh_script,
)
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
+from test_framework.util import (
+ assert_equal,
+ assert_greater_than,
+)
from data import invalid_txs
+
# Use this class for tests that require behavior other than normal p2p behavior.
# For now, it is used to serialize a bloated varint (b64).
class CBrokenBlock(CBlock):
@@ -801,7 +806,7 @@ class FullBlockTest(BitcoinTestFramework):
b58 = self.next_block(58, spend=out[17])
tx = CTransaction()
assert len(out[17].vout) < 42
- tx.vin.append(CTxIn(COutPoint(out[17].sha256, 42), CScript([OP_TRUE]), 0xffffffff))
+ tx.vin.append(CTxIn(COutPoint(out[17].sha256, 42), CScript([OP_TRUE]), SEQUENCE_FINAL))
tx.vout.append(CTxOut(0, b""))
tx.calc_sha256()
b58 = self.update_block(58, [tx])
@@ -876,7 +881,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.nLockTime = 0xffffffff # this locktime is non-final
tx.vin.append(CTxIn(COutPoint(out[18].sha256, 0))) # don't set nSequence
tx.vout.append(CTxOut(0, CScript([OP_TRUE])))
- assert tx.vin[0].nSequence < 0xffffffff
+ assert_greater_than(SEQUENCE_FINAL, tx.vin[0].nSequence)
tx.calc_sha256()
b62 = self.update_block(62, [tx])
self.send_blocks([b62], success=False, reject_reason='bad-txns-nonfinal', reconnect=True)
@@ -1024,7 +1029,7 @@ class FullBlockTest(BitcoinTestFramework):
bogus_tx = CTransaction()
bogus_tx.sha256 = uint256_from_str(b"23c70ed7c0506e9178fc1a987f40a33946d4ad4c962b5ae3a52546da53af0c5c")
tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", 0xffffffff))
+ tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", SEQUENCE_FINAL))
tx.vout.append(CTxOut(1, b""))
b70 = self.update_block(70, [tx])
self.send_blocks([b70], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
@@ -1361,11 +1366,10 @@ class FullBlockTest(BitcoinTestFramework):
else:
coinbase.vout[0].nValue += spend.vout[0].nValue - 1 # all but one satoshi to fees
coinbase.rehash()
- block = create_block(base_block_hash, coinbase, block_time, version=version)
tx = self.create_tx(spend, 0, 1, script) # spend 1 satoshi
self.sign_tx(tx, spend)
- self.add_transactions_to_block(block, [tx])
- block.hashMerkleRoot = block.calc_merkle_root()
+ tx.rehash()
+ block = create_block(base_block_hash, coinbase, block_time, version=version, txlist=[tx])
# Block is created. Find a valid nonce.
block.solve()
self.tip = block
diff --git a/test/functional/feature_blockfilterindex_prune.py b/test/functional/feature_blockfilterindex_prune.py
index 39eb700b4f..2451988135 100755
--- a/test/functional/feature_blockfilterindex_prune.py
+++ b/test/functional/feature_blockfilterindex_prune.py
@@ -24,13 +24,13 @@ class FeatureBlockfilterindexPruneTest(BitcoinTestFramework):
self.log.info("check if we can access a blockfilter when pruning is enabled but no blocks are actually pruned")
self.sync_index(height=200)
assert_greater_than(len(self.nodes[0].getblockfilter(self.nodes[0].getbestblockhash())['filter']), 0)
- # Mine two batches of blocks to avoid hitting NODE_NETWORK_LIMITED_MIN_BLOCKS disconnection
- self.generate(self.nodes[0], 250)
- self.generate(self.nodes[0], 250)
+ self.generate(self.nodes[0], 500)
self.sync_index(height=700)
self.log.info("prune some blocks")
pruneheight = self.nodes[0].pruneblockchain(400)
+ # the prune heights used here and below are magic numbers that are determined by the
+ # thresholds at which block files wrap, so they depend on disk serialization and default block file size.
assert_equal(pruneheight, 248)
self.log.info("check if we can access the tips blockfilter when we have pruned some blocks")
@@ -39,16 +39,29 @@ class FeatureBlockfilterindexPruneTest(BitcoinTestFramework):
self.log.info("check if we can access the blockfilter of a pruned block")
assert_greater_than(len(self.nodes[0].getblockfilter(self.nodes[0].getblockhash(2))['filter']), 0)
+ # mine and sync index up to a height that will later be the pruneheight
+ self.generate(self.nodes[0], 298)
+ self.sync_index(height=998)
+
self.log.info("start node without blockfilterindex")
self.restart_node(0, extra_args=["-fastprune", "-prune=1"])
self.log.info("make sure accessing the blockfilters throws an error")
assert_raises_rpc_error(-1, "Index is not enabled for filtertype basic", self.nodes[0].getblockfilter, self.nodes[0].getblockhash(2))
- self.generate(self.nodes[0], 1000)
+ self.generate(self.nodes[0], 502)
+
+ self.log.info("prune exactly up to the blockfilterindexes best block while blockfilters are disabled")
+ pruneheight_2 = self.nodes[0].pruneblockchain(1000)
+ assert_equal(pruneheight_2, 998)
+ self.restart_node(0, extra_args=["-fastprune", "-prune=1", "-blockfilterindex=1"])
+ self.log.info("make sure that we can continue with the partially synced index after having pruned up to the index height")
+ self.sync_index(height=1500)
self.log.info("prune below the blockfilterindexes best block while blockfilters are disabled")
- pruneheight_new = self.nodes[0].pruneblockchain(1000)
- assert_greater_than(pruneheight_new, pruneheight)
+ self.restart_node(0, extra_args=["-fastprune", "-prune=1"])
+ self.generate(self.nodes[0], 1000)
+ pruneheight_3 = self.nodes[0].pruneblockchain(2000)
+ assert_greater_than(pruneheight_3, pruneheight_2)
self.stop_node(0)
self.log.info("make sure we get an init error when starting the node again with block filters")
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index 1702debe17..7fd0d0140b 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -13,6 +13,7 @@ from test_framework.blocktools import (
)
from test_framework.messages import (
CTransaction,
+ SEQUENCE_FINAL,
msg_block,
)
from test_framework.p2p import P2PInterface
@@ -53,7 +54,7 @@ def cltv_invalidate(tx, failure_reason):
# 3) the lock-time type (height vs. timestamp) of the top stack item and the
# nLockTime field are not the same
# 4) the top stack item is greater than the transaction's nLockTime field
- # 5) the nSequence field of the txin is 0xffffffff
+ # 5) the nSequence field of the txin is 0xffffffff (SEQUENCE_FINAL)
assert failure_reason in range(5)
scheme = [
# | Script to prepend to scriptSig | nSequence | nLockTime |
@@ -62,7 +63,7 @@ def cltv_invalidate(tx, failure_reason):
[[OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP], None, None],
[[CScriptNum(100), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 1296688602], # timestamp of genesis block
[[CScriptNum(100), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0, 50],
- [[CScriptNum(50), OP_CHECKLOCKTIMEVERIFY, OP_DROP], 0xffffffff, 50],
+ [[CScriptNum(50), OP_CHECKLOCKTIMEVERIFY, OP_DROP], SEQUENCE_FINAL, 50],
][failure_reason]
cltv_modify_tx(tx, prepend_scriptsig=scheme[0], nsequence=scheme[1], nlocktime=scheme[2])
@@ -114,16 +115,13 @@ class BIP65Test(BitcoinTestFramework):
# create one invalid tx per CLTV failure reason (5 in total) and collect them
invalid_cltv_txs = []
for i in range(5):
- spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx']
+ spendtx = wallet.create_self_transfer()['tx']
cltv_invalidate(spendtx, i)
invalid_cltv_txs.append(spendtx)
tip = self.nodes[0].getbestblockhash()
block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
- block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time)
- block.nVersion = 3
- block.vtx.extend(invalid_cltv_txs)
- block.hashMerkleRoot = block.calc_merkle_root()
+ block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time, version=3, txlist=invalid_cltv_txs)
block.solve()
self.test_cltv_info(is_active=False) # Not active as of current tip and next block does not need to obey rules
@@ -134,8 +132,7 @@ class BIP65Test(BitcoinTestFramework):
self.log.info("Test that blocks must now be at least version 4")
tip = block.sha256
block_time += 1
- block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time)
- block.nVersion = 3
+ block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time, version=3)
block.solve()
with self.nodes[0].assert_debug_log(expected_msgs=[f'{block.hash}, bad-version(0x00000003)']):
@@ -149,7 +146,7 @@ class BIP65Test(BitcoinTestFramework):
# create and test one invalid tx per CLTV failure reason (5 in total)
for i in range(5):
- spendtx = wallet.create_self_transfer(from_node=self.nodes[0])['tx']
+ spendtx = wallet.create_self_transfer()['tx']
cltv_invalidate(spendtx, i)
expected_cltv_reject_reason = [
diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py
index 19bb908b64..c70f8a83db 100755
--- a/test/functional/feature_coinstatsindex.py
+++ b/test/functional/feature_coinstatsindex.py
@@ -40,7 +40,9 @@ class CoinStatsIndexTest(BitcoinTestFramework):
self.num_nodes = 2
self.supports_cli = False
self.extra_args = [
- [],
+ # Explicitly set the output type in order to have consistent tx vsize / fees
+ # for both legacy and descriptor wallets (disables the change address type detection algorithm)
+ ["-addresstype=bech32", "-changetype=bech32"],
["-coinstatsindex"]
]
@@ -276,14 +278,6 @@ class CoinStatsIndexTest(BitcoinTestFramework):
res3 = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=112)
assert_equal(res2, res3)
- self.log.info("Test that a node aware of stale blocks syncs them as well")
- node = self.nodes[0]
- # Ensure the node is aware of a stale block prior to restart
- node.getblock(reorg_block)
-
- self.restart_node(0, ["-coinstatsindex"])
- assert_raises_rpc_error(-32603, "Unable to get data because coinstatsindex is still syncing.", node.gettxoutsetinfo, 'muhash', reorg_block)
-
def _test_index_rejects_hash_serialized(self):
self.log.info("Test that the rpc raises if the legacy hash is passed with the index")
diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py
index 5f2ba35c71..6470c1c5eb 100755
--- a/test/functional/feature_csv_activation.py
+++ b/test/functional/feature_csv_activation.py
@@ -104,7 +104,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
def create_self_transfer_from_utxo(self, input_tx):
utxo = self.miniwallet.get_utxo(txid=input_tx.rehash(), mark_as_spent=False)
- tx = self.miniwallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo)['tx']
+ tx = self.miniwallet.create_self_transfer(utxo_to_spend=utxo)['tx']
return tx
def create_bip112special(self, input, txversion):
@@ -173,10 +173,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
return test_blocks
def create_test_block(self, txs):
- block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600)
- block.nVersion = 4
- block.vtx.extend(txs)
- block.hashMerkleRoot = block.calc_merkle_root()
+ block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600, txlist=txs)
block.solve()
return block
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index 8a71bf480e..f35ce7e0c9 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -57,7 +57,7 @@ class BIP66Test(BitcoinTestFramework):
def create_tx(self, input_txid):
utxo_to_spend = self.miniwallet.get_utxo(txid=input_txid, mark_as_spent=False)
- return self.miniwallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_to_spend)['tx']
+ return self.miniwallet.create_self_transfer(utxo_to_spend=utxo_to_spend)['tx']
def test_dersig_info(self, *, is_active):
assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip66'],
@@ -85,9 +85,7 @@ 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.vtx.append(spendtx)
- block.hashMerkleRoot = block.calc_merkle_root()
+ block = create_block(int(tip, 16), create_coinbase(DERSIG_HEIGHT - 1), block_time, txlist=[spendtx])
block.solve()
assert_equal(self.nodes[0].getblockcount(), DERSIG_HEIGHT - 2)
@@ -100,8 +98,7 @@ class BIP66Test(BitcoinTestFramework):
self.log.info("Test that blocks must now be at least version 3")
tip = block.sha256
block_time += 1
- block = create_block(tip, create_coinbase(DERSIG_HEIGHT), block_time)
- block.nVersion = 2
+ block = create_block(tip, create_coinbase(DERSIG_HEIGHT), block_time, version=2)
block.solve()
with self.nodes[0].assert_debug_log(expected_msgs=[f'{block.hash}, bad-version(0x00000002)']):
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py
index 46d5bcf1a6..233ffd60da 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -17,7 +17,6 @@ from test_framework.messages import (
from test_framework.script import (
CScript,
OP_1,
- OP_2,
OP_DROP,
OP_TRUE,
)
@@ -36,16 +35,14 @@ from test_framework.util import (
# Construct 2 trivial P2SH's and the ScriptSigs that spend them
# So we can create many transactions without needing to spend
# time signing.
-REDEEM_SCRIPT_1 = CScript([OP_1, OP_DROP])
-REDEEM_SCRIPT_2 = CScript([OP_2, OP_DROP])
-P2SH_1 = script_to_p2sh_script(REDEEM_SCRIPT_1)
-P2SH_2 = script_to_p2sh_script(REDEEM_SCRIPT_2)
+SCRIPT = CScript([OP_1, OP_DROP])
+P2SH = script_to_p2sh_script(SCRIPT)
+REDEEM_SCRIPT = CScript([OP_TRUE, SCRIPT])
-# Associated ScriptSig's to spend satisfy P2SH_1 and P2SH_2
-SCRIPT_SIG = [CScript([OP_TRUE, REDEEM_SCRIPT_1]), CScript([OP_TRUE, REDEEM_SCRIPT_2])]
-
-def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee_increment):
+def small_txpuzzle_randfee(
+ from_node, conflist, unconflist, amount, min_fee, fee_increment
+):
"""Create and send a transaction with a random fee.
The transaction pays to a trivial P2SH script, and assumes that its inputs
@@ -66,20 +63,15 @@ def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee
while total_in <= (amount + fee) and len(conflist) > 0:
t = conflist.pop(0)
total_in += t["amount"]
- tx.vin.append(CTxIn(COutPoint(int(t["txid"], 16), t["vout"]), b""))
+ tx.vin.append(CTxIn(COutPoint(int(t["txid"], 16), t["vout"]), REDEEM_SCRIPT))
+ while total_in <= (amount + fee) and len(unconflist) > 0:
+ t = unconflist.pop(0)
+ total_in += t["amount"]
+ tx.vin.append(CTxIn(COutPoint(int(t["txid"], 16), t["vout"]), REDEEM_SCRIPT))
if total_in <= amount + fee:
- while total_in <= (amount + fee) and len(unconflist) > 0:
- t = unconflist.pop(0)
- total_in += t["amount"]
- tx.vin.append(CTxIn(COutPoint(int(t["txid"], 16), t["vout"]), b""))
- if total_in <= amount + fee:
- raise RuntimeError(f"Insufficient funds: need {amount + fee}, have {total_in}")
- tx.vout.append(CTxOut(int((total_in - amount - fee) * COIN), P2SH_1))
- tx.vout.append(CTxOut(int(amount * COIN), P2SH_2))
- # These transactions don't need to be signed, but we still have to insert
- # the ScriptSig that will satisfy the ScriptPubKey.
- for inp in tx.vin:
- inp.scriptSig = SCRIPT_SIG[inp.prevout.n]
+ raise RuntimeError(f"Insufficient funds: need {amount + fee}, have {total_in}")
+ tx.vout.append(CTxOut(int((total_in - amount - fee) * COIN), P2SH))
+ tx.vout.append(CTxOut(int(amount * COIN), P2SH))
txid = from_node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
unconflist.append({"txid": txid, "vout": 0, "amount": total_in - amount - fee})
unconflist.append({"txid": txid, "vout": 1, "amount": amount})
@@ -87,34 +79,6 @@ def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee
return (tx.serialize().hex(), fee)
-def split_inputs(from_node, txins, txouts, initial_split=False):
- """Generate a lot of inputs so we can generate a ton of transactions.
-
- This function takes an input from txins, and creates and sends a transaction
- which splits the value into 2 outputs which are appended to txouts.
- Previously this was designed to be small inputs so they wouldn't have
- a high coin age when the notion of priority still existed."""
-
- prevtxout = txins.pop()
- tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(int(prevtxout["txid"], 16), prevtxout["vout"]), b""))
-
- half_change = satoshi_round(prevtxout["amount"] / 2)
- rem_change = prevtxout["amount"] - half_change - Decimal("0.00001000")
- tx.vout.append(CTxOut(int(half_change * COIN), P2SH_1))
- tx.vout.append(CTxOut(int(rem_change * COIN), P2SH_2))
-
- # If this is the initial split we actually need to sign the transaction
- # Otherwise we just need to insert the proper ScriptSig
- if (initial_split):
- completetx = from_node.signrawtransactionwithwallet(tx.serialize().hex())["hex"]
- else:
- tx.vin[0].scriptSig = SCRIPT_SIG[prevtxout["vout"]]
- completetx = tx.serialize().hex()
- txid = from_node.sendrawtransaction(hexstring=completetx, maxfeerate=0)
- txouts.append({"txid": txid, "vout": 0, "amount": half_change})
- txouts.append({"txid": txid, "vout": 1, "amount": rem_change})
-
def check_raw_estimates(node, fees_seen):
"""Call estimaterawfee and verify that the estimates meet certain invariants."""
@@ -125,7 +89,10 @@ def check_raw_estimates(node, fees_seen):
assert_greater_than(feerate, 0)
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)})")
+ raise AssertionError(
+ f"Estimated fee ({feerate}) out of range ({min(fees_seen)},{max(fees_seen)})"
+ )
+
def check_smart_estimates(node, fees_seen):
"""Call estimatesmartfee and verify that the estimates meet certain invariants."""
@@ -133,8 +100,8 @@ 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']
+ 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)
@@ -142,9 +109,13 @@ def check_smart_estimates(node, fees_seen):
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)})")
+ raise AssertionError(
+ f"Estimated fee ({feerate}) out of range ({min(fees_seen)},{max(fees_seen)})"
+ )
if feerate - delta > last_feerate:
- raise AssertionError(f"Estimated fee ({feerate}) larger than last fee ({last_feerate}) for lower number of confirms")
+ raise AssertionError(
+ f"Estimated fee ({feerate}) larger than last fee ({last_feerate}) for lower number of confirms"
+ )
last_feerate = feerate
if i == 0:
@@ -152,6 +123,7 @@ def check_smart_estimates(node, fees_seen):
else:
assert_greater_than_or_equal(i + 1, e["blocks"])
+
def check_estimates(node, fees_seen):
check_raw_estimates(node, fees_seen)
check_smart_estimates(node, fees_seen)
@@ -159,27 +131,25 @@ def check_estimates(node, fees_seen):
def send_tx(node, utxo, feerate):
"""Broadcast a 1in-1out transaction with a specific input and feerate (sat/vb)."""
- overhead, op, scriptsig, nseq, value, spk = 10, 36, 5, 4, 8, 24
- tx_size = overhead + op + scriptsig + nseq + value + spk
- fee = tx_size * feerate
-
tx = CTransaction()
- tx.vin = [CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), SCRIPT_SIG[utxo["vout"]])]
- tx.vout = [CTxOut(int(utxo["amount"] * COIN) - fee, P2SH_1)]
- txid = node.sendrawtransaction(tx.serialize().hex())
+ tx.vin = [CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), REDEEM_SCRIPT)]
+ tx.vout = [CTxOut(int(utxo["amount"] * COIN), P2SH)]
+
+ # vbytes == bytes as we are using legacy transactions
+ fee = tx.get_vsize() * feerate
+ tx.vout[0].nValue -= fee
- return txid
+ return node.sendrawtransaction(tx.serialize().hex())
class EstimateFeeTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 3
- # mine non-standard txs (e.g. txs with "dust" outputs)
# Force fSendTrickle to true (via whitelist.noban)
self.extra_args = [
- ["-acceptnonstdtxn", "-whitelist=noban@127.0.0.1"],
- ["-acceptnonstdtxn", "-whitelist=noban@127.0.0.1", "-blockmaxweight=68000"],
- ["-acceptnonstdtxn", "-whitelist=noban@127.0.0.1", "-blockmaxweight=32000"],
+ ["-whitelist=noban@127.0.0.1"],
+ ["-whitelist=noban@127.0.0.1", "-blockmaxweight=68000"],
+ ["-whitelist=noban@127.0.0.1", "-blockmaxweight=32000"],
]
def skip_test_if_missing_module(self):
@@ -212,11 +182,17 @@ class EstimateFeeTest(BitcoinTestFramework):
random.shuffle(self.confutxo)
for _ in range(random.randrange(100 - 50, 100 + 50)):
from_index = random.randint(1, 2)
- (txhex, fee) = small_txpuzzle_randfee(self.nodes[from_index], self.confutxo,
- self.memutxo, Decimal("0.005"), min_fee, min_fee)
+ (txhex, fee) = small_txpuzzle_randfee(
+ self.nodes[from_index],
+ self.confutxo,
+ self.memutxo,
+ Decimal("0.005"),
+ min_fee,
+ min_fee,
+ )
tx_kbytes = (len(txhex) // 2) / 1000.0
self.fees_per_kb.append(float(fee) / tx_kbytes)
- self.sync_mempools(wait=.1)
+ self.sync_mempools(wait=0.1)
mined = mining_node.getblock(self.generate(mining_node, 1)[0], True)["tx"]
# update which txouts are confirmed
newmem = []
@@ -229,46 +205,45 @@ class EstimateFeeTest(BitcoinTestFramework):
def initial_split(self, node):
"""Split two coinbase UTxOs into many small coins"""
- self.txouts = []
- self.txouts2 = []
- # Split a coinbase into two transaction puzzle outputs
- split_inputs(node, node.listunspent(0), self.txouts, True)
-
- # Mine
+ utxo_count = 2048
+ self.confutxo = []
+ splitted_amount = Decimal("0.04")
+ fee = Decimal("0.1")
+ change = Decimal("100") - splitted_amount * utxo_count - fee
+ tx = CTransaction()
+ tx.vin = [
+ CTxIn(COutPoint(int(cb["txid"], 16), cb["vout"]))
+ for cb in node.listunspent()[:2]
+ ]
+ tx.vout = [CTxOut(int(splitted_amount * COIN), P2SH) for _ in range(utxo_count)]
+ tx.vout.append(CTxOut(int(change * COIN), P2SH))
+ txhex = node.signrawtransactionwithwallet(tx.serialize().hex())["hex"]
+ txid = node.sendrawtransaction(txhex)
+ self.confutxo = [
+ {"txid": txid, "vout": i, "amount": splitted_amount}
+ for i in range(utxo_count)
+ ]
while len(node.getrawmempool()) > 0:
self.generate(node, 1, sync_fun=self.no_op)
- # Repeatedly split those 2 outputs, doubling twice for each rep
- # Use txouts to monitor the available utxo, since these won't be tracked in wallet
- reps = 0
- while reps < 5:
- # Double txouts to txouts2
- while len(self.txouts) > 0:
- split_inputs(node, self.txouts, self.txouts2)
- while len(node.getrawmempool()) > 0:
- self.generate(node, 1, sync_fun=self.no_op)
- # Double txouts2 to txouts
- while len(self.txouts2) > 0:
- split_inputs(node, self.txouts2, self.txouts)
- while len(node.getrawmempool()) > 0:
- self.generate(node, 1, sync_fun=self.no_op)
- reps += 1
-
def sanity_check_estimates_range(self):
"""Populate estimation buckets, assert estimates are in a sane range and
are strictly increasing as the target decreases."""
self.fees_per_kb = []
self.memutxo = []
- self.confutxo = self.txouts # Start with the set of confirmed txouts after splitting
self.log.info("Will output estimates for 1/2/3/6/15/25 blocks")
for _ in range(2):
- self.log.info("Creating transactions and mining them with a block size that can't keep up")
+ self.log.info(
+ "Creating transactions and mining them with a block size that can't keep up"
+ )
# Create transactions and mine 10 small blocks with node 2, but create txs faster than we can mine
self.transact_and_mine(10, self.nodes[2])
check_estimates(self.nodes[1], self.fees_per_kb)
- self.log.info("Creating transactions and mining them at a block size that is just big enough")
+ self.log.info(
+ "Creating transactions and mining them at a block size that is just big enough"
+ )
# Generate transactions while mining 10 more blocks, this time with node1
# which mines blocks with capacity just above the rate that transactions are being created
self.transact_and_mine(10, self.nodes[1])
@@ -277,12 +252,13 @@ class EstimateFeeTest(BitcoinTestFramework):
# Finish by mining a normal-sized block:
while len(self.nodes[1].getrawmempool()) > 0:
self.generate(self.nodes[1], 1)
+
self.log.info("Final estimates after emptying mempools")
check_estimates(self.nodes[1], self.fees_per_kb)
def test_feerate_mempoolminfee(self):
- high_val = 3*self.nodes[1].estimatesmartfee(1)['feerate']
- self.restart_node(1, extra_args=[f'-minrelaytxfee={high_val}'])
+ 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.restart_node(1)
@@ -303,7 +279,7 @@ class EstimateFeeTest(BitcoinTestFramework):
utxos_to_respend = []
txids_to_replace = []
- assert len(utxos) >= 250
+ assert_greater_than_or_equal(len(utxos), 250)
for _ in range(5):
# Broadcast 45 low fee transactions that will need to be RBF'd
for _ in range(45):
@@ -315,27 +291,24 @@ class EstimateFeeTest(BitcoinTestFramework):
for _ in range(5):
send_tx(node, utxos.pop(0), low_feerate)
# Mine the transactions on another node
- self.sync_mempools(wait=.1, nodes=[node, miner])
+ self.sync_mempools(wait=0.1, nodes=[node, miner])
for txid in txids_to_replace:
miner.prioritisetransaction(txid=txid, fee_delta=-COIN)
self.generate(miner, 1)
# RBF the low-fee transactions
- while True:
- try:
- u = utxos_to_respend.pop(0)
- send_tx(node, u, high_feerate)
- except IndexError:
- break
+ while len(utxos_to_respend) > 0:
+ u = utxos_to_respend.pop(0)
+ send_tx(node, u, high_feerate)
# Mine the last replacement txs
- self.sync_mempools(wait=.1, nodes=[node, miner])
+ self.sync_mempools(wait=0.1, nodes=[node, miner])
self.generate(miner, 1)
# Only 10% of the transactions were really confirmed with a low feerate,
# the rest needed to be RBF'd. We must return the 90% conf rate feerate.
- high_feerate_kvb = Decimal(high_feerate) / COIN * 10**3
+ high_feerate_kvb = Decimal(high_feerate) / COIN * 10 ** 3
est_feerate = node.estimatesmartfee(2)["feerate"]
- assert est_feerate == high_feerate_kvb
+ assert_equal(est_feerate, high_feerate_kvb)
def run_test(self):
self.log.info("This test is time consuming, please be patient")
@@ -359,7 +332,9 @@ class EstimateFeeTest(BitcoinTestFramework):
self.sanity_check_estimates_range()
# 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")
+ self.log.info(
+ "Test fee rate estimation after restarting node with high MempoolMinFee"
+ )
self.test_feerate_mempoolminfee()
self.log.info("Restarting node with fresh estimation")
@@ -375,9 +350,10 @@ class EstimateFeeTest(BitcoinTestFramework):
self.log.info("Testing that fee estimation is disabled in blocksonly.")
self.restart_node(0, ["-blocksonly"])
- assert_raises_rpc_error(-32603, "Fee estimation disabled",
- self.nodes[0].estimatesmartfee, 2)
+ assert_raises_rpc_error(
+ -32603, "Fee estimation disabled", self.nodes[0].estimatesmartfee, 2
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
EstimateFeeTest().main()
diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py
new file mode 100755
index 0000000000..4b56b0c26b
--- /dev/null
+++ b/test/functional/feature_init.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Stress tests related to node initialization."""
+import random
+import time
+import os
+from pathlib import Path
+
+from test_framework.test_framework import BitcoinTestFramework, SkipTest
+from test_framework.test_node import ErrorMatch
+from test_framework.util import assert_equal
+
+
+class InitStressTest(BitcoinTestFramework):
+ """
+ Ensure that initialization can be interrupted at a number of points and not impair
+ subsequent starts.
+ """
+
+ def set_test_params(self):
+ self.setup_clean_chain = False
+ self.num_nodes = 1
+
+ def run_test(self):
+ """
+ - test terminating initialization after seeing a certain log line.
+ - test terminating init after seeing a random number of log lines.
+ - test removing certain essential files to test startup error paths.
+ """
+ # TODO: skip Windows for now since it isn't clear how to SIGTERM.
+ #
+ # Windows doesn't support `process.terminate()`.
+ # and other approaches (like below) don't work:
+ #
+ # os.kill(node.process.pid, signal.CTRL_C_EVENT)
+ if os.name == 'nt':
+ raise SkipTest("can't SIGTERM on Windows")
+
+ self.stop_node(0)
+ node = self.nodes[0]
+
+ def sigterm_node():
+ node.process.terminate()
+ node.process.wait()
+
+ def check_clean_start():
+ """Ensure that node restarts successfully after various interrupts."""
+ node.start()
+ node.wait_for_rpc_connection()
+ assert_equal(200, node.getblockcount())
+
+ lines_to_terminate_after = [
+ 'Validating signatures for all blocks',
+ 'scheduler thread start',
+ 'Starting HTTP server',
+ 'Loading P2P addresses',
+ 'Loading banlist',
+ 'Loading block index',
+ 'Switching active chainstate',
+ 'Checking all blk files are present',
+ 'Loaded best chain:',
+ 'init message: Verifying blocks',
+ 'init message: Starting network threads',
+ 'net thread start',
+ 'addcon thread start',
+ 'loadblk thread start',
+ 'txindex thread start',
+ 'msghand thread start',
+ 'net thread start',
+ 'addcon thread start',
+ ]
+ if self.is_wallet_compiled():
+ lines_to_terminate_after.append('Verifying wallet')
+
+ for terminate_line in lines_to_terminate_after:
+ self.log.info(f"Starting node and will exit after line '{terminate_line}'")
+ node.start(extra_args=['-txindex=1'])
+
+ num_total_logs = node.wait_for_debug_log([terminate_line], ignore_case=True)
+ self.log.debug(f"Terminating node after {num_total_logs} log lines seen")
+ sigterm_node()
+
+ check_clean_start()
+ self.stop_node(0)
+
+ self.log.info(
+ f"Terminate at some random point in the init process (max logs: {num_total_logs})")
+
+ for _ in range(40):
+ num_logs = len(Path(node.debug_log_path).read_text().splitlines())
+ additional_lines = random.randint(1, num_total_logs)
+ self.log.debug(f"Starting node and will exit after {additional_lines} lines")
+ node.start(extra_args=['-txindex=1'])
+ logfile = open(node.debug_log_path, 'rb')
+
+ MAX_SECS_TO_WAIT = 10
+ start = time.time()
+ num_lines = 0
+
+ while True:
+ line = logfile.readline()
+ if line:
+ num_lines += 1
+
+ if num_lines >= (num_logs + additional_lines) or \
+ (time.time() - start) > MAX_SECS_TO_WAIT:
+ self.log.debug(f"Terminating node after {num_lines} log lines seen")
+ sigterm_node()
+ break
+
+ if node.process.poll() is not None:
+ raise AssertionError("node failed to start")
+
+ check_clean_start()
+ self.stop_node(0)
+
+ self.log.info("Test startup errors after removing certain essential files")
+
+ files_to_disturb = {
+ 'blocks/index/*.ldb': 'Error opening block database.',
+ 'chainstate/*.ldb': 'Error opening block database.',
+ 'blocks/blk*.dat': 'Error loading block database.',
+ }
+
+ for file_patt, err_fragment in files_to_disturb.items():
+ target_files = list(node.chain_path.glob(file_patt))
+
+ for target_file in target_files:
+ self.log.info(f"Tweaking file to ensure failure {target_file}")
+ bak_path = str(target_file) + ".bak"
+ target_file.rename(bak_path)
+
+ # TODO: at some point, we should test perturbing the files instead of removing
+ # them, e.g.
+ #
+ # contents = target_file.read_bytes()
+ # tweaked_contents = bytearray(contents)
+ # tweaked_contents[50:250] = b'1' * 200
+ # target_file.write_bytes(bytes(tweaked_contents))
+ #
+ # At the moment I can't get this to work (bitcoind loads successfully?) so
+ # investigate doing this later.
+
+ node.assert_start_raises_init_error(
+ extra_args=['-txindex=1'],
+ expected_msg=err_fragment,
+ match=ErrorMatch.PARTIAL_REGEX,
+ )
+
+ for target_file in target_files:
+ bak_path = str(target_file) + ".bak"
+ self.log.debug(f"Restoring file from {bak_path} and restarting")
+ Path(bak_path).rename(target_file)
+
+ check_clean_start()
+ self.stop_node(0)
+
+
+if __name__ == '__main__':
+ InitStressTest().main()
diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py
index b4e0df8a11..24f79dda67 100755
--- a/test/functional/feature_maxuploadtarget.py
+++ b/test/functional/feature_maxuploadtarget.py
@@ -36,7 +36,7 @@ class MaxUploadTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [[
- "-maxuploadtarget=800",
+ "-maxuploadtarget=800M",
"-acceptnonstdtxn=1",
]]
self.supports_cli = False
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index 0edf1d66c8..ba3c5053cb 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -96,9 +96,6 @@ class PruneTest(BitcoinTestFramework):
]
self.rpc_timeout = 120
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def setup_network(self):
self.setup_nodes()
@@ -114,7 +111,8 @@ class PruneTest(BitcoinTestFramework):
def setup_nodes(self):
self.add_nodes(self.num_nodes, self.extra_args)
self.start_nodes()
- self.import_deterministic_coinbase_privkeys()
+ if self.is_wallet_compiled():
+ self.import_deterministic_coinbase_privkeys()
def create_big_chain(self):
# Start by creating some coinbases we can spend later
@@ -277,7 +275,7 @@ class PruneTest(BitcoinTestFramework):
self.start_node(node_number)
node = self.nodes[node_number]
assert_equal(node.getblockcount(), 995)
- assert_raises_rpc_error(-1, "not in prune mode", node.pruneblockchain, 500)
+ assert_raises_rpc_error(-1, "Cannot prune blocks because node is not in prune mode", node.pruneblockchain, 500)
# now re-start in manual pruning mode
self.restart_node(node_number, extra_args=["-prune=1"])
@@ -308,11 +306,18 @@ class PruneTest(BitcoinTestFramework):
self.generate(node, 6, sync_fun=self.no_op)
assert_equal(node.getblockchaininfo()["blocks"], 1001)
+ # prune parameter in the future (block or timestamp) should raise an exception
+ future_parameter = height(1001) + 5
+ if use_timestamp:
+ assert_raises_rpc_error(-8, "Could not find block with at least the specified timestamp", node.pruneblockchain, future_parameter)
+ else:
+ assert_raises_rpc_error(-8, "Blockchain is shorter than the attempted prune height", node.pruneblockchain, future_parameter)
+
# Pruned block should still know the number of transactions
assert_equal(node.getblockheader(node.getblockhash(1))["nTx"], block1_details["nTx"])
# negative heights should raise an exception
- assert_raises_rpc_error(-8, "Negative", node.pruneblockchain, -10)
+ assert_raises_rpc_error(-8, "Negative block height", node.pruneblockchain, -10)
# height=100 too low to prune first block file so this is a no-op
prune(100)
@@ -467,8 +472,9 @@ class PruneTest(BitcoinTestFramework):
self.log.info("Test manual pruning with timestamps")
self.manual_test(4, use_timestamp=True)
- self.log.info("Test wallet re-scan")
- self.wallet_test()
+ if self.is_wallet_compiled():
+ self.log.info("Test wallet re-scan")
+ self.wallet_test()
self.log.info("Test invalid pruning command line options")
self.test_invalid_command_line_options()
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index e540cc1574..f0ed914461 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -14,6 +14,7 @@ from test_framework.messages import (
CTransaction,
CTxIn,
CTxOut,
+ SEQUENCE_FINAL,
)
from test_framework.script import CScript, OP_DROP
from test_framework.test_framework import BitcoinTestFramework
@@ -114,7 +115,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
"""Simple doublespend"""
# we use MiniWallet to create a transaction template with inputs correctly set,
# and modify the output (amount, scriptPubKey) according to our needs
- tx_template = self.wallet.create_self_transfer(from_node=self.nodes[0])['tx']
+ tx_template = self.wallet.create_self_transfer()['tx']
tx1a = deepcopy(tx_template)
tx1a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
@@ -402,7 +403,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
# Create a non-opting in transaction
tx1a = CTransaction()
- tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0xffffffff)]
+ tx1a.vin = [CTxIn(tx0_outpoint, nSequence=SEQUENCE_FINAL)]
tx1a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
tx1a_hex = tx1a.serialize().hex()
tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)
@@ -445,7 +446,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2a_txid = int(tx2a_txid, 16)
tx3a = CTransaction()
- tx3a.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0xffffffff),
+ tx3a.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=SEQUENCE_FINAL),
CTxIn(COutPoint(tx2a_txid, 0), nSequence=0xfffffffd)]
tx3a.vout = [CTxOut(int(0.9 * COIN), CScript([b'c'])), CTxOut(int(0.9 * COIN), CScript([b'd']))]
tx3a_hex = tx3a.serialize().hex()
@@ -538,7 +539,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert_equal(json0["vin"][0]["sequence"], 4294967293)
assert_equal(json1["vin"][0]["sequence"], 4294967295)
- if self.is_wallet_compiled():
+ if self.is_specified_wallet_compiled():
self.init_wallet(node=0)
rawtx2 = self.nodes[0].createrawtransaction([], outs)
frawtx2a = self.nodes[0].fundrawtransaction(rawtx2, {"replaceable": True})
@@ -562,7 +563,6 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert_equal(True, self.nodes[0].getmempoolentry(optin_parent_tx['txid'])['bip125-replaceable'])
replacement_parent_tx = self.wallet.create_self_transfer(
- from_node=self.nodes[0],
utxo_to_spend=confirmed_utxo,
sequence=BIP125_SEQUENCE_NUMBER,
fee_rate=Decimal('0.02'),
@@ -579,7 +579,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
optout_child_tx = self.wallet.send_self_transfer(
from_node=self.nodes[0],
utxo_to_spend=parent_utxo,
- sequence=0xffffffff,
+ sequence=SEQUENCE_FINAL,
fee_rate=Decimal('0.01'),
)
@@ -587,9 +587,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert_equal(True, self.nodes[0].getmempoolentry(optout_child_tx['txid'])['bip125-replaceable'])
replacement_child_tx = self.wallet.create_self_transfer(
- from_node=self.nodes[0],
utxo_to_spend=parent_utxo,
- sequence=0xffffffff,
+ sequence=SEQUENCE_FINAL,
fee_rate=Decimal('0.02'),
mempool_valid=False,
)
@@ -608,7 +607,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
replacement_parent_tx = self.wallet.send_self_transfer(
from_node=self.nodes[0],
utxo_to_spend=confirmed_utxo,
- sequence=0xffffffff,
+ sequence=SEQUENCE_FINAL,
fee_rate=Decimal('0.03'),
)
# Check that child is removed and update wallet utxo state
diff --git a/test/functional/feature_startupnotify.py b/test/functional/feature_startupnotify.py
new file mode 100755
index 0000000000..c6aa837768
--- /dev/null
+++ b/test/functional/feature_startupnotify.py
@@ -0,0 +1,41 @@
+#!/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 -startupnotify."""
+
+import os
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+)
+
+NODE_DIR = "node0"
+FILE_NAME = "test.txt"
+
+
+class StartupNotifyTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.disable_syscall_sandbox = True
+
+ def run_test(self):
+ tmpdir_file = os.path.join(self.options.tmpdir, NODE_DIR, FILE_NAME)
+ assert not os.path.exists(tmpdir_file)
+
+ self.log.info("Test -startupnotify command is run when node starts")
+ self.restart_node(0, extra_args=[f"-startupnotify=echo '{FILE_NAME}' >> {NODE_DIR}/{FILE_NAME}"])
+ self.wait_until(lambda: os.path.exists(tmpdir_file))
+
+ self.log.info("Test -startupnotify is executed once")
+ with open(tmpdir_file, "r", encoding="utf8") as f:
+ file_content = f.read()
+ assert_equal(file_content.count(FILE_NAME), 1)
+
+ self.log.info("Test node is fully started")
+ assert_equal(self.nodes[0].getblockcount(), 200)
+
+
+if __name__ == '__main__':
+ StartupNotifyTest().main()
diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py
index 9f00240a47..3e3d4b3c77 100755
--- a/test/functional/feature_taproot.py
+++ b/test/functional/feature_taproot.py
@@ -19,6 +19,7 @@ from test_framework.messages import (
CTxIn,
CTxInWitness,
CTxOut,
+ SEQUENCE_FINAL,
)
from test_framework.script import (
ANNEX_TAG,
@@ -98,6 +99,7 @@ from test_framework.address import (
program_to_witness
)
from collections import OrderedDict, namedtuple
+from enum import Enum
from io import BytesIO
import json
import hashlib
@@ -456,7 +458,7 @@ def spend(tx, idx, utxos, **kwargs):
# Each spender is a tuple of:
# - A scriptPubKey which is to be spent from (CScript)
# - A comment describing the test (string)
-# - Whether the spending (on itself) is expected to be standard (bool)
+# - Whether the spending (on itself) is expected to be standard (Enum.Standard)
# - A tx-signing lambda returning (scriptsig, witness_stack), taking as inputs:
# - A transaction to sign (CTransaction)
# - An input position (int)
@@ -468,8 +470,14 @@ def spend(tx, idx, utxos, **kwargs):
# - Whether this test demands being placed in a txin with no corresponding txout (for testing SIGHASH_SINGLE behavior)
Spender = namedtuple("Spender", "script,comment,is_standard,sat_function,err_msg,sigops_weight,no_fail,need_vin_vout_mismatch")
+# The full node versions that treat the tx standard.
+# ALL means any version
+# V23 means the major version 23.0 and any later version
+# NONE means no version
+Standard = Enum('Standard', 'ALL V23 NONE')
-def make_spender(comment, *, tap=None, witv0=False, script=None, pkh=None, p2sh=False, spk_mutate_pre_p2sh=None, failure=None, standard=True, err_msg=None, sigops_weight=0, need_vin_vout_mismatch=False, **kwargs):
+
+def make_spender(comment, *, tap=None, witv0=False, script=None, pkh=None, p2sh=False, spk_mutate_pre_p2sh=None, failure=None, standard=Standard.ALL, err_msg=None, sigops_weight=0, need_vin_vout_mismatch=False, **kwargs):
"""Helper for constructing Spender objects using the context signing framework.
* tap: a TaprootInfo object (see taproot_construct), for Taproot spends (cannot be combined with pkh, witv0, or script)
@@ -479,13 +487,18 @@ def make_spender(comment, *, tap=None, witv0=False, script=None, pkh=None, p2sh=
* p2sh: whether the output is P2SH wrapper (this is supported even for Taproot, where it makes the output unencumbered)
* spk_mutate_pre_psh: a callable to be applied to the script (before potentially P2SH-wrapping it)
* failure: a dict of entries to override in the context when intentionally failing to spend (if None, no_fail will be set)
- * standard: whether the (valid version of) spending is expected to be standard
+ * standard: whether the (valid version of) spending is expected to be standard (True is mapped to Standard.ALL, False is mapped to Standard.NONE)
* err_msg: a string with an expected error message for failure (or None, if not cared about)
* sigops_weight: the pre-taproot sigops weight consumed by a successful spend
* need_vin_vout_mismatch: whether this test requires being tested in a transaction input that has no corresponding
transaction output.
"""
+ if standard == True:
+ standard = Standard.ALL
+ elif standard == False:
+ standard = Standard.NONE
+
conf = dict()
# Compute scriptPubKey and set useful defaults based on the inputs.
@@ -1170,12 +1183,12 @@ def spenders_taproot_inactive():
tap = taproot_construct(pub, scripts)
# Test that keypath spending is valid & non-standard, regardless of validity.
- add_spender(spenders, "inactive/keypath_valid", key=sec, tap=tap, standard=False)
+ add_spender(spenders, "inactive/keypath_valid", key=sec, tap=tap, standard=Standard.V23)
add_spender(spenders, "inactive/keypath_invalidsig", key=sec, tap=tap, standard=False, sighash=bitflipper(default_sighash))
add_spender(spenders, "inactive/keypath_empty", key=sec, tap=tap, standard=False, witness=[])
# Same for scriptpath spending (and features like annex, leaf versions, or OP_SUCCESS don't change this)
- add_spender(spenders, "inactive/scriptpath_valid", key=sec, tap=tap, leaf="pk", standard=False, inputs=[getter("sign")])
+ add_spender(spenders, "inactive/scriptpath_valid", key=sec, tap=tap, leaf="pk", standard=Standard.V23, inputs=[getter("sign")])
add_spender(spenders, "inactive/scriptpath_invalidsig", key=sec, tap=tap, leaf="pk", standard=False, inputs=[getter("sign")], sighash=bitflipper(default_sighash))
add_spender(spenders, "inactive/scriptpath_invalidcb", key=sec, tap=tap, leaf="pk", standard=False, inputs=[getter("sign")], controlblock=bitflipper(default_controlblock))
add_spender(spenders, "inactive/scriptpath_valid_unkleaf", key=sec, tap=tap, leaf="future_leaf", standard=False, inputs=[getter("sign")])
@@ -1205,7 +1218,7 @@ def dump_json_test(tx, input_utxos, idx, success, failure):
# The "final" field indicates that a spend should be always valid, even with more validation flags enabled
# than the listed ones. Use standardness as a proxy for this (which gives a conservative underestimate).
- if spender.is_standard:
+ if spender.is_standard == Standard.ALL:
fields.append(("final", True))
def dump_witness(wit):
@@ -1266,12 +1279,8 @@ class TaprootTest(BitcoinTestFramework):
# transactions.
extra_output_script = CScript([OP_CHECKSIG]*((MAX_BLOCK_SIGOPS_WEIGHT - sigops_weight) // WITNESS_SCALE_FACTOR))
- block = create_block(self.tip, create_coinbase(self.lastblockheight + 1, pubkey=cb_pubkey, extra_output_script=extra_output_script, fees=fees), self.lastblocktime + 1)
- block.nVersion = 4
- for tx in txs:
- tx.rehash()
- block.vtx.append(tx)
- block.hashMerkleRoot = block.calc_merkle_root()
+ coinbase_tx = create_coinbase(self.lastblockheight + 1, pubkey=cb_pubkey, extra_output_script=extra_output_script, fees=fees)
+ block = create_block(self.tip, coinbase_tx, self.lastblocktime + 1, txlist=txs)
witness and add_witness_commitment(block)
block.solve()
block_response = node.submitblock(block.serialize().hex())
@@ -1474,8 +1483,13 @@ class TaprootTest(BitcoinTestFramework):
for i in range(len(input_utxos)):
tx.vin[i].scriptSig = input_data[i][i != fail_input][0]
tx.wit.vtxinwit[i].scriptWitness.stack = input_data[i][i != fail_input][1]
+ taproot_spend_policy = Standard.V23 if node.version is None else Standard.ALL
# Submit to mempool to check standardness
- is_standard_tx = fail_input is None and all(utxo.spender.is_standard for utxo in input_utxos) and tx.nVersion >= 1 and tx.nVersion <= 2
+ is_standard_tx = (
+ fail_input is None # Must be valid to be standard
+ and (all(utxo.spender.is_standard == Standard.ALL or utxo.spender.is_standard == taproot_spend_policy for utxo in input_utxos)) # All inputs must be standard
+ and tx.nVersion >= 1 # The tx version must be standard
+ and tx.nVersion <= 2)
tx.rehash()
msg = ','.join(utxo.spender.comment + ("*" if n == fail_input else "") for n, utxo in enumerate(input_utxos))
if is_standard_tx:
@@ -1503,7 +1517,7 @@ class TaprootTest(BitcoinTestFramework):
assert self.nodes[1].getblockcount() == 0
coinbase = CTransaction()
coinbase.nVersion = 1
- coinbase.vin = [CTxIn(COutPoint(0, 0xffffffff), CScript([OP_1, OP_1]), 0xffffffff)]
+ coinbase.vin = [CTxIn(COutPoint(0, 0xffffffff), CScript([OP_1, OP_1]), SEQUENCE_FINAL)]
coinbase.vout = [CTxOut(5000000000, CScript([OP_1]))]
coinbase.nLockTime = 0
coinbase.rehash()
@@ -1591,7 +1605,7 @@ class TaprootTest(BitcoinTestFramework):
val = 42000000 * (i + 7)
tx = CTransaction()
tx.nVersion = 1
- tx.vin = [CTxIn(COutPoint(lasttxid, i & 1), CScript([]), 0xffffffff)]
+ tx.vin = [CTxIn(COutPoint(lasttxid, i & 1), CScript([]), SEQUENCE_FINAL)]
tx.vout = [CTxOut(val, spk), CTxOut(amount - val, CScript([OP_1]))]
if i & 1:
tx.vout = list(reversed(tx.vout))
@@ -1651,7 +1665,7 @@ class TaprootTest(BitcoinTestFramework):
tx.vin = []
inputs = []
input_spks = [tap_spks[0], tap_spks[1], old_spks[0], tap_spks[2], tap_spks[5], old_spks[2], tap_spks[6], tap_spks[3], tap_spks[4]]
- sequences = [0, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffffe, 0, 0, 0xffffffff, 0xffffffff]
+ sequences = [0, SEQUENCE_FINAL, SEQUENCE_FINAL, 0xfffffffe, 0xfffffffe, 0, 0, SEQUENCE_FINAL, SEQUENCE_FINAL]
hashtypes = [SIGHASH_SINGLE, SIGHASH_SINGLE|SIGHASH_ANYONECANPAY, SIGHASH_ALL, SIGHASH_ALL, SIGHASH_DEFAULT, SIGHASH_ALL, SIGHASH_NONE, SIGHASH_NONE|SIGHASH_ANYONECANPAY, SIGHASH_ALL|SIGHASH_ANYONECANPAY]
for i, spk in enumerate(input_spks):
tx.vin.append(CTxIn(spend_info[spk]['prevout'], CScript(), sequences[i]))
diff --git a/test/functional/feature_utxo_set_hash.py b/test/functional/feature_utxo_set_hash.py
index 33b7615aea..75180e62a2 100755
--- a/test/functional/feature_utxo_set_hash.py
+++ b/test/functional/feature_utxo_set_hash.py
@@ -69,8 +69,8 @@ class UTXOSetHashTest(BitcoinTestFramework):
assert_equal(finalized[::-1].hex(), node_muhash)
self.log.info("Test deterministic UTXO set hash results")
- assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "221f245cf4c9010eeb7f5183d342c002ae6c1c27e98aa357dccb788c21d98049")
- assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "7c0890c68501f7630d36aeb3999dc924e63af084ae1bbfba11dd462144637635")
+ assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "3a570529b4c32e77268de1f81b903c75cc2da53c48df0d125c1e697ba7c8c7b7")
+ assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "a13e0e70eb8acc786549596e3bc154623f1a5a622ba2f70715f6773ec745f435")
def run_test(self):
self.test_muhash_implementation()
diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py
index fb4fa61a1c..e83dd7f446 100755
--- a/test/functional/feature_versionbits_warning.py
+++ b/test/functional/feature_versionbits_warning.py
@@ -48,8 +48,7 @@ class VersionBitsWarningTest(BitcoinTestFramework):
tip = int(tip, 16)
for _ in range(numblocks):
- block = create_block(tip, create_coinbase(height + 1), block_time)
- block.nVersion = version
+ block = create_block(tip, create_coinbase(height + 1), block_time, version=version)
block.solve()
peer.send_message(msg_block(block))
block_time += 1
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index 6076dceeaf..db5564ac50 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -69,7 +69,7 @@ class TestBitcoinCli(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
- if self.is_wallet_compiled():
+ if self.is_specified_wallet_compiled():
self.requires_wallet = True
def skip_test_if_missing_module(self):
@@ -113,7 +113,7 @@ class TestBitcoinCli(BitcoinTestFramework):
assert_raises_process_error(1, "Invalid value for -color option. Valid values: always, auto, never.", self.nodes[0].cli('-getinfo', '-color=foo').send_cli)
self.log.info("Test -getinfo returns expected network and blockchain info")
- if self.is_wallet_compiled():
+ if self.is_specified_wallet_compiled():
self.nodes[0].encryptwallet(password)
cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli()
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
@@ -138,8 +138,11 @@ class TestBitcoinCli(BitcoinTestFramework):
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, cjdns), 127.0.0.1:7656 (i2p)")
- if self.is_wallet_compiled():
+ if self.is_specified_wallet_compiled():
self.log.info("Test -getinfo and bitcoin-cli getwalletinfo return expected wallet info")
+ # Explicitly set the output type in order to have consistent tx vsize / fees
+ # for both legacy and descriptor wallets (disables the change address type detection algorithm)
+ self.restart_node(0, extra_args=["-addresstype=bech32", "-changetype=bech32"])
assert_equal(Decimal(cli_get_info['Balance']), BALANCE)
assert 'Balances' not in cli_get_info_string
wallet_info = self.nodes[0].getwalletinfo()
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index a2f84573da..06aa5608bb 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -22,6 +22,10 @@ from test_framework.util import (
from test_framework.messages import BLOCK_HEADER_SIZE
+INVALID_PARAM = "abc"
+UNKNOWN_PARAM = "0000000000000000000000000000000000000000000000000000000000000000"
+
+
class ReqType(Enum):
JSON = 1
BIN = 2
@@ -41,7 +45,7 @@ class RESTTest (BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
- self.extra_args = [["-rest"], []]
+ self.extra_args = [["-rest", "-blockfilterindex=1"], []]
self.supports_cli = False
def skip_test_if_missing_module(self):
@@ -103,6 +107,12 @@ class RESTTest (BitcoinTestFramework):
n, = filter_output_indices_by_value(json_obj['vout'], Decimal('0.1'))
spending = (txid, n)
+ # Test /tx with an invalid and an unknown txid
+ resp = self.test_rest_request(uri=f"/tx/{INVALID_PARAM}", ret_type=RetType.OBJ, status=400)
+ assert_equal(resp.read().decode('utf-8').rstrip(), f"Invalid hash: {INVALID_PARAM}")
+ resp = self.test_rest_request(uri=f"/tx/{UNKNOWN_PARAM}", ret_type=RetType.OBJ, status=404)
+ assert_equal(resp.read().decode('utf-8').rstrip(), f"{UNKNOWN_PARAM} not found")
+
self.log.info("Query an unspent TXO using the /getutxos URI")
self.generatetoaddress(self.nodes[1], 1, not_related_address)
@@ -205,8 +215,8 @@ class RESTTest (BitcoinTestFramework):
bb_hash = self.nodes[0].getbestblockhash()
# Check result if block does not exists
- assert_equal(self.test_rest_request('/headers/1/0000000000000000000000000000000000000000000000000000000000000000'), [])
- self.test_rest_request('/block/0000000000000000000000000000000000000000000000000000000000000000', status=404, ret_type=RetType.OBJ)
+ assert_equal(self.test_rest_request(f"/headers/1/{UNKNOWN_PARAM}"), [])
+ self.test_rest_request(f"/block/{UNKNOWN_PARAM}", status=404, ret_type=RetType.OBJ)
# Check result if block is not in the active chain
self.nodes[0].invalidateblock(bb_hash)
@@ -250,8 +260,8 @@ class RESTTest (BitcoinTestFramework):
assert_equal(blockhash, bb_hash)
# Check invalid blockhashbyheight requests
- resp = self.test_rest_request("/blockhashbyheight/abc", ret_type=RetType.OBJ, status=400)
- assert_equal(resp.read().decode('utf-8').rstrip(), "Invalid height: abc")
+ resp = self.test_rest_request(f"/blockhashbyheight/{INVALID_PARAM}", ret_type=RetType.OBJ, status=400)
+ assert_equal(resp.read().decode('utf-8').rstrip(), f"Invalid height: {INVALID_PARAM}")
resp = self.test_rest_request("/blockhashbyheight/1000000", ret_type=RetType.OBJ, status=404)
assert_equal(resp.read().decode('utf-8').rstrip(), "Block height out of range")
resp = self.test_rest_request("/blockhashbyheight/-1", ret_type=RetType.OBJ, status=400)
@@ -272,11 +282,20 @@ class RESTTest (BitcoinTestFramework):
self.generate(self.nodes[1], 5)
json_obj = self.test_rest_request(f"/headers/5/{bb_hash}")
assert_equal(len(json_obj), 5) # now we should have 5 header objects
+ json_obj = self.test_rest_request(f"/blockfilterheaders/basic/5/{bb_hash}")
+ first_filter_header = json_obj[0]
+ assert_equal(len(json_obj), 5) # now we should have 5 filter header objects
+ json_obj = self.test_rest_request(f"/blockfilter/basic/{bb_hash}")
+
+ # Compare with normal RPC blockfilter response
+ rpc_blockfilter = self.nodes[0].getblockfilter(bb_hash)
+ assert_equal(first_filter_header, rpc_blockfilter['header'])
+ assert_equal(json_obj['filter'], rpc_blockfilter['filter'])
# Test number parsing
for num in ['5a', '-5', '0', '2001', '99999999999999999999999999999999999']:
assert_equal(
- bytes(f'Header count out of range: {num}\r\n', 'ascii'),
+ bytes(f'Header count is invalid or out of acceptable range (1-2000): {num}\r\n', 'ascii'),
self.test_rest_request(f"/headers/{num}/{bb_hash}", ret_type=RetType.BYTES, status=400),
)
diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py
index 395fde18fd..1ee12c0040 100755
--- a/test/functional/interface_zmq.py
+++ b/test/functional/interface_zmq.py
@@ -18,7 +18,6 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import (
CTransaction,
hash256,
- tx_from_hex,
)
from test_framework.util import (
assert_equal,
@@ -402,12 +401,8 @@ class ZMQTest (BitcoinTestFramework):
raw_tx = self.nodes[0].getrawtransaction(orig_txid)
bump_info = self.nodes[0].bumpfee(orig_txid)
# Mine the pre-bump tx
- block = create_block(int(self.nodes[0].getbestblockhash(), 16), create_coinbase(self.nodes[0].getblockcount()+1))
- tx = tx_from_hex(raw_tx)
- block.vtx.append(tx)
- for txid in more_tx:
- tx = tx_from_hex(self.nodes[0].getrawtransaction(txid))
- block.vtx.append(tx)
+ txs_to_add = [raw_tx] + [self.nodes[0].getrawtransaction(txid) for txid in more_tx]
+ block = create_block(int(self.nodes[0].getbestblockhash(), 16), create_coinbase(self.nodes[0].getblockcount()+1), txlist=txs_to_add)
add_witness_commitment(block)
block.solve()
assert_equal(self.nodes[0].submitblock(block.serialize().hex()), None)
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index 44db8bb00a..d3961e753d 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mempool acceptance of raw transactions."""
+from copy import deepcopy
from decimal import Decimal
import math
@@ -17,6 +18,7 @@ from test_framework.messages import (
CTxOut,
MAX_BLOCK_WEIGHT,
MAX_MONEY,
+ SEQUENCE_FINAL,
tx_from_hex,
)
from test_framework.script import (
@@ -33,6 +35,7 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
+from test_framework.wallet import MiniWallet
class MempoolAcceptanceTest(BitcoinTestFramework):
@@ -43,9 +46,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
]] * self.num_nodes
self.supports_cli = False
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def check_mempool_result(self, result_expected, *args, **kwargs):
"""Wrapper to check result of testmempoolaccept on node_0's mempool"""
result_test = self.nodes[0].testmempoolaccept(*args, **kwargs)
@@ -56,12 +56,13 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
def run_test(self):
node = self.nodes[0]
+ self.wallet = MiniWallet(node)
+ self.wallet.rescan_utxos()
self.log.info('Start with empty mempool, and 200 blocks')
self.mempool_size = 0
assert_equal(node.getblockcount(), 200)
assert_equal(node.getmempoolinfo()['size'], self.mempool_size)
- coins = node.listunspent()
self.log.info('Should not accept garbage to testmempoolaccept')
assert_raises_rpc_error(-3, 'Expected type array, got string', lambda: node.testmempoolaccept(rawtxs='ff00baar'))
@@ -70,12 +71,12 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
assert_raises_rpc_error(-22, 'TX decode failed', lambda: node.testmempoolaccept(rawtxs=['ff00baar']))
self.log.info('A transaction already in the blockchain')
- coin = coins.pop() # Pick a random coin(base) to spend
- raw_tx_in_block = node.signrawtransactionwithwallet(node.createrawtransaction(
- inputs=[{'txid': coin['txid'], 'vout': coin['vout']}],
- outputs=[{node.getnewaddress(): 0.3}, {node.getnewaddress(): 49}],
- ))['hex']
- txid_in_block = node.sendrawtransaction(hexstring=raw_tx_in_block, maxfeerate=0)
+ tx = self.wallet.create_self_transfer()['tx'] # Pick a random coin(base) to spend
+ tx.vout.append(deepcopy(tx.vout[0]))
+ tx.vout[0].nValue = int(0.3 * COIN)
+ tx.vout[1].nValue = int(49 * COIN)
+ raw_tx_in_block = tx.serialize().hex()
+ txid_in_block = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_in_block, maxfeerate=0)
self.generate(node, 1)
self.mempool_size = 0
self.check_mempool_result(
@@ -85,11 +86,10 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
self.log.info('A transaction not in the mempool')
fee = Decimal('0.000007')
- raw_tx_0 = node.signrawtransactionwithwallet(node.createrawtransaction(
- inputs=[{"txid": txid_in_block, "vout": 0, "sequence": BIP125_SEQUENCE_NUMBER}], # RBF is used later
- outputs=[{node.getnewaddress(): Decimal('0.3') - fee}],
- ))['hex']
- tx = tx_from_hex(raw_tx_0)
+ utxo_to_spend = self.wallet.get_utxo(txid=txid_in_block) # use 0.3 BTC UTXO
+ tx = self.wallet.create_self_transfer(utxo_to_spend=utxo_to_spend, sequence=BIP125_SEQUENCE_NUMBER)['tx']
+ tx.vout[0].nValue = int((Decimal('0.3') - fee) * COIN)
+ raw_tx_0 = tx.serialize().hex()
txid_0 = tx.rehash()
self.check_mempool_result(
result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': fee}}],
@@ -97,15 +97,15 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
)
self.log.info('A final transaction not in the mempool')
- coin = coins.pop() # Pick a random coin(base) to spend
output_amount = Decimal('0.025')
- raw_tx_final = node.signrawtransactionwithwallet(node.createrawtransaction(
- inputs=[{'txid': coin['txid'], 'vout': coin['vout'], "sequence": 0xffffffff}], # SEQUENCE_FINAL
- outputs=[{node.getnewaddress(): output_amount}],
+ tx = self.wallet.create_self_transfer(
+ sequence=SEQUENCE_FINAL,
locktime=node.getblockcount() + 2000, # Can be anything
- ))['hex']
+ )['tx']
+ tx.vout[0].nValue = int(output_amount * COIN)
+ raw_tx_final = tx.serialize().hex()
tx = tx_from_hex(raw_tx_final)
- fee_expected = coin['amount'] - output_amount
+ fee_expected = Decimal('50.0') - output_amount
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': fee_expected}}],
rawtxs=[tx.serialize().hex()],
@@ -126,8 +126,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx = tx_from_hex(raw_tx_0)
tx.vout[0].nValue -= int(fee * COIN) # Double the fee
tx.vin[0].nSequence = BIP125_SEQUENCE_NUMBER + 1 # Now, opt out of RBF
- raw_tx_0 = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
- tx = tx_from_hex(raw_tx_0)
+ raw_tx_0 = tx.serialize().hex()
txid_0 = tx.rehash()
self.check_mempool_result(
result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': (2 * fee)}}],
@@ -140,7 +139,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
# take original raw_tx_0
tx = tx_from_hex(raw_tx_0)
tx.vout[0].nValue -= int(4 * fee * COIN) # Set more fee
- # skip re-signing the tx
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'txn-mempool-conflict'}],
rawtxs=[tx.serialize().hex()],
@@ -150,7 +148,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
self.log.info('A transaction with missing inputs, that never existed')
tx = tx_from_hex(raw_tx_0)
tx.vin[0].prevout = COutPoint(hash=int('ff' * 32, 16), n=14)
- # skip re-signing the tx
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'missing-inputs'}],
rawtxs=[tx.serialize().hex()],
@@ -159,17 +156,17 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
self.log.info('A transaction with missing inputs, that existed once in the past')
tx = tx_from_hex(raw_tx_0)
tx.vin[0].prevout.n = 1 # Set vout to 1, to spend the other outpoint (49 coins) of the in-chain-tx we want to double spend
- raw_tx_1 = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
+ raw_tx_1 = tx.serialize().hex()
txid_1 = node.sendrawtransaction(hexstring=raw_tx_1, maxfeerate=0)
# Now spend both to "clearly hide" the outputs, ie. remove the coins from the utxo set by spending them
- raw_tx_spend_both = node.signrawtransactionwithwallet(node.createrawtransaction(
- inputs=[
- {'txid': txid_0, 'vout': 0},
- {'txid': txid_1, 'vout': 0},
- ],
- outputs=[{node.getnewaddress(): 0.1}]
- ))['hex']
- txid_spend_both = node.sendrawtransaction(hexstring=raw_tx_spend_both, maxfeerate=0)
+ tx = self.wallet.create_self_transfer()['tx']
+ tx.vin.append(deepcopy(tx.vin[0]))
+ tx.wit.vtxinwit.append(deepcopy(tx.wit.vtxinwit[0]))
+ tx.vin[0].prevout = COutPoint(hash=int(txid_0, 16), n=0)
+ tx.vin[1].prevout = COutPoint(hash=int(txid_1, 16), n=0)
+ tx.vout[0].nValue = int(0.1 * COIN)
+ raw_tx_spend_both = tx.serialize().hex()
+ txid_spend_both = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_spend_both, maxfeerate=0)
self.generate(node, 1)
self.mempool_size = 0
# Now see if we can add the coins back to the utxo set by sending the exact txs again
@@ -182,12 +179,11 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
rawtxs=[raw_tx_1],
)
- self.log.info('Create a signed "reference" tx for later use')
- raw_tx_reference = node.signrawtransactionwithwallet(node.createrawtransaction(
- inputs=[{'txid': txid_spend_both, 'vout': 0}],
- outputs=[{node.getnewaddress(): 0.05}],
- ))['hex']
- tx = tx_from_hex(raw_tx_reference)
+ self.log.info('Create a "reference" tx for later use')
+ utxo_to_spend = self.wallet.get_utxo(txid=txid_spend_both)
+ tx = self.wallet.create_self_transfer(utxo_to_spend=utxo_to_spend, sequence=SEQUENCE_FINAL)['tx']
+ tx.vout[0].nValue = int(0.05 * COIN)
+ raw_tx_reference = tx.serialize().hex()
# Reference tx should be valid on itself
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': { 'base': Decimal('0.1') - Decimal('0.05')}}],
@@ -198,8 +194,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
self.log.info('A transaction with no outputs')
tx = tx_from_hex(raw_tx_reference)
tx.vout = []
- # Skip re-signing the transaction for context independent checks from now on
- # tx = tx_from_hex(node.signrawtransactionwithwallet(tx.serialize().hex())['hex'])
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-empty'}],
rawtxs=[tx.serialize().hex()],
@@ -256,7 +250,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
)
self.log.info('A coinbase transaction')
- # Pick the input of the first tx we signed, so it has to be a coinbase tx
+ # Pick the input of the first tx we created, so it has to be a coinbase tx
raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid'])
tx = tx_from_hex(raw_tx_coinbase_spent)
self.check_mempool_result(
@@ -333,7 +327,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
self.log.info('A transaction that is locked by BIP68 sequence logic')
tx = tx_from_hex(raw_tx_reference)
tx.vin[0].nSequence = 2 # We could include it in the second block mined from now, but not the very next one
- # Can skip re-signing the tx because of early rejection
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-BIP68-final'}],
rawtxs=[tx.serialize().hex()],
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index dcbd340f11..068fdc0b65 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -91,7 +91,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(ancestor_vsize, sum([mempool[tx]['vsize'] for tx in mempool]))
ancestor_count = MAX_ANCESTORS
- assert_equal(ancestor_fees, sum([mempool[tx]['fee'] for tx in mempool]))
+ assert_equal(ancestor_fees, sum([mempool[tx]['fees']['base'] for tx in mempool]))
descendants = []
ancestors = list(chain)
@@ -102,11 +102,8 @@ class MempoolPackagesTest(BitcoinTestFramework):
# Check that the descendant calculations are correct
assert_equal(entry['descendantcount'], descendant_count)
- descendant_fees += entry['fee']
- assert_equal(entry['modifiedfee'], entry['fee'])
- assert_equal(entry['fees']['base'], entry['fee'])
- assert_equal(entry['fees']['modified'], entry['modifiedfee'])
- assert_equal(entry['descendantfees'], descendant_fees * COIN)
+ descendant_fees += entry['fees']['base']
+ assert_equal(entry['fees']['modified'], entry['fees']['base'])
assert_equal(entry['fees']['descendant'], descendant_fees)
descendant_vsize += entry['vsize']
assert_equal(entry['descendantsize'], descendant_vsize)
@@ -114,10 +111,10 @@ class MempoolPackagesTest(BitcoinTestFramework):
# Check that ancestor calculations are correct
assert_equal(entry['ancestorcount'], ancestor_count)
- assert_equal(entry['ancestorfees'], ancestor_fees * COIN)
+ assert_equal(entry['fees']['ancestor'], ancestor_fees)
assert_equal(entry['ancestorsize'], ancestor_vsize)
ancestor_vsize -= entry['vsize']
- ancestor_fees -= entry['fee']
+ ancestor_fees -= entry['fees']['base']
ancestor_count -= 1
# Check that parent/child list is correct
@@ -168,9 +165,8 @@ class MempoolPackagesTest(BitcoinTestFramework):
ancestor_fees = 0
for x in chain:
entry = self.nodes[0].getmempoolentry(x)
- ancestor_fees += entry['fee']
+ ancestor_fees += entry['fees']['base']
assert_equal(entry['fees']['ancestor'], ancestor_fees + Decimal('0.00001'))
- assert_equal(entry['ancestorfees'], ancestor_fees * COIN + 1000)
# Undo the prioritisetransaction for later tests
self.nodes[0].prioritisetransaction(txid=chain[0], fee_delta=-1000)
@@ -182,9 +178,8 @@ class MempoolPackagesTest(BitcoinTestFramework):
descendant_fees = 0
for x in reversed(chain):
entry = self.nodes[0].getmempoolentry(x)
- descendant_fees += entry['fee']
+ descendant_fees += entry['fees']['base']
assert_equal(entry['fees']['descendant'], descendant_fees + Decimal('0.00001'))
- assert_equal(entry['descendantfees'], descendant_fees * COIN + 1000)
# Adding one more transaction on to the chain should fail.
assert_raises_rpc_error(-26, "too-long-mempool-chain", chain_transaction, self.nodes[0], [txid], [vout], value, fee, 1)
@@ -204,11 +199,9 @@ class MempoolPackagesTest(BitcoinTestFramework):
descendant_fees = 0
for x in reversed(chain):
entry = self.nodes[0].getmempoolentry(x)
- descendant_fees += entry['fee']
+ descendant_fees += entry['fees']['base']
if (x == chain[-1]):
- assert_equal(entry['modifiedfee'], entry['fee'] + Decimal("0.00002"))
- assert_equal(entry['fees']['modified'], entry['fee'] + Decimal("0.00002"))
- assert_equal(entry['descendantfees'], descendant_fees * COIN + 2000)
+ assert_equal(entry['fees']['modified'], entry['fees']['base'] + Decimal("0.00002"))
assert_equal(entry['fees']['descendant'], descendant_fees + Decimal("0.00002"))
# Check that node1's mempool is as expected (-> custom ancestor limit)
diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py
index 7e940fa3ca..91f2d0051a 100755
--- a/test/functional/mempool_reorg.py
+++ b/test/functional/mempool_reorg.py
@@ -45,14 +45,13 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
utxo_2 = wallet.get_utxo(txid=coinbase_txids[2])
utxo_3 = wallet.get_utxo(txid=coinbase_txids[3])
self.log.info("Create three transactions spending from coinbase utxos: spend_1, spend_2, spend_3")
- spend_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_1)
- spend_2 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_2)
- spend_3 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_3)
+ spend_1 = wallet.create_self_transfer(utxo_to_spend=utxo_1)
+ spend_2 = wallet.create_self_transfer(utxo_to_spend=utxo_2)
+ spend_3 = wallet.create_self_transfer(utxo_to_spend=utxo_3)
self.log.info("Create another transaction which is time-locked to two blocks in the future")
utxo = wallet.get_utxo(txid=coinbase_txids[0])
timelock_tx = wallet.create_self_transfer(
- from_node=self.nodes[0],
utxo_to_spend=utxo,
mempool_valid=False,
locktime=self.nodes[0].getblockcount() + 2
@@ -71,9 +70,9 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
self.log.info("Create spend_2_1 and spend_3_1")
spend_2_utxo = wallet.get_utxo(txid=spend_2['txid'])
- spend_2_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=spend_2_utxo)
+ spend_2_1 = wallet.create_self_transfer(utxo_to_spend=spend_2_utxo)
spend_3_utxo = wallet.get_utxo(txid=spend_3['txid'])
- spend_3_1 = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=spend_3_utxo)
+ spend_3_1 = wallet.create_self_transfer(utxo_to_spend=spend_3_utxo)
self.log.info("Broadcast and mine spend_3_1")
spend_3_1_id = self.nodes[0].sendrawtransaction(spend_3_1['hex'])
diff --git a/test/functional/mempool_spend_coinbase.py b/test/functional/mempool_spend_coinbase.py
index 5afa6be925..9c43ddaf6f 100755
--- a/test/functional/mempool_spend_coinbase.py
+++ b/test/functional/mempool_spend_coinbase.py
@@ -40,7 +40,7 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework):
spend_mature_id = wallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_mature)["txid"]
# other coinbase should be too immature to spend
- immature_tx = wallet.create_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_immature, mempool_valid=False)
+ immature_tx = wallet.create_self_transfer(utxo_to_spend=utxo_immature, mempool_valid=False)
assert_raises_rpc_error(-26,
"bad-txns-premature-spend-of-coinbase",
lambda: self.nodes[0].sendrawtransaction(immature_tx['hex']))
diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py
index f8d002e664..9c64bb1945 100755
--- a/test/functional/mining_basic.py
+++ b/test/functional/mining_basic.py
@@ -29,6 +29,8 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
+from test_framework.wallet import MiniWallet
+
VERSIONBITS_TOP_BITS = 0x20000000
VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT = 28
@@ -51,14 +53,11 @@ class MiningTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.supports_cli = False
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def mine_chain(self):
self.log.info('Create some old blocks')
for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600):
self.nodes[0].setmocktime(t)
- self.generate(self.nodes[0], 1, sync_fun=self.no_op)
+ self.generate(self.wallet, 1, sync_fun=self.no_op)
mining_info = self.nodes[0].getmininginfo()
assert_equal(mining_info['blocks'], 200)
assert_equal(mining_info['currentblocktx'], 0)
@@ -75,8 +74,9 @@ class MiningTest(BitcoinTestFramework):
self.connect_nodes(0, 1)
def run_test(self):
- self.mine_chain()
node = self.nodes[0]
+ self.wallet = MiniWallet(node)
+ self.mine_chain()
def assert_submitblock(block, result_str_1, result_str_2=None):
block.solve()
@@ -95,7 +95,7 @@ class MiningTest(BitcoinTestFramework):
assert_equal(mining_info['pooledtx'], 0)
self.log.info("getblocktemplate: Test default witness commitment")
- txid = int(node.sendtoaddress(node.getnewaddress(), 1), 16)
+ txid = int(self.wallet.send_self_transfer(from_node=node)['wtxid'], 16)
tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
# Check that default_witness_commitment is present.
diff --git a/test/functional/mocks/invalid_signer.py b/test/functional/mocks/invalid_signer.py
new file mode 100755
index 0000000000..e30cc9e20b
--- /dev/null
+++ b/test/functional/mocks/invalid_signer.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018-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.
+
+import os
+import sys
+import argparse
+import json
+
+def perform_pre_checks():
+ mock_result_path = os.path.join(os.getcwd(), "mock_result")
+ if(os.path.isfile(mock_result_path)):
+ with open(mock_result_path, "r", encoding="utf8") as f:
+ mock_result = f.read()
+ if mock_result[0]:
+ sys.stdout.write(mock_result[2:])
+ sys.exit(int(mock_result[0]))
+
+def enumerate(args):
+ sys.stdout.write(json.dumps([{"fingerprint": "b3c19bfc", "type": "trezor", "model": "trezor_t"}, {"fingerprint": "00000002"}]))
+
+def getdescriptors(args):
+ xpub_pkh = "xpub6CRhJvXV8x2AKWvqi1ZSMFU6cbxzQiYrv3dxSUXCawjMJ1JzpqVsveH4way1yCmJm29KzH1zrVZmVwes4Qo6oXVE1HFn4fdiKrYJngqFFc6"
+ xpub_sh = "xpub6CoNoq3Tg4tGSpom2BSwL42gy864KHo3TXkHxLxBbhvCkgmdVXADQmiHbLZhX3Me1cYhRx7s25Lpm4LnT5zu395ANHsXB2QvT9tqJDAibTN"
+ xpub_wpkh = "xpub6DUcLgY1DfgDy2RV6q4djwwsLitaoZDumbribqrR8mP78fEtgZa1XEsqT5MWQ7gwLwKsTQPT28XLoVE5A97rDNTwMXjmzPaNijoCApCbWvp"
+
+ sys.stdout.write(json.dumps({
+ "receive": [
+ "pkh([b3c19bfc/44'/1'/" + args.account + "']" + xpub_pkh + "/0/*)#h26nxtl9",
+ "sh(wpkh([b3c19bfc/49'/1'/" + args.account + "']" + xpub_sh + "/0/*))#32ry02yp",
+ "wpkh([b3c19bfc/84'/1'/" + args.account + "']" + xpub_wpkh + "/0/*)#jftn8ppv"
+ ],
+ "internal": [
+ "pkh([b3c19bfc/44'/1'/" + args.account + "']" + xpub_pkh + "/1/*)#x7ljm70a",
+ "sh(wpkh([b3c19bfc/49'/1'/" + args.account + "']" + xpub_sh + "/1/*))#ytdjh437",
+ "wpkh([b3c19bfc/84'/1'/" + args.account + "']" + xpub_wpkh + "/1/*)#rawj6535"
+ ]
+ }))
+
+parser = argparse.ArgumentParser(prog='./invalid_signer.py', description='External invalid signer mock')
+parser.add_argument('--fingerprint')
+parser.add_argument('--chain', default='main')
+parser.add_argument('--stdin', action='store_true')
+
+subparsers = parser.add_subparsers(description='Commands', dest='command')
+subparsers.required = True
+
+parser_enumerate = subparsers.add_parser('enumerate', help='list available signers')
+parser_enumerate.set_defaults(func=enumerate)
+
+parser_getdescriptors = subparsers.add_parser('getdescriptors')
+parser_getdescriptors.set_defaults(func=getdescriptors)
+parser_getdescriptors.add_argument('--account', metavar='account')
+
+if not sys.stdin.isatty():
+ buffer = sys.stdin.read()
+ if buffer and buffer.rstrip() != "":
+ sys.argv.extend(buffer.rstrip().split(" "))
+
+args = parser.parse_args()
+
+perform_pre_checks()
+
+args.func(args)
diff --git a/test/functional/p2p_add_connections.py b/test/functional/p2p_add_connections.py
index a04ba5db2d..f4462673f2 100755
--- a/test/functional/p2p_add_connections.py
+++ b/test/functional/p2p_add_connections.py
@@ -1,19 +1,23 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test add_outbound_p2p_connection test framework functionality"""
from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
-
-
-def check_node_connections(*, node, num_in, num_out):
- info = node.getnetworkinfo()
- assert_equal(info["connections_in"], num_in)
- assert_equal(info["connections_out"], num_out)
-
+from test_framework.util import (
+ assert_equal,
+ check_node_connections,
+)
+
+class P2PFeelerReceiver(P2PInterface):
+ def on_version(self, message):
+ # The bitcoind node closes feeler connections as soon as a version
+ # message is received from the test framework. Don't send any responses
+ # to the node's version message since the connection will already be
+ # closed.
+ pass
class P2PAddConnections(BitcoinTestFramework):
def set_test_params(self):
@@ -91,6 +95,16 @@ class P2PAddConnections(BitcoinTestFramework):
check_node_connections(node=self.nodes[1], num_in=5, num_out=10)
+ self.log.info("Add 1 feeler connection to node 0")
+ feeler_conn = self.nodes[0].add_outbound_p2p_connection(P2PFeelerReceiver(), p2p_idx=6, connection_type="feeler")
+
+ # Feeler connection is closed
+ assert not feeler_conn.is_connected
+
+ # Verify version message received
+ assert_equal(feeler_conn.message_count["version"], 1)
+ # Feeler connections do not request tx relay
+ assert_equal(feeler_conn.last_message["version"].relay, 0)
if __name__ == '__main__':
P2PAddConnections().main()
diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py
index 5532056dbe..3218a9b14a 100755
--- a/test/functional/p2p_addr_relay.py
+++ b/test/functional/p2p_addr_relay.py
@@ -44,7 +44,7 @@ class AddrReceiver(P2PInterface):
assert_equal(addr.nServices, 9)
if not 8333 <= addr.port < 8343:
raise AssertionError("Invalid addr.port of {} (8333-8342 expected)".format(addr.port))
- assert addr.ip.startswith('123.123.123.')
+ assert addr.ip.startswith('123.123.')
def on_getaddr(self, message):
# When the node sends us a getaddr, it increments the addr relay tokens for the connection by 1000
@@ -91,37 +91,31 @@ class AddrTest(BitcoinTestFramework):
self.blocksonly_mode_tests()
self.rate_limit_tests()
- def setup_addr_msg(self, num):
+ def setup_addr_msg(self, num, sequential_ips=True):
addrs = []
for i in range(num):
addr = CAddress()
- addr.time = self.mocktime + i
+ addr.time = self.mocktime + random.randrange(-100, 100)
addr.nServices = P2P_SERVICES
- addr.ip = f"123.123.123.{self.counter % 256}"
+ if sequential_ips:
+ assert self.counter < 256 ** 2 # Don't allow the returned ip addresses to wrap.
+ addr.ip = f"123.123.{self.counter // 256}.{self.counter % 256}"
+ self.counter += 1
+ else:
+ addr.ip = f"{random.randrange(128,169)}.{random.randrange(1,255)}.{random.randrange(1,255)}.{random.randrange(1,255)}"
addr.port = 8333 + i
addrs.append(addr)
- self.counter += 1
msg = msg_addr()
msg.addrs = addrs
return msg
- def setup_rand_addr_msg(self, num):
- addrs = []
- for i in range(num):
- addr = CAddress()
- addr.time = self.mocktime + i
- 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)
- msg = msg_addr()
- msg.addrs = addrs
- return msg
-
def send_addr_msg(self, source, msg, receivers):
source.send_and_ping(msg)
- # pop m_next_addr_send timer
+ # invoke m_next_addr_send timer:
+ # `addr` messages are sent on an exponential distribution with mean interval of 30s.
+ # Setting the mocktime 600s forward gives a probability of (1 - e^-(600/30)) that
+ # the event will occur (i.e. this fails once in ~500 million repeats).
self.mocktime += 10 * 60
self.nodes[0].setmocktime(self.mocktime)
for peer in receivers:
@@ -282,7 +276,8 @@ class AddrTest(BitcoinTestFramework):
block_relay_peer.send_and_ping(msg_getaddr())
inbound_peer.send_and_ping(msg_getaddr())
- self.mocktime += 5 * 60
+ # invoke m_next_addr_send timer, see under send_addr_msg() function for rationale
+ self.mocktime += 10 * 60
self.nodes[0].setmocktime(self.mocktime)
inbound_peer.wait_until(lambda: inbound_peer.addr_received() is True)
@@ -313,7 +308,7 @@ class AddrTest(BitcoinTestFramework):
def send_addrs_and_test_rate_limiting(self, peer, no_relay, *, new_addrs, total_addrs):
"""Send an addr message and check that the number of addresses processed and rate-limited is as expected"""
- peer.send_and_ping(self.setup_rand_addr_msg(new_addrs))
+ peer.send_and_ping(self.setup_addr_msg(new_addrs, sequential_ips=False))
peerinfo = self.nodes[0].getpeerinfo()[0]
addrs_processed = peerinfo['addr_processed']
diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py
index 6e48341259..6f142f23f2 100755
--- a/test/functional/p2p_blocksonly.py
+++ b/test/functional/p2p_blocksonly.py
@@ -102,7 +102,7 @@ class P2PBlocksOnly(BitcoinTestFramework):
def check_p2p_tx_violation(self):
self.log.info('Check that txs from P2P are rejected and result in disconnect')
- spendtx = self.miniwallet.create_self_transfer(from_node=self.nodes[0])
+ spendtx = self.miniwallet.create_self_transfer()
with self.nodes[0].assert_debug_log(['transaction sent in violation of protocol peer=0']):
self.nodes[0].p2ps[0].send_message(msg_tx(spendtx['tx']))
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index a314e8edfd..364e806e18 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -65,6 +65,8 @@ from test_framework.util import (
assert_equal,
softfork_active,
)
+from test_framework.wallet import MiniWallet
+
# TestP2PConn: A peer we use to send messages to bitcoind, and store responses.
class TestP2PConn(P2PInterface):
@@ -150,9 +152,6 @@ class CompactBlocksTest(BitcoinTestFramework):
]]
self.utxos = []
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def build_block_on_tip(self, node, segwit=False):
block = create_block(tmpl=node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS))
if segwit:
@@ -165,7 +164,7 @@ class CompactBlocksTest(BitcoinTestFramework):
block = self.build_block_on_tip(self.nodes[0])
self.segwit_node.send_and_ping(msg_no_witness_block(block))
assert int(self.nodes[0].getbestblockhash(), 16) == block.sha256
- self.generatetoaddress(self.nodes[0], COINBASE_MATURITY, self.nodes[0].getnewaddress(address_type="bech32"))
+ self.generate(self.wallet, COINBASE_MATURITY)
total_value = block.vtx[0].vout[0].nValue
out_value = total_value // 10
@@ -296,12 +295,10 @@ class CompactBlocksTest(BitcoinTestFramework):
# Generate a bunch of transactions.
self.generate(node, COINBASE_MATURITY + 1)
num_transactions = 25
- address = node.getnewaddress()
segwit_tx_generated = False
for _ in range(num_transactions):
- txid = node.sendtoaddress(address, 0.1)
- hex_tx = node.gettransaction(txid)["hex"]
+ hex_tx = self.wallet.send_self_transfer(from_node=self.nodes[0])['hex']
tx = tx_from_hex(hex_tx)
if not tx.wit.is_null():
segwit_tx_generated = True
@@ -843,8 +840,7 @@ class CompactBlocksTest(BitcoinTestFramework):
assert_highbandwidth_states(self.nodes[0], hb_to=True, hb_from=False)
def run_test(self):
- # Get the nodes out of IBD
- self.generate(self.nodes[0], 1)
+ self.wallet = MiniWallet(self.nodes[0])
# Setup the p2p connections
self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=2))
diff --git a/test/functional/p2p_disconnect_ban.py b/test/functional/p2p_disconnect_ban.py
index fb8529ad2b..7284ecde83 100755
--- a/test/functional/p2p_disconnect_ban.py
+++ b/test/functional/p2p_disconnect_ban.py
@@ -57,11 +57,11 @@ class DisconnectBanTest(BitcoinTestFramework):
assert_equal(len(self.nodes[1].listbanned()), 0)
self.log.info("setban: test persistence across node restart")
- self.nodes[1].setban("127.0.0.0/32", "add")
- self.nodes[1].setban("127.0.0.0/24", "add")
# Set the mocktime so we can control when bans expire
old_time = int(time.time())
self.nodes[1].setmocktime(old_time)
+ self.nodes[1].setban("127.0.0.0/32", "add")
+ self.nodes[1].setban("127.0.0.0/24", "add")
self.nodes[1].setban("192.168.0.1", "add", 1) # ban for 1 seconds
self.nodes[1].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds
listBeforeShutdown = self.nodes[1].listbanned()
@@ -70,6 +70,15 @@ class DisconnectBanTest(BitcoinTestFramework):
self.nodes[1].setmocktime(old_time + 3)
assert_equal(len(self.nodes[1].listbanned()), 3)
+ self.log.info("Test ban_duration and time_remaining")
+ for ban in self.nodes[1].listbanned():
+ if ban["address"] in ["127.0.0.0/32", "127.0.0.0/24"]:
+ assert_equal(ban["ban_duration"], 86400)
+ assert_equal(ban["time_remaining"], 86397)
+ elif ban["address"] == "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19":
+ assert_equal(ban["ban_duration"], 1000)
+ assert_equal(ban["time_remaining"], 997)
+
self.restart_node(1)
listAfterShutdown = self.nodes[1].listbanned()
diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py
index 2192363a89..3cf92b0316 100755
--- a/test/functional/p2p_filter.py
+++ b/test/functional/p2p_filter.py
@@ -31,7 +31,7 @@ from test_framework.script import MAX_SCRIPT_ELEMENT_SIZE
from test_framework.test_framework import BitcoinTestFramework
from test_framework.wallet import (
MiniWallet,
- random_p2wpkh,
+ getnewdestination,
)
@@ -169,14 +169,14 @@ class FilterTest(BitcoinTestFramework):
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.generatetoscriptpubkey(random_p2wpkh())
+ block_hash = self.generatetoscriptpubkey(getnewdestination()[1])
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.wallet.send_to(from_node=self.nodes[0], scriptPubKey=random_p2wpkh(), amount=7 * COIN)
+ self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=getnewdestination()[1], amount=7 * COIN)
filter_peer.sync_send_with_ping()
assert not filter_peer.merkleblock_received
assert not filter_peer.tx_received
@@ -190,14 +190,14 @@ class FilterTest(BitcoinTestFramework):
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.wallet.send_to(from_node=self.nodes[0], scriptPubKey=random_p2wpkh(), amount=7 * COIN)
+ txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=getnewdestination()[1], 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.generatetoscriptpubkey(random_p2wpkh())
+ block_hash = self.generatetoscriptpubkey(getnewdestination()[1])
filter_peer.wait_for_inv([CInv(MSG_BLOCK, int(block_hash, 16))])
filter_peer.sync_with_ping()
assert not filter_peer.merkleblock_received
diff --git a/test/functional/p2p_ibd_txrelay.py b/test/functional/p2p_ibd_txrelay.py
index 9044ed5cdb..65a94ad31c 100755
--- a/test/functional/p2p_ibd_txrelay.py
+++ b/test/functional/p2p_ibd_txrelay.py
@@ -2,11 +2,30 @@
# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Test fee filters during and after IBD."""
+"""Test transaction relay behavior during IBD:
+- Set fee filters to MAX_MONEY
+- Don't request transactions
+- Ignore all transaction messages
+"""
from decimal import Decimal
+import time
-from test_framework.messages import COIN
+from test_framework.messages import (
+ CInv,
+ COIN,
+ CTransaction,
+ from_hex,
+ msg_inv,
+ msg_tx,
+ MSG_WTX,
+)
+from test_framework.p2p import (
+ NONPREF_PEER_TX_DELAY,
+ P2PDataStore,
+ P2PInterface,
+ p2p_lock
+)
from test_framework.test_framework import BitcoinTestFramework
MAX_FEE_FILTER = Decimal(9170997) / COIN
@@ -28,6 +47,31 @@ class P2PIBDTxRelayTest(BitcoinTestFramework):
assert node.getblockchaininfo()['initialblockdownload']
self.wait_until(lambda: all(peer['minfeefilter'] == MAX_FEE_FILTER for peer in node.getpeerinfo()))
+ self.log.info("Check that nodes don't send getdatas for transactions while still in IBD")
+ peer_inver = self.nodes[0].add_p2p_connection(P2PDataStore())
+ txid = 0xdeadbeef
+ peer_inver.send_and_ping(msg_inv([CInv(t=MSG_WTX, h=txid)]))
+ # The node should not send a getdata, but if it did, it would first delay 2 seconds
+ self.nodes[0].setmocktime(int(time.time() + NONPREF_PEER_TX_DELAY))
+ peer_inver.sync_send_with_ping()
+ with p2p_lock:
+ assert txid not in peer_inver.getdata_requests
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info("Check that nodes don't process unsolicited transactions while still in IBD")
+ # A transaction hex pulled from tx_valid.json. There are no valid transactions since no UTXOs
+ # exist yet, but it should be a well-formed transaction.
+ rawhex = "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff473" + \
+ "04402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e168" + \
+ "1a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696a" + \
+ "d990364e555c271ad504b88ac00000000"
+ assert self.nodes[1].decoderawtransaction(rawhex) # returns a dict, should not throw
+ tx = from_hex(CTransaction(), rawhex)
+ peer_txer = self.nodes[0].add_p2p_connection(P2PInterface())
+ with self.nodes[0].assert_debug_log(expected_msgs=["received: tx"], unexpected_msgs=["was not accepted"]):
+ peer_txer.send_and_ping(msg_tx(tx))
+ self.nodes[0].disconnect_p2ps()
+
# Come out of IBD by generating a block
self.generate(self.nodes[0], 1)
@@ -36,6 +80,10 @@ class P2PIBDTxRelayTest(BitcoinTestFramework):
assert not node.getblockchaininfo()['initialblockdownload']
self.wait_until(lambda: all(peer['minfeefilter'] == NORMAL_FEE_FILTER for peer in node.getpeerinfo()))
+ self.log.info("Check that nodes process the same transaction, even when unsolicited, when no longer in IBD")
+ peer_txer = self.nodes[0].add_p2p_connection(P2PInterface())
+ with self.nodes[0].assert_debug_log(expected_msgs=["was not accepted"]):
+ peer_txer.send_and_ping(msg_tx(tx))
if __name__ == '__main__':
P2PIBDTxRelayTest().main()
diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py
index 4baf407f89..710f3d93e1 100755
--- a/test/functional/p2p_invalid_block.py
+++ b/test/functional/p2p_invalid_block.py
@@ -15,14 +15,18 @@ becomes valid.
import copy
import time
-from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script
+from test_framework.blocktools import (
+ MAX_FUTURE_BLOCK_TIME,
+ create_block,
+ create_coinbase,
+ create_tx_with_script,
+)
from test_framework.messages import COIN
from test_framework.p2p import P2PDataStore
+from test_framework.script import OP_TRUE
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
-MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60
-
class InvalidBlockRequestTest(BitcoinTestFramework):
def set_test_params(self):
@@ -66,15 +70,10 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
# For more information on merkle-root malleability see src/consensus/merkle.cpp.
self.log.info("Test merkle root malleability.")
- block2 = create_block(tip, create_coinbase(height), block_time)
+ tx1 = create_tx_with_script(block1.vtx[0], 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN)
+ tx2 = create_tx_with_script(tx1, 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN)
+ block2 = create_block(tip, create_coinbase(height), block_time, txlist=[tx1, tx2])
block_time += 1
-
- # b'0x51' is OP_TRUE
- tx1 = create_tx_with_script(block1.vtx[0], 0, script_sig=b'\x51', amount=50 * COIN)
- tx2 = create_tx_with_script(tx1, 0, script_sig=b'\x51', amount=50 * COIN)
-
- block2.vtx.extend([tx1, tx2])
- block2.hashMerkleRoot = block2.calc_merkle_root()
block2.solve()
orig_hash = block2.sha256
block2_orig = copy.deepcopy(block2)
@@ -99,12 +98,8 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
self.log.info("Test very broken block.")
- block3 = create_block(tip, create_coinbase(height), block_time)
+ block3 = create_block(tip, create_coinbase(height, nValue=100), block_time)
block_time += 1
- block3.vtx[0].vout[0].nValue = 100 * COIN # Too high!
- block3.vtx[0].sha256 = None
- block3.vtx[0].calc_sha256()
- block3.hashMerkleRoot = block3.calc_merkle_root()
block3.solve()
peer.send_blocks_and_test([block3], node, success=False, reject_reason='bad-cb-amount')
@@ -123,14 +118,10 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
# Complete testing of CVE-2018-17144, by checking for the inflation bug.
# Create a block that spends the output of a tx in a previous block.
- block4 = create_block(tip, create_coinbase(height), block_time)
- tx3 = create_tx_with_script(tx2, 0, script_sig=b'\x51', amount=50 * COIN)
-
- # Duplicates input
- tx3.vin.append(tx3.vin[0])
+ tx3 = create_tx_with_script(tx2, 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN)
+ tx3.vin.append(tx3.vin[0]) # Duplicates input
tx3.rehash()
- block4.vtx.append(tx3)
- block4.hashMerkleRoot = block4.calc_merkle_root()
+ block4 = create_block(tip, create_coinbase(height), block_time, txlist=[tx3])
block4.solve()
self.log.info("Test inflation by duplicating input")
peer.send_blocks_and_test([block4], node, success=False, reject_reason='bad-txns-inputs-duplicate')
@@ -140,7 +131,6 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
node.setmocktime(t)
# Set block time +1 second past max future validity
block = create_block(tip, create_coinbase(height), t + MAX_FUTURE_BLOCK_TIME + 1)
- block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
# Need force_send because the block will get rejected without a getdata otherwise
peer.send_blocks_and_test([block], node, force_send=True, success=False, reject_reason='time-too-new')
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 252844ce1f..f377fbaaa6 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -232,7 +232,6 @@ class SegWitTest(BitcoinTestFramework):
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 = 4
block.rehash()
return block
diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py
index a7e240dcfa..f0abbc7d8b 100755
--- a/test/functional/p2p_timeouts.py
+++ b/test/functional/p2p_timeouts.py
@@ -1,16 +1,15 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-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 various net timeouts.
-- Create three bitcoind nodes:
+- Create three peers:
no_verack_node - we never send a verack in response to their version
no_version_node - we never send a version (only a ping)
no_send_node - we never send any P2P message.
-- Start all three nodes
- Wait 1 second
- Assert that we're connected
- Send a ping to no_verack_node and no_version_node
@@ -21,12 +20,12 @@
- Assert that we're no longer connected (timeout to receive version/verack is 3 seconds)
"""
-from time import sleep
-
from test_framework.messages import msg_ping
from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
+import time
+
class TestP2PConn(P2PInterface):
def on_version(self, message):
@@ -41,17 +40,27 @@ class TimeoutsTest(BitcoinTestFramework):
# set timeout to receive version/verack to 3 seconds
self.extra_args = [["-peertimeout=3"]]
+ def mock_forward(self, delta):
+ self.mock_time += delta
+ self.nodes[0].setmocktime(self.mock_time)
+
def run_test(self):
- # Setup the p2p connections
- no_verack_node = self.nodes[0].add_p2p_connection(TestP2PConn(), wait_for_verack=False)
- no_version_node = self.nodes[0].add_p2p_connection(TestP2PConn(), send_version=False, wait_for_verack=False)
- no_send_node = self.nodes[0].add_p2p_connection(TestP2PConn(), send_version=False, wait_for_verack=False)
+ self.mock_time = int(time.time())
+ self.mock_forward(0)
+
+ # Setup the p2p connections, making sure the connections are established before the mocktime is bumped
+ with self.nodes[0].assert_debug_log(['Added connection peer=0']):
+ no_verack_node = self.nodes[0].add_p2p_connection(TestP2PConn(), wait_for_verack=False)
+ with self.nodes[0].assert_debug_log(['Added connection peer=1']):
+ no_version_node = self.nodes[0].add_p2p_connection(TestP2PConn(), send_version=False, wait_for_verack=False)
+ with self.nodes[0].assert_debug_log(['Added connection peer=2']):
+ no_send_node = self.nodes[0].add_p2p_connection(TestP2PConn(), send_version=False, wait_for_verack=False)
# Wait until we got the verack in response to the version. Though, don't wait for the other node to receive the
# verack, since we never sent one
no_verack_node.wait_for_verack()
- sleep(1)
+ self.mock_forward(1)
assert no_verack_node.is_connected
assert no_version_node.is_connected
@@ -62,7 +71,7 @@ class TimeoutsTest(BitcoinTestFramework):
with self.nodes[0].assert_debug_log(['non-version message before version handshake. Message "ping" from peer=1']):
no_version_node.send_message(msg_ping())
- sleep(1)
+ self.mock_forward(1)
assert "version" in no_verack_node.last_message
@@ -80,14 +89,10 @@ class TimeoutsTest(BitcoinTestFramework):
]
with self.nodes[0].assert_debug_log(expected_msgs=expected_timeout_logs):
- sleep(3)
- # By now, we waited a total of 5 seconds. Off-by-two for two
- # reasons:
- # * The internal precision is one second
- # * Account for network delay
- assert not no_verack_node.is_connected
- assert not no_version_node.is_connected
- assert not no_send_node.is_connected
+ self.mock_forward(2)
+ no_verack_node.wait_for_disconnect(timeout=1)
+ no_version_node.wait_for_disconnect(timeout=1)
+ no_send_node.wait_for_disconnect(timeout=1)
if __name__ == '__main__':
diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py
index 3b02a1c61f..9c4e1dd1b1 100755
--- a/test/functional/p2p_unrequested_blocks.py
+++ b/test/functional/p2p_unrequested_blocks.py
@@ -225,10 +225,9 @@ class AcceptBlockTest(BitcoinTestFramework):
block_289f.solve()
block_290f = create_block(block_289f.sha256, create_coinbase(290), block_289f.nTime+1)
block_290f.solve()
- block_291 = create_block(block_290f.sha256, create_coinbase(291), block_290f.nTime+1)
# block_291 spends a coinbase below maturity!
- block_291.vtx.append(create_tx_with_script(block_290f.vtx[0], 0, script_sig=b"42", amount=1))
- block_291.hashMerkleRoot = block_291.calc_merkle_root()
+ tx_to_add = create_tx_with_script(block_290f.vtx[0], 0, script_sig=b"42", amount=1)
+ block_291 = create_block(block_290f.sha256, create_coinbase(291), block_290f.nTime+1, txlist=[tx_to_add])
block_291.solve()
block_292 = create_block(block_291.sha256, create_coinbase(292), block_291.nTime+1)
block_292.solve()
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index 4be9616345..4dd4899f74 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -26,9 +26,10 @@ import os
import subprocess
from test_framework.blocktools import (
+ MAX_FUTURE_BLOCK_TIME,
+ TIME_GENESIS_BLOCK,
create_block,
create_coinbase,
- TIME_GENESIS_BLOCK,
)
from test_framework.messages import (
CBlockHeader,
@@ -53,6 +54,7 @@ from test_framework.wallet import MiniWallet
HEIGHT = 200 # blocks mined
TIME_RANGE_STEP = 600 # ten-minute steps
TIME_RANGE_MTP = TIME_GENESIS_BLOCK + (HEIGHT - 6) * TIME_RANGE_STEP
+TIME_RANGE_TIP = TIME_GENESIS_BLOCK + (HEIGHT - 1) * TIME_RANGE_STEP
TIME_RANGE_END = TIME_GENESIS_BLOCK + HEIGHT * TIME_RANGE_STEP
@@ -65,6 +67,7 @@ class BlockchainTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
self.mine_chain()
+ self._test_max_future_block_time()
self.restart_node(0, extra_args=['-stopatheight=207', '-prune=1']) # Set extra args with pruning after rescan is complete
self._test_getblockchaininfo()
@@ -85,6 +88,19 @@ class BlockchainTest(BitcoinTestFramework):
self.generate(self.wallet, 1)
assert_equal(self.nodes[0].getblockchaininfo()['blocks'], HEIGHT)
+ def _test_max_future_block_time(self):
+ self.stop_node(0)
+ self.log.info("A block tip of more than MAX_FUTURE_BLOCK_TIME in the future raises an error")
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=[f"-mocktime={TIME_RANGE_TIP - MAX_FUTURE_BLOCK_TIME - 1}"],
+ expected_msg=": The block database contains a block which appears to be from the future."
+ " This may be due to your computer's date and time being set incorrectly."
+ f" Only rebuild the block database if you are sure that your computer's date and time are correct.{os.linesep}"
+ "Please restart with -reindex or -reindex-chainstate to recover.",
+ )
+ self.log.info("A block tip of MAX_FUTURE_BLOCK_TIME in the future is fine")
+ self.start_node(0, extra_args=[f"-mocktime={TIME_RANGE_TIP - MAX_FUTURE_BLOCK_TIME}"])
+
def _test_getblockchaininfo(self):
self.log.info("Test getblockchaininfo")
@@ -313,7 +329,7 @@ class BlockchainTest(BitcoinTestFramework):
assert 'muhash' not in r
# Unknown hash_type raises an error
- assert_raises_rpc_error(-8, "foohash is not a valid hash_type", node.gettxoutsetinfo, "foohash")
+ assert_raises_rpc_error(-8, "'foo hash' is not a valid hash_type", node.gettxoutsetinfo, "foo hash")
def _test_getblockheader(self):
self.log.info("Test getblockheader")
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index f56e71ae7a..1a3d14100f 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -75,13 +75,19 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
for keys in itertools.permutations([pk0, pk1, pk2]):
# Results should be the same as this legacy one
legacy_addr = node0.createmultisig(2, keys, 'legacy')['address']
- assert_equal(legacy_addr, wmulti0.addmultisigaddress(2, keys, '', 'legacy')['address'])
+ result = wmulti0.addmultisigaddress(2, keys, '', 'legacy')
+ assert_equal(legacy_addr, result['address'])
+ assert 'warnings' not in result
# Generate addresses with the segwit types. These should all make legacy addresses
- assert_equal(legacy_addr, wmulti0.createmultisig(2, keys, 'bech32')['address'])
- assert_equal(legacy_addr, wmulti0.createmultisig(2, keys, 'p2sh-segwit')['address'])
- assert_equal(legacy_addr, wmulti0.addmultisigaddress(2, keys, '', 'bech32')['address'])
- assert_equal(legacy_addr, wmulti0.addmultisigaddress(2, keys, '', 'p2sh-segwit')['address'])
+ for addr_type in ['bech32', 'p2sh-segwit']:
+ result = wmulti0.createmultisig(2, keys, addr_type)
+ assert_equal(legacy_addr, result['address'])
+ assert_equal(result['warnings'], ["Unable to make chosen address type, please ensure no uncompressed public keys are present."])
+
+ result = wmulti0.addmultisigaddress(2, keys, '', addr_type)
+ assert_equal(legacy_addr, result['address'])
+ assert_equal(result['warnings'], ["Unable to make chosen address type, please ensure no uncompressed public keys are present."])
self.log.info('Testing sortedmulti descriptors with BIP 67 test vectors')
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/rpc_bip67.json'), encoding='utf-8') as f:
diff --git a/test/functional/rpc_decodescript.py b/test/functional/rpc_decodescript.py
index 8c0f48129a..56f596d419 100755
--- a/test/functional/rpc_decodescript.py
+++ b/test/functional/rpc_decodescript.py
@@ -4,6 +4,9 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test decoding scripts via decodescript RPC command."""
+import json
+import os
+
from test_framework.messages import (
sha256,
tx_from_hex,
@@ -252,6 +255,14 @@ class DecodeScriptTest(BitcoinTestFramework):
rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])
+ def decodescript_datadriven_tests(self):
+ with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/rpc_decodescript.json'), encoding='utf-8') as f:
+ dd_tests = json.load(f)
+
+ for script, result in dd_tests:
+ rpc_result = self.nodes[0].decodescript(script)
+ assert_equal(result, rpc_result)
+
def run_test(self):
self.log.info("Test decoding of standard input scripts [scriptSig]")
self.decodescript_script_sig()
@@ -259,6 +270,8 @@ class DecodeScriptTest(BitcoinTestFramework):
self.decodescript_script_pub_key()
self.log.info("Test 'asm' script decoding of transactions")
self.decoderawtransaction_asm_sighashtype()
+ self.log.info("Data-driven tests")
+ self.decodescript_datadriven_tests()
if __name__ == '__main__':
DecodeScriptTest().main()
diff --git a/test/functional/rpc_dumptxoutset.py b/test/functional/rpc_dumptxoutset.py
index f54f600839..1721b6ffe8 100755
--- a/test/functional/rpc_dumptxoutset.py
+++ b/test/functional/rpc_dumptxoutset.py
@@ -45,6 +45,10 @@ class DumptxoutsetTest(BitcoinTestFramework):
assert_equal(
digest, '7ae82c986fa5445678d2a21453bb1c86d39e47af13da137640c2b1cf8093691c')
+ assert_equal(
+ out['txoutset_hash'], 'd4b614f476b99a6e569973bf1c0120d88b1a168076f8ce25691fb41dd1cef149')
+ assert_equal(out['nchaintx'], 101)
+
# Specifying a path to an existing file will fail.
assert_raises_rpc_error(
-8, '{} already exists'.format(FILENAME), node.dumptxoutset, FILENAME)
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 0d8117bd02..a8e6acea45 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -415,7 +415,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Create same transaction over sendtoaddress.
txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1)
- signedFee = self.nodes[0].getmempoolentry(txId)['fee']
+ signedFee = self.nodes[0].getmempoolentry(txId)['fees']['base']
# Compare fee.
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
@@ -441,7 +441,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Create same transaction over sendtoaddress.
txId = self.nodes[0].sendmany("", outputs)
- signedFee = self.nodes[0].getmempoolentry(txId)['fee']
+ signedFee = self.nodes[0].getmempoolentry(txId)['fees']['base']
# Compare fee.
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
@@ -468,7 +468,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Create same transaction over sendtoaddress.
txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)
- signedFee = self.nodes[0].getmempoolentry(txId)['fee']
+ signedFee = self.nodes[0].getmempoolentry(txId)['fees']['base']
# Compare fee.
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
@@ -512,7 +512,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Create same transaction over sendtoaddress.
txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)
- signedFee = self.nodes[0].getmempoolentry(txId)['fee']
+ signedFee = self.nodes[0].getmempoolentry(txId)['fees']['base']
# Compare fee.
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
@@ -644,7 +644,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Create same transaction over sendtoaddress.
txId = self.nodes[1].sendmany("", outputs)
- signedFee = self.nodes[1].getmempoolentry(txId)['fee']
+ signedFee = self.nodes[1].getmempoolentry(txId)['fees']['base']
# Compare fee.
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
diff --git a/test/functional/rpc_generate.py b/test/functional/rpc_generate.py
index e55f2e6d12..47d7814da3 100755
--- a/test/functional/rpc_generate.py
+++ b/test/functional/rpc_generate.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test generate RPC."""
@@ -17,9 +17,9 @@ class RPCGenerateTest(BitcoinTestFramework):
def run_test(self):
message = (
- "generate\n"
+ "generate\n\n"
"has been replaced by the -generate "
- "cli option. Refer to -help for more information."
+ "cli option. Refer to -help for more information.\n"
)
self.log.info("Test rpc generate raises with message to use cli option")
diff --git a/test/functional/rpc_generateblock.py b/test/functional/rpc_generateblock.py
index 4dc5c63ff3..7eeb745817 100755
--- a/test/functional/rpc_generateblock.py
+++ b/test/functional/rpc_generateblock.py
@@ -6,6 +6,7 @@
'''
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.wallet import MiniWallet
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
@@ -16,14 +17,13 @@ class GenerateBlockTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def run_test(self):
node = self.nodes[0]
+ miniwallet = MiniWallet(node)
+ miniwallet.rescan_utxos()
self.log.info('Generate an empty block to address')
- address = node.getnewaddress()
+ address = miniwallet.get_address()
hash = self.generateblock(node, output=address, transactions=[])['hash']
block = node.getblock(blockhash=hash, verbose=2)
assert_equal(len(block['tx']), 1)
@@ -51,37 +51,31 @@ class GenerateBlockTest(BitcoinTestFramework):
assert_equal(len(block['tx']), 1)
assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['address'], combo_address)
- # Generate 110 blocks to spend
- self.generatetoaddress(node, 110, address)
-
# Generate some extra mempool transactions to verify they don't get mined
for _ in range(10):
- node.sendtoaddress(address, 0.001)
+ miniwallet.send_self_transfer(from_node=node)
self.log.info('Generate block with txid')
- txid = node.sendtoaddress(address, 1)
+ txid = miniwallet.send_self_transfer(from_node=node)['txid']
hash = self.generateblock(node, address, [txid])['hash']
block = node.getblock(hash, 1)
assert_equal(len(block['tx']), 2)
assert_equal(block['tx'][1], txid)
self.log.info('Generate block with raw tx')
- utxos = node.listunspent(addresses=[address])
- raw = node.createrawtransaction([{'txid':utxos[0]['txid'], 'vout':utxos[0]['vout']}],[{address:1}])
- signed_raw = node.signrawtransactionwithwallet(raw)['hex']
- hash = self.generateblock(node, address, [signed_raw])['hash']
+ rawtx = miniwallet.create_self_transfer()['hex']
+ hash = self.generateblock(node, address, [rawtx])['hash']
+
block = node.getblock(hash, 1)
assert_equal(len(block['tx']), 2)
txid = block['tx'][1]
- assert_equal(node.gettransaction(txid)['hex'], signed_raw)
+ assert_equal(node.getrawtransaction(txid=txid, verbose=False, blockhash=hash), rawtx)
self.log.info('Fail to generate block with out of order txs')
- raw1 = node.createrawtransaction([{'txid':txid, 'vout':0}],[{address:0.9999}])
- signed_raw1 = node.signrawtransactionwithwallet(raw1)['hex']
- txid1 = node.sendrawtransaction(signed_raw1)
- raw2 = node.createrawtransaction([{'txid':txid1, 'vout':0}],[{address:0.999}])
- signed_raw2 = node.signrawtransactionwithwallet(raw2)['hex']
- assert_raises_rpc_error(-25, 'TestBlockValidity failed: bad-txns-inputs-missingorspent', self.generateblock, node, address, [signed_raw2, txid1])
+ txid1 = miniwallet.send_self_transfer(from_node=node)['txid']
+ utxo1 = miniwallet.get_utxo(txid=txid1)
+ rawtx2 = miniwallet.create_self_transfer(utxo_to_spend=utxo1)['hex']
+ assert_raises_rpc_error(-25, 'TestBlockValidity failed: bad-txns-inputs-missingorspent', self.generateblock, node, address, [rawtx2, txid1])
self.log.info('Fail to generate block with txid not in mempool')
missing_txid = '0000000000000000000000000000000000000000000000000000000000000000'
diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py
new file mode 100755
index 0000000000..effcebe854
--- /dev/null
+++ b/test/functional/rpc_getblockfrompeer.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020-2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test the getblockfrompeer RPC."""
+
+from test_framework.authproxy import JSONRPCException
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
+
+class GetBlockFromPeerTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 2
+
+ def setup_network(self):
+ self.setup_nodes()
+
+ def check_for_block(self, hash):
+ try:
+ self.nodes[0].getblock(hash)
+ return True
+ except JSONRPCException:
+ return False
+
+ def run_test(self):
+ self.log.info("Mine 4 blocks on Node 0")
+ self.generate(self.nodes[0], 4, sync_fun=self.no_op)
+ assert_equal(self.nodes[0].getblockcount(), 204)
+
+ self.log.info("Mine competing 3 blocks on Node 1")
+ self.generate(self.nodes[1], 3, sync_fun=self.no_op)
+ assert_equal(self.nodes[1].getblockcount(), 203)
+ short_tip = self.nodes[1].getbestblockhash()
+
+ self.log.info("Connect nodes to sync headers")
+ self.connect_nodes(0, 1)
+ self.sync_blocks()
+
+ self.log.info("Node 0 should only have the header for node 1's block 3")
+ for x in self.nodes[0].getchaintips():
+ if x['hash'] == short_tip:
+ assert_equal(x['status'], "headers-only")
+ break
+ else:
+ raise AssertionError("short tip not synced")
+ assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, short_tip)
+
+ self.log.info("Fetch block from node 1")
+ peers = self.nodes[0].getpeerinfo()
+ assert_equal(len(peers), 1)
+ peer_0_peer_1_id = peers[0]["id"]
+
+ self.log.info("Arguments must be sensible")
+ assert_raises_rpc_error(-8, "hash must be of length 64 (not 4, for '1234')", self.nodes[0].getblockfrompeer, "1234", 0)
+
+ self.log.info("We must already have the header")
+ assert_raises_rpc_error(-1, "Block header missing", self.nodes[0].getblockfrompeer, "00" * 32, 0)
+
+ self.log.info("Non-existent peer generates error")
+ assert_raises_rpc_error(-1, f"Peer nodeid {peer_0_peer_1_id + 1} does not exist", self.nodes[0].getblockfrompeer, short_tip, peer_0_peer_1_id + 1)
+
+ self.log.info("Successful fetch")
+ result = self.nodes[0].getblockfrompeer(short_tip, peer_0_peer_1_id)
+ self.wait_until(lambda: self.check_for_block(short_tip), timeout=1)
+ assert(not "warnings" in result)
+
+ self.log.info("Don't fetch blocks we already have")
+ result = self.nodes[0].getblockfrompeer(short_tip, peer_0_peer_1_id)
+ assert("warnings" in result)
+ assert_equal(result["warnings"], "Block already downloaded")
+
+if __name__ == '__main__':
+ GetBlockFromPeerTest().main()
diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py
index 8c08d2ced5..1ea1ee5659 100755
--- a/test/functional/rpc_getblockstats.py
+++ b/test/functional/rpc_getblockstats.py
@@ -142,17 +142,17 @@ class GetblockstatsTest(BitcoinTestFramework):
inv_sel_stat = 'asdfghjkl'
inv_stats = [
[inv_sel_stat],
- ['minfee' , inv_sel_stat],
+ ['minfee', inv_sel_stat],
[inv_sel_stat, 'minfee'],
['minfee', inv_sel_stat, 'maxfee'],
]
for inv_stat in inv_stats:
- assert_raises_rpc_error(-8, 'Invalid selected statistic %s' % inv_sel_stat,
+ assert_raises_rpc_error(-8, f"Invalid selected statistic '{inv_sel_stat}'",
self.nodes[0].getblockstats, hash_or_height=1, stats=inv_stat)
# Make sure we aren't always returning inv_sel_stat as the culprit stat
- assert_raises_rpc_error(-8, 'Invalid selected statistic aaa%s' % inv_sel_stat,
- self.nodes[0].getblockstats, hash_or_height=1, stats=['minfee' , 'aaa%s' % inv_sel_stat])
+ assert_raises_rpc_error(-8, f"Invalid selected statistic 'aaa{inv_sel_stat}'",
+ self.nodes[0].getblockstats, hash_or_height=1, stats=['minfee', f'aaa{inv_sel_stat}'])
# Mainchain's genesis block shouldn't be found on regtest
assert_raises_rpc_error(-5, 'Block not found', self.nodes[0].getblockstats,
hash_or_height='000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f')
diff --git a/test/functional/rpc_getdescriptorinfo.py b/test/functional/rpc_getdescriptorinfo.py
index 563f54c5e7..5e6fd66aab 100755
--- a/test/functional/rpc_getdescriptorinfo.py
+++ b/test/functional/rpc_getdescriptorinfo.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2022 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 getdescriptorinfo RPC.
@@ -30,7 +30,7 @@ class DescriptorTest(BitcoinTestFramework):
def run_test(self):
assert_raises_rpc_error(-1, 'getdescriptorinfo', self.nodes[0].getdescriptorinfo)
assert_raises_rpc_error(-3, 'Expected type string', self.nodes[0].getdescriptorinfo, 1)
- assert_raises_rpc_error(-5, 'is not a valid descriptor function', self.nodes[0].getdescriptorinfo, '')
+ assert_raises_rpc_error(-5, "'' is not a valid descriptor function", self.nodes[0].getdescriptorinfo, "")
# P2PK output with the specified public key.
self.test_desc('pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)', isrange=False, issolvable=True, hasprivatekeys=False)
diff --git a/test/functional/rpc_invalid_address_message.py b/test/functional/rpc_invalid_address_message.py
index 8f9b2c3312..fcc49d0a75 100755
--- a/test/functional/rpc_invalid_address_message.py
+++ b/test/functional/rpc_invalid_address_message.py
@@ -12,79 +12,96 @@ from test_framework.util import (
)
BECH32_VALID = 'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv'
+BECH32_VALID_CAPITALS = 'BCRT1QPLMTZKC2XHARPPZDLNPAQL78RSHJ68U33RAH7R'
+BECH32_VALID_MULTISIG = 'bcrt1qdg3myrgvzw7ml9q0ejxhlkyxm7vl9r56yzkfgvzclrf4hkpx9yfqhpsuks'
+
BECH32_INVALID_BECH32 = 'bcrt1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqdmchcc'
BECH32_INVALID_BECH32M = 'bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7k35mrzd'
BECH32_INVALID_VERSION = 'bcrt130xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqynjegk'
BECH32_INVALID_SIZE = 'bcrt1s0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav25430mtr'
BECH32_INVALID_V0_SIZE = 'bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kqqq5k3my'
BECH32_INVALID_PREFIX = 'bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx'
+BECH32_TOO_LONG = 'bcrt1q049edschfnwystcqnsvyfpj23mpsg3jcedq9xv049edschfnwystcqnsvyfpj23mpsg3jcedq9xv049edschfnwystcqnsvyfpj23m'
+BECH32_ONE_ERROR = 'bcrt1q049edschfnwystcqnsvyfpj23mpsg3jcedq9xv'
+BECH32_ONE_ERROR_CAPITALS = 'BCRT1QPLMTZKC2XHARPPZDLNPAQL78RSHJ68U32RAH7R'
+BECH32_TWO_ERRORS = 'bcrt1qax9suht3qv95sw33xavx8crpxduefdrsvgsklu' # should be bcrt1qax9suht3qv95sw33wavx8crpxduefdrsvgsklx
+BECH32_NO_SEPARATOR = 'bcrtq049ldschfnwystcqnsvyfpj23mpsg3jcedq9xv'
+BECH32_INVALID_CHAR = 'bcrt1q04oldschfnwystcqnsvyfpj23mpsg3jcedq9xv'
+BECH32_MULTISIG_TWO_ERRORS = 'bcrt1qdg3myrgvzw7ml8q0ejxhlkyxn7vl9r56yzkfgvzclrf4hkpx9yfqhpsuks'
+BECH32_WRONG_VERSION = 'bcrt1ptmp74ayg7p24uslctssvjm06q5phz4yrxucgnv'
BASE58_VALID = 'mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn'
BASE58_INVALID_PREFIX = '17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem'
+BASE58_INVALID_CHECKSUM = 'mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJJfn'
+BASE58_INVALID_LENGTH = '2VKf7XKMrp4bVNVmuRbyCewkP8FhGLP2E54LHDPakr9Sq5mtU2'
INVALID_ADDRESS = 'asfah14i8fajz0123f'
+INVALID_ADDRESS_2 = '1q049ldschfnwystcqnsvyfpj23mpsg3jcedq9xv'
class InvalidAddressErrorMessageTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
- def test_validateaddress(self):
- node = self.nodes[0]
-
- # Bech32
- info = node.validateaddress(BECH32_INVALID_SIZE)
- assert not info['isvalid']
- assert_equal(info['error'], 'Invalid Bech32 address data size')
-
- info = node.validateaddress(BECH32_INVALID_PREFIX)
- assert not info['isvalid']
- assert_equal(info['error'], 'Invalid prefix for Bech32 address')
-
- info = node.validateaddress(BECH32_INVALID_BECH32)
- assert not info['isvalid']
- assert_equal(info['error'], 'Version 1+ witness address must use Bech32m checksum')
-
- info = node.validateaddress(BECH32_INVALID_BECH32M)
- assert not info['isvalid']
- assert_equal(info['error'], 'Version 0 witness address must use Bech32 checksum')
-
- info = node.validateaddress(BECH32_INVALID_V0_SIZE)
- assert not info['isvalid']
- assert_equal(info['error'], 'Invalid Bech32 v0 address data size')
-
- info = node.validateaddress(BECH32_VALID)
+ def check_valid(self, addr):
+ info = self.nodes[0].validateaddress(addr)
assert info['isvalid']
assert 'error' not in info
+ assert 'error_locations' not in info
- info = node.validateaddress(BECH32_INVALID_VERSION)
- assert not info['isvalid']
- assert_equal(info['error'], 'Invalid Bech32 address witness version')
-
- # Base58
- info = node.validateaddress(BASE58_INVALID_PREFIX)
- assert not info['isvalid']
- assert_equal(info['error'], 'Invalid prefix for Base58-encoded address')
+ def check_invalid(self, addr, error_str, error_locations=None):
+ res = self.nodes[0].validateaddress(addr)
+ assert not res['isvalid']
+ assert_equal(res['error'], error_str)
+ if error_locations:
+ assert_equal(res['error_locations'], error_locations)
+ else:
+ assert_equal(res['error_locations'], [])
- info = node.validateaddress(BASE58_VALID)
- assert info['isvalid']
- assert 'error' not in info
+ def test_validateaddress(self):
+ # Invalid Bech32
+ self.check_invalid(BECH32_INVALID_SIZE, 'Invalid Bech32 address data size')
+ self.check_invalid(BECH32_INVALID_PREFIX, 'Not a valid Bech32 or Base58 encoding')
+ self.check_invalid(BECH32_INVALID_BECH32, 'Version 1+ witness address must use Bech32m checksum')
+ self.check_invalid(BECH32_INVALID_BECH32M, 'Version 0 witness address must use Bech32 checksum')
+ self.check_invalid(BECH32_INVALID_VERSION, 'Invalid Bech32 address witness version')
+ self.check_invalid(BECH32_INVALID_V0_SIZE, 'Invalid Bech32 v0 address data size')
+ self.check_invalid(BECH32_TOO_LONG, 'Bech32 string too long', list(range(90, 108)))
+ self.check_invalid(BECH32_ONE_ERROR, 'Invalid Bech32 checksum', [9])
+ self.check_invalid(BECH32_TWO_ERRORS, 'Invalid Bech32 checksum', [22, 43])
+ self.check_invalid(BECH32_ONE_ERROR_CAPITALS, 'Invalid Bech32 checksum', [38])
+ self.check_invalid(BECH32_NO_SEPARATOR, 'Missing separator')
+ self.check_invalid(BECH32_INVALID_CHAR, 'Invalid Base 32 character', [8])
+ self.check_invalid(BECH32_MULTISIG_TWO_ERRORS, 'Invalid Bech32 checksum', [19, 30])
+ self.check_invalid(BECH32_WRONG_VERSION, 'Invalid Bech32 checksum', [5])
+
+ # Valid Bech32
+ self.check_valid(BECH32_VALID)
+ self.check_valid(BECH32_VALID_CAPITALS)
+ self.check_valid(BECH32_VALID_MULTISIG)
+
+ # Invalid Base58
+ self.check_invalid(BASE58_INVALID_PREFIX, 'Invalid prefix for Base58-encoded address')
+ self.check_invalid(BASE58_INVALID_CHECKSUM, 'Invalid checksum or length of Base58 address')
+ self.check_invalid(BASE58_INVALID_LENGTH, 'Invalid checksum or length of Base58 address')
+
+ # Valid Base58
+ self.check_valid(BASE58_VALID)
# Invalid address format
- info = node.validateaddress(INVALID_ADDRESS)
- assert not info['isvalid']
- assert_equal(info['error'], 'Invalid address format')
+ self.check_invalid(INVALID_ADDRESS, 'Not a valid Bech32 or Base58 encoding')
+ self.check_invalid(INVALID_ADDRESS_2, 'Not a valid Bech32 or Base58 encoding')
def test_getaddressinfo(self):
node = self.nodes[0]
assert_raises_rpc_error(-5, "Invalid Bech32 address data size", node.getaddressinfo, BECH32_INVALID_SIZE)
- assert_raises_rpc_error(-5, "Invalid prefix for Bech32 address", node.getaddressinfo, BECH32_INVALID_PREFIX)
+ assert_raises_rpc_error(-5, "Not a valid Bech32 or Base58 encoding", node.getaddressinfo, BECH32_INVALID_PREFIX)
assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", node.getaddressinfo, BASE58_INVALID_PREFIX)
- assert_raises_rpc_error(-5, "Invalid address format", node.getaddressinfo, INVALID_ADDRESS)
+ assert_raises_rpc_error(-5, "Not a valid Bech32 or Base58 encoding", node.getaddressinfo, INVALID_ADDRESS)
def run_test(self):
self.test_validateaddress()
diff --git a/test/functional/rpc_mempool_entry_fee_fields_deprecation.py b/test/functional/rpc_mempool_entry_fee_fields_deprecation.py
new file mode 100755
index 0000000000..82761ff7c8
--- /dev/null
+++ b/test/functional/rpc_mempool_entry_fee_fields_deprecation.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test deprecation of fee fields from top level mempool entry object"""
+
+from test_framework.blocktools import COIN
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+from test_framework.wallet import MiniWallet
+
+
+def assertions_helper(new_object, deprecated_object, deprecated_fields):
+ for field in deprecated_fields:
+ assert field in deprecated_object
+ assert field not in new_object
+
+
+class MempoolFeeFieldsDeprecationTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 2
+ self.extra_args = [[], ["-deprecatedrpc=fees"]]
+
+ def run_test(self):
+ # we get spendable outputs from the premined chain starting
+ # at block 76. see BitcoinTestFramework._initialize_chain() for details
+ self.wallet = MiniWallet(self.nodes[0])
+ self.wallet.rescan_utxos()
+
+ # we create the tx on the first node and wait until it syncs to node_deprecated
+ # thus, any differences must be coming from getmempoolentry or getrawmempool
+ tx = self.wallet.send_self_transfer(from_node=self.nodes[0])
+ self.nodes[1].sendrawtransaction(tx["hex"])
+
+ deprecated_fields = ["ancestorfees", "descendantfees", "modifiedfee", "fee"]
+ self.test_getmempoolentry(tx["txid"], deprecated_fields)
+ self.test_getrawmempool(tx["txid"], deprecated_fields)
+ self.test_deprecated_fields_match(tx["txid"])
+
+ def test_getmempoolentry(self, txid, deprecated_fields):
+
+ self.log.info("Test getmempoolentry rpc")
+ entry = self.nodes[0].getmempoolentry(txid)
+ deprecated_entry = self.nodes[1].getmempoolentry(txid)
+ assertions_helper(entry, deprecated_entry, deprecated_fields)
+
+ def test_getrawmempool(self, txid, deprecated_fields):
+
+ self.log.info("Test getrawmempool rpc")
+ entry = self.nodes[0].getrawmempool(verbose=True)[txid]
+ deprecated_entry = self.nodes[1].getrawmempool(verbose=True)[txid]
+ assertions_helper(entry, deprecated_entry, deprecated_fields)
+
+ def test_deprecated_fields_match(self, txid):
+
+ self.log.info("Test deprecated fee fields match new fees object")
+ entry = self.nodes[0].getmempoolentry(txid)
+ deprecated_entry = self.nodes[1].getmempoolentry(txid)
+
+ assert_equal(deprecated_entry["fee"], entry["fees"]["base"])
+ assert_equal(deprecated_entry["modifiedfee"], entry["fees"]["modified"])
+ assert_equal(deprecated_entry["descendantfees"], entry["fees"]["descendant"] * COIN)
+ assert_equal(deprecated_entry["ancestorfees"], entry["fees"]["ancestor"] * COIN)
+
+
+if __name__ == "__main__":
+ MempoolFeeFieldsDeprecationTest().main()
diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py
index b3abd9d236..2f1796d7cc 100755
--- a/test/functional/rpc_misc.py
+++ b/test/functional/rpc_misc.py
@@ -50,7 +50,7 @@ class RpcMiscTest(BitcoinTestFramework):
assert_equal(tree.tag, 'malloc')
except JSONRPCException:
self.log.info('getmemoryinfo(mode="mallocinfo") not available')
- assert_raises_rpc_error(-8, 'mallocinfo is only available when compiled with glibc 2.10+', node.getmemoryinfo, mode="mallocinfo")
+ assert_raises_rpc_error(-8, 'mallocinfo mode not available', node.getmemoryinfo, mode="mallocinfo")
assert_raises_rpc_error(-8, "unknown mode foobar", node.getmemoryinfo, mode="foobar")
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 9b00eab346..153a201e95 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -31,7 +31,7 @@ class PSBTTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 3
self.extra_args = [
- ["-walletrbf=1"],
+ ["-walletrbf=1", "-addresstype=bech32", "-changetype=bech32"], #TODO: Remove address type restrictions once taproot has psbt extensions
["-walletrbf=0", "-changetype=legacy"],
[]
]
@@ -120,7 +120,9 @@ class PSBTTest(BitcoinTestFramework):
self.nodes[0].walletpassphrase(passphrase="password", timeout=1000000)
# Sign the transaction and send
- signed_tx = self.nodes[0].walletprocesspsbt(psbtx)['psbt']
+ signed_tx = self.nodes[0].walletprocesspsbt(psbt=psbtx, finalize=False)['psbt']
+ finalized_tx = self.nodes[0].walletprocesspsbt(psbt=psbtx, finalize=True)['psbt']
+ assert signed_tx != finalized_tx
final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex']
self.nodes[0].sendrawtransaction(final_tx)
@@ -455,7 +457,7 @@ class PSBTTest(BitcoinTestFramework):
wrpc = self.nodes[2].get_wallet_rpc("wallet{}".format(i))
for key in signer['privkeys']:
wrpc.importprivkey(key)
- signed_tx = wrpc.walletprocesspsbt(signer['psbt'])['psbt']
+ signed_tx = wrpc.walletprocesspsbt(signer['psbt'], True, "ALL")['psbt']
assert_equal(signed_tx, signer['result'])
# Combiner test
diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py
index 8703bfab8e..acb6d3ea4a 100755
--- a/test/functional/rpc_scantxoutset.py
+++ b/test/functional/rpc_scantxoutset.py
@@ -3,62 +3,60 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the scantxoutset rpc call."""
+from test_framework.messages import COIN
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
+from test_framework.wallet import (
+ MiniWallet,
+ address_to_scriptpubkey,
+ getnewdestination,
+)
from decimal import Decimal
-import shutil
-import os
+
def descriptors(out):
return sorted(u['desc'] for u in out['unspents'])
+
class ScantxoutsetTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.setup_clean_chain = True
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
+ def sendtodestination(self, destination, amount):
+ # interpret strings as addresses, assume scriptPubKey otherwise
+ if isinstance(destination, str):
+ destination = address_to_scriptpubkey(destination)
+ self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=destination, amount=int(COIN * amount))
def run_test(self):
- self.log.info("Mining blocks...")
- self.generate(self.nodes[0], 110)
-
- addr_P2SH_SEGWIT = self.nodes[0].getnewaddress("", "p2sh-segwit")
- pubk1 = self.nodes[0].getaddressinfo(addr_P2SH_SEGWIT)['pubkey']
- addr_LEGACY = self.nodes[0].getnewaddress("", "legacy")
- pubk2 = self.nodes[0].getaddressinfo(addr_LEGACY)['pubkey']
- addr_BECH32 = self.nodes[0].getnewaddress("", "bech32")
- pubk3 = self.nodes[0].getaddressinfo(addr_BECH32)['pubkey']
- self.nodes[0].sendtoaddress(addr_P2SH_SEGWIT, 0.001)
- self.nodes[0].sendtoaddress(addr_LEGACY, 0.002)
- self.nodes[0].sendtoaddress(addr_BECH32, 0.004)
+ self.wallet = MiniWallet(self.nodes[0])
+ self.wallet.rescan_utxos()
- #send to child keys of tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK
- self.nodes[0].sendtoaddress("mkHV1C6JLheLoUSSZYk7x3FH5tnx9bu7yc", 0.008) # (m/0'/0'/0')
- self.nodes[0].sendtoaddress("mipUSRmJAj2KrjSvsPQtnP8ynUon7FhpCR", 0.016) # (m/0'/0'/1')
- self.nodes[0].sendtoaddress("n37dAGe6Mq1HGM9t4b6rFEEsDGq7Fcgfqg", 0.032) # (m/0'/0'/1500')
- self.nodes[0].sendtoaddress("mqS9Rpg8nNLAzxFExsgFLCnzHBsoQ3PRM6", 0.064) # (m/0'/0'/0)
- self.nodes[0].sendtoaddress("mnTg5gVWr3rbhHaKjJv7EEEc76ZqHgSj4S", 0.128) # (m/0'/0'/1)
- self.nodes[0].sendtoaddress("mketCd6B9U9Uee1iCsppDJJBHfvi6U6ukC", 0.256) # (m/0'/0'/1500)
- self.nodes[0].sendtoaddress("mj8zFzrbBcdaWXowCQ1oPZ4qioBVzLzAp7", 0.512) # (m/1/1/0')
- self.nodes[0].sendtoaddress("mfnKpKQEftniaoE1iXuMMePQU3PUpcNisA", 1.024) # (m/1/1/1')
- self.nodes[0].sendtoaddress("mou6cB1kaP1nNJM1sryW6YRwnd4shTbXYQ", 2.048) # (m/1/1/1500')
- self.nodes[0].sendtoaddress("mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", 4.096) # (m/1/1/0)
- self.nodes[0].sendtoaddress("mxp7w7j8S1Aq6L8StS2PqVvtt4HGxXEvdy", 8.192) # (m/1/1/1)
- self.nodes[0].sendtoaddress("mpQ8rokAhp1TAtJQR6F6TaUmjAWkAWYYBq", 16.384) # (m/1/1/1500)
+ self.log.info("Create UTXOs...")
+ pubk1, spk_P2SH_SEGWIT, addr_P2SH_SEGWIT = getnewdestination("p2sh-segwit")
+ pubk2, spk_LEGACY, addr_LEGACY = getnewdestination("legacy")
+ pubk3, spk_BECH32, addr_BECH32 = getnewdestination("bech32")
+ self.sendtodestination(spk_P2SH_SEGWIT, 0.001)
+ self.sendtodestination(spk_LEGACY, 0.002)
+ self.sendtodestination(spk_BECH32, 0.004)
+ #send to child keys of tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK
+ self.sendtodestination("mkHV1C6JLheLoUSSZYk7x3FH5tnx9bu7yc", 0.008) # (m/0'/0'/0')
+ self.sendtodestination("mipUSRmJAj2KrjSvsPQtnP8ynUon7FhpCR", 0.016) # (m/0'/0'/1')
+ self.sendtodestination("n37dAGe6Mq1HGM9t4b6rFEEsDGq7Fcgfqg", 0.032) # (m/0'/0'/1500')
+ self.sendtodestination("mqS9Rpg8nNLAzxFExsgFLCnzHBsoQ3PRM6", 0.064) # (m/0'/0'/0)
+ self.sendtodestination("mnTg5gVWr3rbhHaKjJv7EEEc76ZqHgSj4S", 0.128) # (m/0'/0'/1)
+ self.sendtodestination("mketCd6B9U9Uee1iCsppDJJBHfvi6U6ukC", 0.256) # (m/0'/0'/1500)
+ self.sendtodestination("mj8zFzrbBcdaWXowCQ1oPZ4qioBVzLzAp7", 0.512) # (m/1/1/0')
+ self.sendtodestination("mfnKpKQEftniaoE1iXuMMePQU3PUpcNisA", 1.024) # (m/1/1/1')
+ self.sendtodestination("mou6cB1kaP1nNJM1sryW6YRwnd4shTbXYQ", 2.048) # (m/1/1/1500')
+ self.sendtodestination("mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", 4.096) # (m/1/1/0)
+ self.sendtodestination("mxp7w7j8S1Aq6L8StS2PqVvtt4HGxXEvdy", 8.192) # (m/1/1/1)
+ self.sendtodestination("mpQ8rokAhp1TAtJQR6F6TaUmjAWkAWYYBq", 16.384) # (m/1/1/1500)
self.generate(self.nodes[0], 1)
- self.log.info("Stop node, remove wallet, mine again some blocks...")
- self.stop_node(0)
- shutil.rmtree(os.path.join(self.nodes[0].datadir, self.chain, 'wallets'))
- self.start_node(0, ['-nowallet'])
- self.import_deterministic_coinbase_privkeys()
- self.generate(self.nodes[0], 110)
-
scan = self.nodes[0].scantxoutset("start", [])
info = self.nodes[0].gettxoutsetinfo()
assert_equal(scan['success'], True)
@@ -66,56 +64,55 @@ class ScantxoutsetTest(BitcoinTestFramework):
assert_equal(scan['txouts'], info['txouts'])
assert_equal(scan['bestblock'], info['bestblock'])
- self.restart_node(0, ['-nowallet'])
self.log.info("Test if we have found the non HD unspent outputs.")
- assert_equal(self.nodes[0].scantxoutset("start", [ "pkh(" + pubk1 + ")", "pkh(" + pubk2 + ")", "pkh(" + pubk3 + ")"])['total_amount'], Decimal("0.002"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "wpkh(" + pubk1 + ")", "wpkh(" + pubk2 + ")", "wpkh(" + pubk3 + ")"])['total_amount'], Decimal("0.004"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "sh(wpkh(" + pubk1 + "))", "sh(wpkh(" + pubk2 + "))", "sh(wpkh(" + pubk3 + "))"])['total_amount'], Decimal("0.001"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(" + pubk1 + ")", "combo(" + pubk2 + ")", "combo(" + pubk3 + ")"])['total_amount'], Decimal("0.007"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "addr(" + addr_P2SH_SEGWIT + ")", "addr(" + addr_LEGACY + ")", "addr(" + addr_BECH32 + ")"])['total_amount'], Decimal("0.007"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "addr(" + addr_P2SH_SEGWIT + ")", "addr(" + addr_LEGACY + ")", "combo(" + pubk3 + ")"])['total_amount'], Decimal("0.007"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["pkh(" + pubk1.hex() + ")", "pkh(" + pubk2.hex() + ")", "pkh(" + pubk3.hex() + ")"])['total_amount'], Decimal("0.002"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["wpkh(" + pubk1.hex() + ")", "wpkh(" + pubk2.hex() + ")", "wpkh(" + pubk3.hex() + ")"])['total_amount'], Decimal("0.004"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["sh(wpkh(" + pubk1.hex() + "))", "sh(wpkh(" + pubk2.hex() + "))", "sh(wpkh(" + pubk3.hex() + "))"])['total_amount'], Decimal("0.001"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(" + pubk1.hex() + ")", "combo(" + pubk2.hex() + ")", "combo(" + pubk3.hex() + ")"])['total_amount'], Decimal("0.007"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["addr(" + addr_P2SH_SEGWIT + ")", "addr(" + addr_LEGACY + ")", "addr(" + addr_BECH32 + ")"])['total_amount'], Decimal("0.007"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["addr(" + addr_P2SH_SEGWIT + ")", "addr(" + addr_LEGACY + ")", "combo(" + pubk3.hex() + ")"])['total_amount'], Decimal("0.007"))
self.log.info("Test range validation.")
- assert_raises_rpc_error(-8, "End of range is too high", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": -1}])
- assert_raises_rpc_error(-8, "Range should be greater or equal than 0", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [-1, 10]}])
- assert_raises_rpc_error(-8, "End of range is too high", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]}])
- assert_raises_rpc_error(-8, "Range specified as [begin,end] must not have begin after end", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [2, 1]}])
- assert_raises_rpc_error(-8, "Range is too large", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [0, 1000001]}])
+ assert_raises_rpc_error(-8, "End of range is too high", self.nodes[0].scantxoutset, "start", [{"desc": "desc", "range": -1}])
+ assert_raises_rpc_error(-8, "Range should be greater or equal than 0", self.nodes[0].scantxoutset, "start", [{"desc": "desc", "range": [-1, 10]}])
+ assert_raises_rpc_error(-8, "End of range is too high", self.nodes[0].scantxoutset, "start", [{"desc": "desc", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]}])
+ assert_raises_rpc_error(-8, "Range specified as [begin,end] must not have begin after end", self.nodes[0].scantxoutset, "start", [{"desc": "desc", "range": [2, 1]}])
+ assert_raises_rpc_error(-8, "Range is too large", self.nodes[0].scantxoutset, "start", [{"desc": "desc", "range": [0, 1000001]}])
self.log.info("Test extended key derivation.")
# Run various scans, and verify that the sum of the amounts of the matches corresponds to the expected subset.
# Note that all amounts in the UTXO set are powers of 2 multiplied by 0.001 BTC, so each amounts uniquely identifies a subset.
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/0h)"])['total_amount'], Decimal("0.008"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0'/1h)"])['total_amount'], Decimal("0.016"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/1500')"])['total_amount'], Decimal("0.032"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0h/0)"])['total_amount'], Decimal("0.064"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/1)"])['total_amount'], Decimal("0.128"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/1500)"])['total_amount'], Decimal("0.256"))
- assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/*h)", "range": 1499}])['total_amount'], Decimal("0.024"))
- assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0'/*h)", "range": 1500}])['total_amount'], Decimal("0.056"))
- assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/*)", "range": 1499}])['total_amount'], Decimal("0.192"))
- assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/*)", "range": 1500}])['total_amount'], Decimal("0.448"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0')"])['total_amount'], Decimal("0.512"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1')"])['total_amount'], Decimal("1.024"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1500h)"])['total_amount'], Decimal("2.048"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"])['total_amount'], Decimal("4.096"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1)"])['total_amount'], Decimal("8.192"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1500)"])['total_amount'], Decimal("16.384"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0)"])['total_amount'], Decimal("4.096"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo([abcdef88/1/2'/3/4h]tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1)"])['total_amount'], Decimal("8.192"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1500)"])['total_amount'], Decimal("16.384"))
- assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*')", "range": 1499}])['total_amount'], Decimal("1.536"))
- assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*')", "range": 1500}])['total_amount'], Decimal("3.584"))
- assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", "range": 1499}])['total_amount'], Decimal("12.288"))
- assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", "range": 1500}])['total_amount'], Decimal("28.672"))
- assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1499}])['total_amount'], Decimal("12.288"))
- assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])['total_amount'], Decimal("28.672"))
- assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": [1500,1500]}])['total_amount'], Decimal("16.384"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/0h)"])['total_amount'], Decimal("0.008"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0'/1h)"])['total_amount'], Decimal("0.016"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/1500')"])['total_amount'], Decimal("0.032"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0h/0)"])['total_amount'], Decimal("0.064"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/1)"])['total_amount'], Decimal("0.128"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/1500)"])['total_amount'], Decimal("0.256"))
+ assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/*h)", "range": 1499}])['total_amount'], Decimal("0.024"))
+ assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0'/*h)", "range": 1500}])['total_amount'], Decimal("0.056"))
+ assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/*)", "range": 1499}])['total_amount'], Decimal("0.192"))
+ assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/*)", "range": 1500}])['total_amount'], Decimal("0.448"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0')"])['total_amount'], Decimal("0.512"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1')"])['total_amount'], Decimal("1.024"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1500h)"])['total_amount'], Decimal("2.048"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"])['total_amount'], Decimal("4.096"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1)"])['total_amount'], Decimal("8.192"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1500)"])['total_amount'], Decimal("16.384"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0)"])['total_amount'], Decimal("4.096"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo([abcdef88/1/2'/3/4h]tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1)"])['total_amount'], Decimal("8.192"))
+ assert_equal(self.nodes[0].scantxoutset("start", ["combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1500)"])['total_amount'], Decimal("16.384"))
+ assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*')", "range": 1499}])['total_amount'], Decimal("1.536"))
+ assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*')", "range": 1500}])['total_amount'], Decimal("3.584"))
+ assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", "range": 1499}])['total_amount'], Decimal("12.288"))
+ assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", "range": 1500}])['total_amount'], Decimal("28.672"))
+ assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1499}])['total_amount'], Decimal("12.288"))
+ assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])['total_amount'], Decimal("28.672"))
+ assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": [1500, 1500]}])['total_amount'], Decimal("16.384"))
# Test the reported descriptors for a few matches
- assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/*)", "range": 1499}])), ["pkh([0c5f9a1e/0'/0'/0]026dbd8b2315f296d36e6b6920b1579ca75569464875c7ebe869b536a7d9503c8c)#dzxw429x", "pkh([0c5f9a1e/0'/0'/1]033e6f25d76c00bedb3a8993c7d5739ee806397f0529b1b31dda31ef890f19a60c)#43rvceed"])
- assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"])), ["pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)#cxmct4w8"])
- assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])), ['pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)#cxmct4w8', 'pkh([0c5f9a1e/1/1/1500]03832901c250025da2aebae2bfb38d5c703a57ab66ad477f9c578bfbcd78abca6f)#vchwd07g', 'pkh([0c5f9a1e/1/1/1]030d820fc9e8211c4169be8530efbc632775d8286167afd178caaf1089b77daba7)#z2t3ypsa'])
+ assert_equal(descriptors(self.nodes[0].scantxoutset("start", [{"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/*)", "range": 1499}])), ["pkh([0c5f9a1e/0'/0'/0]026dbd8b2315f296d36e6b6920b1579ca75569464875c7ebe869b536a7d9503c8c)#dzxw429x", "pkh([0c5f9a1e/0'/0'/1]033e6f25d76c00bedb3a8993c7d5739ee806397f0529b1b31dda31ef890f19a60c)#43rvceed"])
+ assert_equal(descriptors(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"])), ["pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)#cxmct4w8"])
+ assert_equal(descriptors(self.nodes[0].scantxoutset("start", [{"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])), ['pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)#cxmct4w8', 'pkh([0c5f9a1e/1/1/1500]03832901c250025da2aebae2bfb38d5c703a57ab66ad477f9c578bfbcd78abca6f)#vchwd07g', 'pkh([0c5f9a1e/1/1/1]030d820fc9e8211c4169be8530efbc632775d8286167afd178caaf1089b77daba7)#z2t3ypsa'])
# Check that status and abort don't need second arg
assert_equal(self.nodes[0].scantxoutset("status"), None)
@@ -124,5 +121,6 @@ class ScantxoutsetTest(BitcoinTestFramework):
# Check that second arg is needed for start
assert_raises_rpc_error(-1, "scanobjects argument is required for the start action", self.nodes[0].scantxoutset, "start")
-if __name__ == '__main__':
+
+if __name__ == "__main__":
ScantxoutsetTest().main()
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index eaa193e357..40fcbf7761 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -22,6 +22,7 @@ from .messages import (
CTxIn,
CTxInWitness,
CTxOut,
+ SEQUENCE_FINAL,
hash256,
ser_uint256,
tx_from_hex,
@@ -50,6 +51,8 @@ MAX_BLOCK_SIGOPS_WEIGHT = MAX_BLOCK_SIGOPS * WITNESS_SCALE_FACTOR
# Genesis block time (regtest)
TIME_GENESIS_BLOCK = 1296688602
+MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60
+
# Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
COINBASE_MATURITY = 100
@@ -126,7 +129,7 @@ def create_coinbase(height, pubkey=None, extra_output_script=None, fees=0, nValu
If extra_output_script is given, make a 0-value output to that
script. This is useful to pad block weight/sigops as needed. """
coinbase = CTransaction()
- coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), 0xffffffff))
+ coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), SEQUENCE_FINAL))
coinbaseoutput = CTxOut()
coinbaseoutput.nValue = nValue * COIN
if nValue == 50:
@@ -154,7 +157,7 @@ def create_tx_with_script(prevtx, n, script_sig=b"", *, amount, script_pub_key=C
"""
tx = CTransaction()
assert n < len(prevtx.vout)
- tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), script_sig, 0xffffffff))
+ tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), script_sig, SEQUENCE_FINAL))
tx.vout.append(CTxOut(amount, script_pub_key))
tx.calc_sha256()
return tx
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 71ac5c5bfd..f57b6e7494 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -40,6 +40,7 @@ COIN = 100000000 # 1 btc in satoshis
MAX_MONEY = 21000000 * COIN
BIP125_SEQUENCE_NUMBER = 0xfffffffd # Sequence number that is rbf-opt-in (BIP 125) and csv-opt-out (BIP 68)
+SEQUENCE_FINAL = 0xffffffff # Sequence number that disables nLockTime if set for every input of a tx
MAX_PROTOCOL_MESSAGE_LENGTH = 4000000 # Maximum length of incoming protocol messages
MAX_HEADERS_RESULTS = 2000 # Number of headers sent in one getheaders result
@@ -64,13 +65,15 @@ FILTER_TYPE_BASIC = 0
WITNESS_SCALE_FACTOR = 4
-# Serialization/deserialization tools
+
def sha256(s):
- return hashlib.new('sha256', s).digest()
+ return hashlib.sha256(s).digest()
+
def hash256(s):
return sha256(sha256(s))
+
def ser_compact_size(l):
r = b""
if l < 253:
@@ -506,7 +509,7 @@ class CTransaction:
def __init__(self, tx=None):
if tx is None:
- self.nVersion = 1
+ self.nVersion = 2
self.vin = []
self.vout = []
self.wit = CTxWitness()
diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py
index c99868de72..251d3d5eae 100755
--- a/test/functional/test_framework/p2p.py
+++ b/test/functional/test_framework/p2p.py
@@ -89,6 +89,8 @@ P2P_SERVICES = NODE_NETWORK | NODE_WITNESS
P2P_SUBVERSION = "/python-p2p-tester:0.0.3/"
# Value for relay that this test framework sends in its `version` message
P2P_VERSION_RELAY = 1
+# Delay after receiving a tx inv before requesting transactions from non-preferred peers, in seconds
+NONPREF_PEER_TX_DELAY = 2
MESSAGEMAP = {
b"addr": msg_addr,
diff --git a/test/functional/test_framework/ripemd160.py b/test/functional/test_framework/ripemd160.py
new file mode 100644
index 0000000000..12801364b4
--- /dev/null
+++ b/test/functional/test_framework/ripemd160.py
@@ -0,0 +1,130 @@
+# Copyright (c) 2021 Pieter Wuille
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test-only pure Python RIPEMD160 implementation."""
+
+import unittest
+
+# Message schedule indexes for the left path.
+ML = [
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
+ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
+ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
+ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
+]
+
+# Message schedule indexes for the right path.
+MR = [
+ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
+ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
+ 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
+ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
+ 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
+]
+
+# Rotation counts for the left path.
+RL = [
+ 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
+ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
+ 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
+ 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
+ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
+]
+
+# Rotation counts for the right path.
+RR = [
+ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
+ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
+ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
+ 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
+ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
+]
+
+# K constants for the left path.
+KL = [0, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e]
+
+# K constants for the right path.
+KR = [0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0]
+
+
+def fi(x, y, z, i):
+ """The f1, f2, f3, f4, and f5 functions from the specification."""
+ if i == 0:
+ return x ^ y ^ z
+ elif i == 1:
+ return (x & y) | (~x & z)
+ elif i == 2:
+ return (x | ~y) ^ z
+ elif i == 3:
+ return (x & z) | (y & ~z)
+ elif i == 4:
+ return x ^ (y | ~z)
+ else:
+ assert False
+
+
+def rol(x, i):
+ """Rotate the bottom 32 bits of x left by i bits."""
+ return ((x << i) | ((x & 0xffffffff) >> (32 - i))) & 0xffffffff
+
+
+def compress(h0, h1, h2, h3, h4, block):
+ """Compress state (h0, h1, h2, h3, h4) with block."""
+ # Left path variables.
+ al, bl, cl, dl, el = h0, h1, h2, h3, h4
+ # Right path variables.
+ ar, br, cr, dr, er = h0, h1, h2, h3, h4
+ # Message variables.
+ x = [int.from_bytes(block[4*i:4*(i+1)], 'little') for i in range(16)]
+
+ # Iterate over the 80 rounds of the compression.
+ for j in range(80):
+ rnd = j >> 4
+ # Perform left side of the transformation.
+ al = rol(al + fi(bl, cl, dl, rnd) + x[ML[j]] + KL[rnd], RL[j]) + el
+ al, bl, cl, dl, el = el, al, bl, rol(cl, 10), dl
+ # Perform right side of the transformation.
+ ar = rol(ar + fi(br, cr, dr, 4 - rnd) + x[MR[j]] + KR[rnd], RR[j]) + er
+ ar, br, cr, dr, er = er, ar, br, rol(cr, 10), dr
+
+ # Compose old state, left transform, and right transform into new state.
+ return h1 + cl + dr, h2 + dl + er, h3 + el + ar, h4 + al + br, h0 + bl + cr
+
+
+def ripemd160(data):
+ """Compute the RIPEMD-160 hash of data."""
+ # Initialize state.
+ state = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0)
+ # Process full 64-byte blocks in the input.
+ for b in range(len(data) >> 6):
+ state = compress(*state, data[64*b:64*(b+1)])
+ # Construct final blocks (with padding and size).
+ pad = b"\x80" + b"\x00" * ((119 - len(data)) & 63)
+ fin = data[len(data) & ~63:] + pad + (8 * len(data)).to_bytes(8, 'little')
+ # Process final blocks.
+ for b in range(len(fin) >> 6):
+ state = compress(*state, fin[64*b:64*(b+1)])
+ # Produce output.
+ return b"".join((h & 0xffffffff).to_bytes(4, 'little') for h in state)
+
+
+class TestFrameworkKey(unittest.TestCase):
+ def test_ripemd160(self):
+ """RIPEMD-160 test vectors."""
+ # See https://homes.esat.kuleuven.be/~bosselae/ripemd160.html
+ for msg, hexout in [
+ (b"", "9c1185a5c5e9fc54612808977ee8f548b2258d31"),
+ (b"a", "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"),
+ (b"abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"),
+ (b"message digest", "5d0689ef49d2fae572b881b123a85ffa21595f36"),
+ (b"abcdefghijklmnopqrstuvwxyz",
+ "f71c27109c692c1b56bbdceb5b9d2865b3708dbc"),
+ (b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ "12a053384a9c0c88e405a06c27dcf49ada62eb2b"),
+ (b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ "b0e20b6e3116640286ed3a87a5713079b21f5189"),
+ (b"1234567890" * 8, "9b752e45573d4b39f4dbd3323cab82bf63326bfb"),
+ (b"a" * 1000000, "52783243c1697bdbe16d37f97f68f08325dc1528")
+ ]:
+ self.assertEqual(ripemd160(msg).hex(), hexout)
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index 947a1f9808..7791ae5392 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -8,7 +8,6 @@ This file is modified from python-bitcoinlib.
"""
from collections import namedtuple
-import hashlib
import struct
import unittest
from typing import List, Dict
@@ -25,6 +24,8 @@ from .messages import (
uint256_from_str,
)
+from .ripemd160 import ripemd160
+
MAX_SCRIPT_ELEMENT_SIZE = 520
LOCKTIME_THRESHOLD = 500000000
ANNEX_TAG = 0x50
@@ -32,7 +33,7 @@ ANNEX_TAG = 0x50
LEAF_VERSION_TAPSCRIPT = 0xc0
def hash160(s):
- return hashlib.new('ripemd160', sha256(s)).digest()
+ return ripemd160(sha256(s))
def bn2vch(v):
"""Convert number to bitcoin-specific little endian format."""
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index a781da2720..8f75255caf 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -431,7 +431,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
n = self.nodes[node]
if wallet_name is not None:
n.createwallet(wallet_name=wallet_name, descriptors=self.options.descriptors, load_on_startup=True)
- n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase')
+ n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase', rescan=True)
def run_test(self):
"""Tests must override this method to define test logic"""
@@ -886,6 +886,14 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
"""Checks whether the wallet module was compiled."""
return self.config["components"].getboolean("ENABLE_WALLET")
+ def is_specified_wallet_compiled(self):
+ """Checks whether wallet support for the specified type
+ (legacy or descriptor wallet) was compiled."""
+ if self.options.descriptors:
+ return self.is_sqlite_compiled()
+ else:
+ return self.is_bdb_compiled()
+
def is_wallet_tool_compiled(self):
"""Checks whether bitcoin-wallet was compiled."""
return self.config["components"].getboolean("ENABLE_WALLET_TOOL")
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 269f2442a9..0b9154a030 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -20,6 +20,7 @@ import urllib.parse
import collections
import shlex
import sys
+from pathlib import Path
from .authproxy import JSONRPCException
from .descriptors import descsum_create
@@ -380,21 +381,31 @@ class TestNode():
def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT):
wait_until_helper(self.is_node_stopped, timeout=timeout, timeout_factor=self.timeout_factor)
+ @property
+ def chain_path(self) -> Path:
+ return Path(self.datadir) / self.chain
+
+ @property
+ def debug_log_path(self) -> Path:
+ return self.chain_path / 'debug.log'
+
+ def debug_log_bytes(self) -> int:
+ with open(self.debug_log_path, encoding='utf-8') as dl:
+ dl.seek(0, 2)
+ return dl.tell()
+
@contextlib.contextmanager
def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2):
if unexpected_msgs is None:
unexpected_msgs = []
time_end = time.time() + timeout * self.timeout_factor
- debug_log = os.path.join(self.datadir, self.chain, 'debug.log')
- with open(debug_log, encoding='utf-8') as dl:
- dl.seek(0, 2)
- prev_size = dl.tell()
+ prev_size = self.debug_log_bytes()
yield
while True:
found = True
- with open(debug_log, encoding='utf-8') as dl:
+ with open(self.debug_log_path, encoding='utf-8') as dl:
dl.seek(prev_size)
log = dl.read()
print_log = " - " + "\n - ".join(log.splitlines())
@@ -411,6 +422,42 @@ class TestNode():
time.sleep(0.05)
self._raise_assertion_error('Expected messages "{}" does not partially match log:\n\n{}\n\n'.format(str(expected_msgs), print_log))
+ def wait_for_debug_log(self, expected_msgs, timeout=10, ignore_case=False) -> int:
+ """
+ Block until we see a particular debug log message fragment or until we exceed the timeout.
+ Return:
+ the number of log lines we encountered when matching
+ """
+ time_end = time.time() + timeout * self.timeout_factor
+ prev_size = self.debug_log_bytes()
+ re_flags = re.MULTILINE | (re.IGNORECASE if ignore_case else 0)
+
+ while True:
+ found = True
+ with open(self.debug_log_path, encoding='utf-8') as dl:
+ dl.seek(prev_size)
+ log = dl.read()
+
+ for expected_msg in expected_msgs:
+ if re.search(re.escape(expected_msg), log, flags=re_flags) is None:
+ found = False
+
+ if found:
+ num_logs = len(log.splitlines())
+ return num_logs
+
+ if time.time() >= time_end:
+ print_log = " - " + "\n - ".join(log.splitlines())
+ break
+
+ # No sleep here because we want to detect the message fragment as fast as
+ # possible.
+
+ self._raise_assertion_error(
+ 'Expected messages "{}" does not partially match log:\n\n{}\n\n'.format(
+ str(expected_msgs), print_log))
+ return -1 # useless return to satisfy linter
+
@contextlib.contextmanager
def profile_with_perf(self, profile_name: str):
"""
@@ -570,7 +617,7 @@ class TestNode():
def add_outbound_p2p_connection(self, p2p_conn, *, p2p_idx, connection_type="outbound-full-relay", **kwargs):
"""Add an outbound p2p connection from node. Must be an
- "outbound-full-relay", "block-relay-only" or "addr-fetch" connection.
+ "outbound-full-relay", "block-relay-only", "addr-fetch" or "feeler" connection.
This method adds the p2p connection to the self.p2ps list and returns
the connection to the caller.
@@ -582,11 +629,16 @@ class TestNode():
p2p_conn.peer_accept_connection(connect_cb=addconnection_callback, connect_id=p2p_idx + 1, net=self.chain, timeout_factor=self.timeout_factor, **kwargs)()
- p2p_conn.wait_for_connect()
- self.p2ps.append(p2p_conn)
+ if connection_type == "feeler":
+ # feeler connections are closed as soon as the node receives a `version` message
+ p2p_conn.wait_until(lambda: p2p_conn.message_count["version"] == 1, check_connected=False)
+ p2p_conn.wait_until(lambda: not p2p_conn.is_connected, check_connected=False)
+ else:
+ p2p_conn.wait_for_connect()
+ self.p2ps.append(p2p_conn)
- p2p_conn.wait_for_verack()
- p2p_conn.sync_with_ping()
+ p2p_conn.wait_for_verack()
+ p2p_conn.sync_with_ping()
return p2p_conn
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 57ef6d99d5..195af14914 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -269,6 +269,7 @@ def wait_until_helper(predicate, *, attempts=float('inf'), timeout=float('inf'),
raise AssertionError("Predicate {} not true after {} seconds".format(predicate_source, timeout))
raise RuntimeError('Unreachable')
+
def sha256sum_file(filename):
h = hashlib.sha256()
with open(filename, 'rb') as f:
@@ -378,10 +379,10 @@ def write_config(config_path, *, n, chain, extra_config="", disable_autoconnect=
f.write("fixedseeds=0\n")
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 overridden in
- # tests.
- f.write("peertimeout=999999\n")
+ # peertimeout is measured in mock time, so setting it large enough to
+ # cover any duration in mock time is sufficient. It can be overridden
+ # in tests.
+ f.write("peertimeout=999999999\n")
f.write("printtoconsole=0\n")
f.write("upnp=0\n")
f.write("natpmp=0\n")
@@ -445,6 +446,12 @@ def set_node_times(nodes, t):
node.setmocktime(t)
+def check_node_connections(*, node, num_in, num_out):
+ info = node.getnetworkinfo()
+ assert_equal(info["connections_in"], num_in)
+ assert_equal(info["connections_out"], num_out)
+
+
# Transaction/Block functions
#############################
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index f724cb2af3..dd41a740ae 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -9,7 +9,13 @@ from decimal import Decimal
from enum import Enum
from random import choice
from typing import Optional
-from test_framework.address import create_deterministic_address_bcrt1_p2tr_op_true
+from test_framework.address import (
+ base58_to_byte,
+ create_deterministic_address_bcrt1_p2tr_op_true,
+ key_to_p2pkh,
+ key_to_p2sh_p2wpkh,
+ key_to_p2wpkh,
+)
from test_framework.descriptors import descsum_create
from test_framework.key import ECKey
from test_framework.messages import (
@@ -31,7 +37,11 @@ from test_framework.script import (
)
from test_framework.script_util import (
key_to_p2pk_script,
+ key_to_p2pkh_script,
+ key_to_p2sh_p2wpkh_script,
key_to_p2wpkh_script,
+ keyhash_to_p2pkh_script,
+ scripthash_to_p2sh_script,
)
from test_framework.util import (
assert_equal,
@@ -169,8 +179,9 @@ class MiniWallet:
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):
+ def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node=None, 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."""
+ from_node = from_node or self._test_node
utxo_to_spend = utxo_to_spend or self.get_utxo()
if self._priv_key is None:
vsize = Decimal(104) # anyone-can-spend
@@ -203,18 +214,46 @@ class MiniWallet:
assert_equal(tx_info['fees']['base'], utxo_to_spend['value'] - Decimal(send_value) / COIN)
return {'txid': tx_info['txid'], 'wtxid': tx_info['wtxid'], 'hex': tx_hex, 'tx': tx}
- def sendrawtransaction(self, *, from_node, tx_hex):
- txid = from_node.sendrawtransaction(tx_hex)
+ def sendrawtransaction(self, *, from_node, tx_hex, **kwargs):
+ txid = from_node.sendrawtransaction(hexstring=tx_hex, **kwargs)
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)."""
+def getnewdestination(address_type='bech32'):
+ """Generate a random destination of the specified type and return the
+ corresponding public key, scriptPubKey and address. Supported types are
+ 'legacy', 'p2sh-segwit' and 'bech32'. Can be used when a random
+ destination is needed, but no compiled wallet is available (e.g. as
+ replacement to the getnewaddress/getaddressinfo RPCs)."""
key = ECKey()
key.generate()
- return key_to_p2wpkh_script(key.get_pubkey().get_bytes())
+ pubkey = key.get_pubkey().get_bytes()
+ if address_type == 'legacy':
+ scriptpubkey = key_to_p2pkh_script(pubkey)
+ address = key_to_p2pkh(pubkey)
+ elif address_type == 'p2sh-segwit':
+ scriptpubkey = key_to_p2sh_p2wpkh_script(pubkey)
+ address = key_to_p2sh_p2wpkh(pubkey)
+ elif address_type == 'bech32':
+ scriptpubkey = key_to_p2wpkh_script(pubkey)
+ address = key_to_p2wpkh(pubkey)
+ # TODO: also support bech32m (need to generate x-only-pubkey)
+ else:
+ assert False
+ return pubkey, scriptpubkey, address
+
+
+def address_to_scriptpubkey(address):
+ """Converts a given address to the corresponding output script (scriptPubKey)."""
+ payload, version = base58_to_byte(address)
+ if version == 111: # testnet pubkey hash
+ return keyhash_to_p2pkh_script(payload)
+ elif version == 196: # testnet script hash
+ return scripthash_to_p2sh_script(payload)
+ # TODO: also support other address formats
+ else:
+ assert False
def make_chain(node, address, privkeys, parent_txid, parent_value, n=0, parent_locking_script=None, fee=DEFAULT_FEE):
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index ab5740d1aa..eb2d030f4a 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -138,7 +138,8 @@ BASE_SCRIPTS = [
'feature_fee_estimation.py',
'interface_zmq.py',
'rpc_invalid_address_message.py',
- 'interface_bitcoin_cli.py',
+ 'interface_bitcoin_cli.py --legacy-wallet',
+ 'interface_bitcoin_cli.py --descriptors',
'feature_bind_extra.py',
'mempool_resurrect.py',
'wallet_txn_doublespend.py --mineblock',
@@ -178,7 +179,8 @@ BASE_SCRIPTS = [
'rpc_rawtransaction.py --legacy-wallet',
'rpc_rawtransaction.py --descriptors',
'wallet_groups.py --legacy-wallet',
- 'wallet_transactiontime_rescan.py',
+ 'wallet_transactiontime_rescan.py --descriptors',
+ 'wallet_transactiontime_rescan.py --legacy-wallet',
'p2p_addrv2_relay.py',
'wallet_groups.py --descriptors',
'p2p_compactblocks_hb.py',
@@ -215,9 +217,11 @@ BASE_SCRIPTS = [
'wallet_txn_clone.py --mineblock',
'feature_notifications.py',
'rpc_getblockfilter.py',
+ 'rpc_getblockfrompeer.py',
'rpc_invalidateblock.py',
'feature_utxo_set_hash.py',
- 'feature_rbf.py',
+ 'feature_rbf.py --legacy-wallet',
+ 'feature_rbf.py --descriptors',
'mempool_packages.py',
'mempool_package_onemore.py',
'rpc_createmultisig.py --legacy-wallet',
@@ -253,6 +257,7 @@ BASE_SCRIPTS = [
'wallet_bumpfee.py --descriptors',
'wallet_implicitsegwit.py --legacy-wallet',
'rpc_named_arguments.py',
+ 'feature_startupnotify.py',
'wallet_listsinceblock.py --legacy-wallet',
'wallet_listsinceblock.py --descriptors',
'wallet_listdescriptors.py --descriptors',
@@ -277,6 +282,7 @@ BASE_SCRIPTS = [
'wallet_taproot.py',
'p2p_fingerprint.py',
'feature_uacomment.py',
+ 'feature_init.py',
'wallet_coinbase_category.py --legacy-wallet',
'wallet_coinbase_category.py --descriptors',
'feature_filelock.py',
@@ -299,7 +305,8 @@ BASE_SCRIPTS = [
'feature_txindex_compatibility.py',
'feature_logging.py',
'feature_anchors.py',
- 'feature_coinstatsindex.py',
+ 'feature_coinstatsindex.py --legacy-wallet',
+ 'feature_coinstatsindex.py --descriptors',
'wallet_orphanedreward.py',
'p2p_node_network_limited.py',
'p2p_permissions.py',
@@ -310,6 +317,7 @@ BASE_SCRIPTS = [
'feature_presegwit_node_upgrade.py',
'feature_settings.py',
'rpc_getdescriptorinfo.py',
+ 'rpc_mempool_entry_fee_fields_deprecation.py',
'rpc_help.py',
'feature_help.py',
'feature_shutdown.py',
@@ -522,33 +530,35 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=
max_len_name = len(max(test_list, key=len))
test_count = len(test_list)
- for i in range(test_count):
- test_result, testdir, stdout, stderr = job_queue.get_next()
- test_results.append(test_result)
- done_str = "{}/{} - {}{}{}".format(i + 1, test_count, BOLD[1], test_result.name, BOLD[0])
- if test_result.status == "Passed":
- logging.debug("%s passed, Duration: %s s" % (done_str, test_result.time))
- elif test_result.status == "Skipped":
- logging.debug("%s skipped" % (done_str))
- else:
- print("%s failed, Duration: %s s\n" % (done_str, test_result.time))
- print(BOLD[1] + 'stdout:\n' + BOLD[0] + stdout + '\n')
- print(BOLD[1] + 'stderr:\n' + BOLD[0] + stderr + '\n')
- if combined_logs_len and os.path.isdir(testdir):
- # Print the final `combinedlogslen` lines of the combined logs
- print('{}Combine the logs and print the last {} lines ...{}'.format(BOLD[1], combined_logs_len, BOLD[0]))
- print('\n============')
- print('{}Combined log for {}:{}'.format(BOLD[1], testdir, BOLD[0]))
- print('============\n')
- combined_logs_args = [sys.executable, os.path.join(tests_dir, 'combine_logs.py'), testdir]
- if BOLD[0]:
- combined_logs_args += ['--color']
- combined_logs, _ = subprocess.Popen(combined_logs_args, universal_newlines=True, stdout=subprocess.PIPE).communicate()
- print("\n".join(deque(combined_logs.splitlines(), combined_logs_len)))
-
- if failfast:
- logging.debug("Early exiting after test failure")
- break
+ i = 0
+ while i < test_count:
+ for test_result, testdir, stdout, stderr in job_queue.get_next():
+ test_results.append(test_result)
+ i += 1
+ done_str = "{}/{} - {}{}{}".format(i, test_count, BOLD[1], test_result.name, BOLD[0])
+ if test_result.status == "Passed":
+ logging.debug("%s passed, Duration: %s s" % (done_str, test_result.time))
+ elif test_result.status == "Skipped":
+ logging.debug("%s skipped" % (done_str))
+ else:
+ print("%s failed, Duration: %s s\n" % (done_str, test_result.time))
+ print(BOLD[1] + 'stdout:\n' + BOLD[0] + stdout + '\n')
+ print(BOLD[1] + 'stderr:\n' + BOLD[0] + stderr + '\n')
+ if combined_logs_len and os.path.isdir(testdir):
+ # Print the final `combinedlogslen` lines of the combined logs
+ print('{}Combine the logs and print the last {} lines ...{}'.format(BOLD[1], combined_logs_len, BOLD[0]))
+ print('\n============')
+ print('{}Combined log for {}:{}'.format(BOLD[1], testdir, BOLD[0]))
+ print('============\n')
+ combined_logs_args = [sys.executable, os.path.join(tests_dir, 'combine_logs.py'), testdir]
+ if BOLD[0]:
+ combined_logs_args += ['--color']
+ combined_logs, _ = subprocess.Popen(combined_logs_args, universal_newlines=True, stdout=subprocess.PIPE).communicate()
+ print("\n".join(deque(combined_logs.splitlines(), combined_logs_len)))
+
+ if failfast:
+ logging.debug("Early exiting after test failure")
+ break
print_results(test_results, max_len_name, (int(time.time() - start_time)))
@@ -642,8 +652,9 @@ class TestHandler:
dot_count = 0
while True:
- # Return first proc that finishes
+ # Return all procs that have finished, if any. Otherwise sleep until there is one.
time.sleep(.5)
+ ret = []
for job in self.jobs:
(name, start_time, proc, testdir, log_out, log_err) = job
if proc.poll() is not None:
@@ -662,7 +673,9 @@ class TestHandler:
clearline = '\r' + (' ' * dot_count) + '\r'
print(clearline, end='', flush=True)
dot_count = 0
- return TestResult(name, status, int(time.time() - start_time)), testdir, stdout, stderr
+ ret.append((TestResult(name, status, int(time.time() - start_time)), testdir, stdout, stderr))
+ if ret:
+ return ret
if self.use_term_control:
print('.', end='', flush=True)
dot_count += 1
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index 616ac29b15..2cb9dc4523 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -70,8 +70,8 @@ class ToolWalletTest(BitcoinTestFramework):
def get_expected_info_output(self, name="", transactions=0, keypool=2, address=0):
wallet_name = self.default_wallet_name if name == "" else name
- output_types = 3 # p2pkh, p2sh, segwit
if self.options.descriptors:
+ output_types = 4 # p2pkh, p2sh, segwit, bech32m
return textwrap.dedent('''\
Wallet info
===========
@@ -85,6 +85,7 @@ class ToolWalletTest(BitcoinTestFramework):
Address Book: %d
''' % (wallet_name, keypool * output_types, transactions, address))
else:
+ output_types = 3 # p2pkh, p2sh, segwit. Legacy wallets do not support bech32m.
return textwrap.dedent('''\
Wallet info
===========
@@ -298,8 +299,8 @@ class ToolWalletTest(BitcoinTestFramework):
assert_equal(1000, out['keypoolsize_hd_internal'])
assert_equal(True, 'hdseedid' in out)
else:
- assert_equal(3000, out['keypoolsize'])
- assert_equal(3000, out['keypoolsize_hd_internal'])
+ assert_equal(4000, out['keypoolsize'])
+ assert_equal(4000, out['keypoolsize_hd_internal'])
self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after)
assert_equal(timestamp_before, timestamp_after)
@@ -389,7 +390,11 @@ class ToolWalletTest(BitcoinTestFramework):
bad_sum_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_sum3.dump")
dump_data["checksum"] = "2" * 10
self.write_dump(dump_data, bad_sum_wallet_dump)
- self.assert_raises_tool_error('Error: Dumpfile checksum does not match. Computed {}, expected {}{}'.format(checksum, "2" * 10, "0" * 54), '-wallet=badload', '-dumpfile={}'.format(bad_sum_wallet_dump), 'createfromdump')
+ self.assert_raises_tool_error('Error: Checksum is not the correct size', '-wallet=badload', '-dumpfile={}'.format(bad_sum_wallet_dump), 'createfromdump')
+ assert not os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest/wallets", "badload"))
+ dump_data["checksum"] = "3" * 66
+ self.write_dump(dump_data, bad_sum_wallet_dump)
+ self.assert_raises_tool_error('Error: Checksum is not the correct size', '-wallet=badload', '-dumpfile={}'.format(bad_sum_wallet_dump), 'createfromdump')
assert not os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest/wallets", "badload"))
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index e4fe150333..f7c80f805c 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -121,6 +121,12 @@ class AddressTypeTest(BitcoinTestFramework):
assert_equal(info['witness_version'], 0)
assert_equal(len(info['witness_program']), 40)
assert 'pubkey' in info
+ elif not multisig and typ == "bech32m":
+ # P2TR single sig
+ assert info["isscript"]
+ assert info["iswitness"]
+ assert_equal(info["witness_version"], 1)
+ assert_equal(len(info["witness_program"]), 64)
elif typ == 'legacy':
# P2SH-multisig
assert info['isscript']
@@ -339,19 +345,31 @@ class AddressTypeTest(BitcoinTestFramework):
self.log.info("Nodes with addresstype=legacy never use a P2WPKH change output (unless changetype is set otherwise):")
self.test_change_output_type(0, [to_address_bech32_1], 'legacy')
- self.log.info("Nodes with addresstype=p2sh-segwit only use a P2WPKH change output if any destination address is bech32:")
- self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
- self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
- self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
- self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
+ if self.options.descriptors:
+ self.log.info("Nodes with addresstype=p2sh-segwit match the change output")
+ self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
+ self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
+ self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
+ self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
+ else:
+ self.log.info("Nodes with addresstype=p2sh-segwit match the change output")
+ self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
+ self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
+ self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
+ self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
self.log.info("Nodes with change_type=bech32 always use a P2WPKH change output:")
self.test_change_output_type(2, [to_address_bech32_1], 'bech32')
self.test_change_output_type(2, [to_address_p2sh], 'bech32')
- self.log.info("Nodes with addresstype=bech32 always use a P2WPKH change output (unless changetype is set otherwise):")
- self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
- self.test_change_output_type(3, [to_address_p2sh], 'bech32')
+ if self.options.descriptors:
+ self.log.info("Nodes with addresstype=bech32 match the change output (unless changetype is set otherwise):")
+ self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
+ self.test_change_output_type(3, [to_address_p2sh], 'p2sh-segwit')
+ else:
+ self.log.info("Nodes with addresstype=bech32 match the change output (unless changetype is set otherwise):")
+ self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
+ self.test_change_output_type(3, [to_address_p2sh], 'p2sh-segwit')
self.log.info('getrawchangeaddress defaults to addresstype if -changetype is not set and argument is absent')
self.test_address(3, self.nodes[3].getrawchangeaddress(), multisig=False, typ='bech32')
@@ -370,10 +388,9 @@ class AddressTypeTest(BitcoinTestFramework):
self.test_address(4, self.nodes[4].getrawchangeaddress('bech32'), multisig=False, typ='bech32')
if self.options.descriptors:
- self.log.info("Descriptor wallets do not have bech32m addresses by default yet")
- # TODO: Remove this when they do
- assert_raises_rpc_error(-12, "Error: No bech32m addresses available", self.nodes[0].getnewaddress, "", "bech32m")
- assert_raises_rpc_error(-12, "Error: No bech32m addresses available", self.nodes[0].getrawchangeaddress, "bech32m")
+ self.log.info("Descriptor wallets have bech32m addresses")
+ self.test_address(4, self.nodes[4].getnewaddress("", "bech32m"), multisig=False, typ="bech32m")
+ self.test_address(4, self.nodes[4].getrawchangeaddress("bech32m"), multisig=False, typ="bech32m")
else:
self.log.info("Legacy wallets cannot make bech32m addresses")
assert_raises_rpc_error(-8, "Legacy wallets cannot provide bech32m addresses", self.nodes[0].getnewaddress, "", "bech32m")
diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py
index 932df4fbff..292fe3a310 100755
--- a/test/functional/wallet_backup.py
+++ b/test/functional/wallet_backup.py
@@ -110,17 +110,32 @@ class WalletBackupTest(BitcoinTestFramework):
os.remove(os.path.join(self.nodes[1].datadir, self.chain, 'wallets', self.default_wallet_name, self.wallet_data_filename))
os.remove(os.path.join(self.nodes[2].datadir, self.chain, 'wallets', self.default_wallet_name, self.wallet_data_filename))
+ def restore_invalid_wallet(self):
+ node = self.nodes[3]
+ invalid_wallet_file = os.path.join(self.nodes[0].datadir, 'invalid_wallet_file.bak')
+ open(invalid_wallet_file, 'a', encoding="utf8").write('invald wallet')
+ wallet_name = "res0"
+ not_created_wallet_file = os.path.join(node.datadir, self.chain, 'wallets', wallet_name)
+ error_message = "Wallet file verification failed. Failed to load database path '{}'. Data is not in recognized format.".format(not_created_wallet_file)
+ assert_raises_rpc_error(-18, error_message, node.restorewallet, wallet_name, invalid_wallet_file)
+ assert not os.path.exists(not_created_wallet_file)
+
def restore_nonexistent_wallet(self):
node = self.nodes[3]
nonexistent_wallet_file = os.path.join(self.nodes[0].datadir, 'nonexistent_wallet.bak')
wallet_name = "res0"
assert_raises_rpc_error(-8, "Backup file does not exist", node.restorewallet, wallet_name, nonexistent_wallet_file)
+ not_created_wallet_file = os.path.join(node.datadir, self.chain, 'wallets', wallet_name)
+ assert not os.path.exists(not_created_wallet_file)
def restore_wallet_existent_name(self):
node = self.nodes[3]
- wallet_file = os.path.join(self.nodes[0].datadir, 'wallet.bak')
+ backup_file = os.path.join(self.nodes[0].datadir, 'wallet.bak')
wallet_name = "res0"
- assert_raises_rpc_error(-8, "Wallet name already exists.", node.restorewallet, wallet_name, wallet_file)
+ wallet_file = os.path.join(node.datadir, self.chain, 'wallets', wallet_name)
+ error_message = "Failed to create database path '{}'. Database already exists.".format(wallet_file)
+ assert_raises_rpc_error(-36, error_message, node.restorewallet, wallet_name, backup_file)
+ assert os.path.exists(wallet_file)
def init_three(self):
self.init_wallet(node=0)
@@ -177,6 +192,7 @@ class WalletBackupTest(BitcoinTestFramework):
##
self.log.info("Restoring wallets on node 3 using backup files")
+ self.restore_invalid_wallet()
self.restore_nonexistent_wallet()
backup_file_0 = os.path.join(self.nodes[0].datadir, 'wallet.bak')
@@ -187,6 +203,10 @@ class WalletBackupTest(BitcoinTestFramework):
self.nodes[3].restorewallet("res1", backup_file_1)
self.nodes[3].restorewallet("res2", backup_file_2)
+ assert os.path.exists(os.path.join(self.nodes[3].datadir, self.chain, 'wallets', "res0"))
+ assert os.path.exists(os.path.join(self.nodes[3].datadir, self.chain, 'wallets', "res1"))
+ assert os.path.exists(os.path.join(self.nodes[3].datadir, self.chain, 'wallets', "res2"))
+
res0_rpc = self.nodes[3].get_wallet_rpc("res0")
res1_rpc = self.nodes[3].get_wallet_rpc("res1")
res2_rpc = self.nodes[3].get_wallet_rpc("res2")
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index 291be055b7..f6843d597d 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -24,7 +24,6 @@ from test_framework.blocktools import (
)
from test_framework.messages import (
BIP125_SEQUENCE_NUMBER,
- tx_from_hex,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -588,13 +587,10 @@ def spend_one_input(node, dest_address, change_size=Decimal("0.00049000")):
def submit_block_with_tx(node, tx):
- ctx = tx_from_hex(tx)
tip = node.getbestblockhash()
height = node.getblockcount() + 1
block_time = node.getblockheader(tip)["mediantime"] + 1
- block = create_block(int(tip, 16), create_coinbase(height), block_time)
- block.vtx.append(ctx)
- block.hashMerkleRoot = block.calc_merkle_root()
+ block = create_block(int(tip, 16), create_coinbase(height), block_time, txlist=[tx])
add_witness_commitment(block)
block.solve()
node.submitblock(block.serialize().hex())
diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py
index a751138d89..4416a9655f 100755
--- a/test/functional/wallet_createwallet.py
+++ b/test/functional/wallet_createwallet.py
@@ -146,7 +146,7 @@ class CreateWalletTest(BitcoinTestFramework):
w6.keypoolrefill(1)
# There should only be 1 key for legacy, 3 for descriptors
walletinfo = w6.getwalletinfo()
- keys = 3 if self.options.descriptors else 1
+ keys = 4 if self.options.descriptors else 1
assert_equal(walletinfo['keypoolsize'], keys)
assert_equal(walletinfo['keypoolsize_hd_internal'], keys)
# Allow empty passphrase, but there should be a warning
diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py
index df2fdb2943..e47d021210 100755
--- a/test/functional/wallet_descriptor.py
+++ b/test/functional/wallet_descriptor.py
@@ -37,12 +37,12 @@ class WalletDescriptorTest(BitcoinTestFramework):
self.log.info("Making a descriptor wallet")
self.nodes[0].createwallet(wallet_name="desc1", descriptors=True)
- # A descriptor wallet should have 100 addresses * 3 types = 300 keys
+ # A descriptor wallet should have 100 addresses * 4 types = 400 keys
self.log.info("Checking wallet info")
wallet_info = self.nodes[0].getwalletinfo()
assert_equal(wallet_info['format'], 'sqlite')
- assert_equal(wallet_info['keypoolsize'], 300)
- assert_equal(wallet_info['keypoolsize_hd_internal'], 300)
+ assert_equal(wallet_info['keypoolsize'], 400)
+ assert_equal(wallet_info['keypoolsize_hd_internal'], 400)
assert 'keypoololdest' not in wallet_info
# Check that getnewaddress works
diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py
index c228bb122a..eb305c5fa2 100755
--- a/test/functional/wallet_groups.py
+++ b/test/functional/wallet_groups.py
@@ -108,12 +108,17 @@ class WalletGroupTest(BitcoinTestFramework):
assert_equal(input_addrs[0], input_addrs[1])
# Node 2 enforces avoidpartialspends so needs no checking here
+ tx4_ungrouped_fee = 2820
+ tx4_grouped_fee = 4160
+ tx5_6_ungrouped_fee = 5520
+ tx5_6_grouped_fee = 8240
+
self.log.info("Test wallet option maxapsfee")
addr_aps = self.nodes[3].getnewaddress()
self.nodes[0].sendtoaddress(addr_aps, 1.0)
self.nodes[0].sendtoaddress(addr_aps, 1.0)
self.generate(self.nodes[0], 1)
- with self.nodes[3].assert_debug_log(['Fee non-grouped = 2820, grouped = 4160, using grouped']):
+ with self.nodes[3].assert_debug_log([f'Fee non-grouped = {tx4_ungrouped_fee}, grouped = {tx4_grouped_fee}, using grouped']):
txid4 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(), 0.1)
tx4 = self.nodes[3].getrawtransaction(txid4, True)
# tx4 should have 2 inputs and 2 outputs although one output would
@@ -124,7 +129,7 @@ class WalletGroupTest(BitcoinTestFramework):
addr_aps2 = self.nodes[3].getnewaddress()
[self.nodes[0].sendtoaddress(addr_aps2, 1.0) for _ in range(5)]
self.generate(self.nodes[0], 1)
- with self.nodes[3].assert_debug_log(['Fee non-grouped = 5520, grouped = 8240, using non-grouped']):
+ with self.nodes[3].assert_debug_log([f'Fee non-grouped = {tx5_6_ungrouped_fee}, grouped = {tx5_6_grouped_fee}, using non-grouped']):
txid5 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(), 2.95)
tx5 = self.nodes[3].getrawtransaction(txid5, True)
# tx5 should have 3 inputs (1.0, 1.0, 1.0) and 2 outputs
@@ -137,7 +142,7 @@ class WalletGroupTest(BitcoinTestFramework):
addr_aps3 = self.nodes[4].getnewaddress()
[self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)]
self.generate(self.nodes[0], 1)
- with self.nodes[4].assert_debug_log(['Fee non-grouped = 5520, grouped = 8240, using grouped']):
+ with self.nodes[4].assert_debug_log([f'Fee non-grouped = {tx5_6_ungrouped_fee}, grouped = {tx5_6_grouped_fee}, using grouped']):
txid6 = self.nodes[4].sendtoaddress(self.nodes[0].getnewaddress(), 2.95)
tx6 = self.nodes[4].getrawtransaction(txid6, True)
# tx6 should have 5 inputs and 2 outputs
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index 436711669e..3953851491 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -65,7 +65,6 @@ class ImportMultiTest(BitcoinTestFramework):
self.generate(self.nodes[0], 1, sync_fun=self.no_op)
self.generate(self.nodes[1], 1, sync_fun=self.no_op)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
- self.nodes[1].syncwithvalidationinterfacequeue() # Sync the timestamp to the wallet, so that importmulti works
node0_address1 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
@@ -260,7 +259,6 @@ class ImportMultiTest(BitcoinTestFramework):
self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)
self.generate(self.nodes[1], 1, sync_fun=self.no_op)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
- self.nodes[1].syncwithvalidationinterfacequeue()
self.log.info("Should import a p2sh")
self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr},
@@ -281,7 +279,6 @@ class ImportMultiTest(BitcoinTestFramework):
self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)
self.generate(self.nodes[1], 1, sync_fun=self.no_op)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
- self.nodes[1].syncwithvalidationinterfacequeue()
self.log.info("Should import a p2sh with respective redeem script")
self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr},
@@ -302,7 +299,6 @@ class ImportMultiTest(BitcoinTestFramework):
self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)
self.generate(self.nodes[1], 1, sync_fun=self.no_op)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
- self.nodes[1].syncwithvalidationinterfacequeue()
self.log.info("Should import a p2sh with respective redeem script and private keys")
self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr},
@@ -328,7 +324,6 @@ class ImportMultiTest(BitcoinTestFramework):
self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)
self.generate(self.nodes[1], 1, sync_fun=self.no_op)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
- self.nodes[1].syncwithvalidationinterfacequeue()
self.log.info("Should import a p2sh with respective redeem script and private keys")
self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr},
diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py
index bf7a342be6..54c47511a9 100755
--- a/test/functional/wallet_keypool.py
+++ b/test/functional/wallet_keypool.py
@@ -87,8 +87,8 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0].walletlock()
wi = nodes[0].getwalletinfo()
if self.options.descriptors:
- assert_equal(wi['keypoolsize_hd_internal'], 18)
- assert_equal(wi['keypoolsize'], 18)
+ assert_equal(wi['keypoolsize_hd_internal'], 24)
+ assert_equal(wi['keypoolsize'], 24)
else:
assert_equal(wi['keypoolsize_hd_internal'], 6)
assert_equal(wi['keypoolsize'], 6)
@@ -132,8 +132,8 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0].keypoolrefill(100)
wi = nodes[0].getwalletinfo()
if self.options.descriptors:
- assert_equal(wi['keypoolsize_hd_internal'], 300)
- assert_equal(wi['keypoolsize'], 300)
+ assert_equal(wi['keypoolsize_hd_internal'], 400)
+ assert_equal(wi['keypoolsize'], 400)
else:
assert_equal(wi['keypoolsize_hd_internal'], 100)
assert_equal(wi['keypoolsize'], 100)
diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py
index 436bbdcfcc..202ef92887 100755
--- a/test/functional/wallet_listdescriptors.py
+++ b/test/functional/wallet_listdescriptors.py
@@ -43,9 +43,9 @@ class ListDescriptorsTest(BitcoinTestFramework):
node.createwallet(wallet_name='w3', descriptors=True)
result = node.get_wallet_rpc('w3').listdescriptors()
assert_equal("w3", result['wallet_name'])
- assert_equal(6, len(result['descriptors']))
- assert_equal(6, len([d for d in result['descriptors'] if d['active']]))
- assert_equal(3, len([d for d in result['descriptors'] if d['internal']]))
+ assert_equal(8, len(result['descriptors']))
+ assert_equal(8, len([d for d in result['descriptors'] if d['active']]))
+ assert_equal(4, len([d for d in result['descriptors'] if d['internal']]))
for item in result['descriptors']:
assert item['desc'] != ''
assert item['next'] == 0
diff --git a/test/functional/wallet_listreceivedby.py b/test/functional/wallet_listreceivedby.py
index 42a2685a0f..48b92796fc 100755
--- a/test/functional/wallet_listreceivedby.py
+++ b/test/functional/wallet_listreceivedby.py
@@ -2,9 +2,10 @@
# Copyright (c) 2014-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 the listreceivedbyaddress RPC."""
+"""Test the listreceivedbyaddress, listreceivedbylabel, getreceivedybaddress, and getreceivedbylabel RPCs."""
from decimal import Decimal
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_array_result,
@@ -17,6 +18,8 @@ from test_framework.wallet_util import test_address
class ReceivedByTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
+ # Test deprecated exclude coinbase on second node
+ self.extra_args = [[], ["-deprecatedrpc=exclude_coinbase"]]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
@@ -162,5 +165,123 @@ class ReceivedByTest(BitcoinTestFramework):
balance = self.nodes[1].getreceivedbylabel("mynewlabel")
assert_equal(balance, Decimal("0.0"))
+ self.log.info("Tests for including coinbase outputs")
+
+ # Generate block reward to address with label
+ label = "label"
+ address = self.nodes[0].getnewaddress(label)
+
+ reward = Decimal("25")
+ self.generatetoaddress(self.nodes[0], 1, address, sync_fun=self.no_op)
+ hash = self.nodes[0].getbestblockhash()
+
+ self.log.info("getreceivedbyaddress returns nothing with defaults")
+ balance = self.nodes[0].getreceivedbyaddress(address)
+ assert_equal(balance, 0)
+
+ self.log.info("getreceivedbyaddress returns block reward when including immature coinbase")
+ balance = self.nodes[0].getreceivedbyaddress(address=address, include_immature_coinbase=True)
+ assert_equal(balance, reward)
+
+ self.log.info("getreceivedbylabel returns nothing with defaults")
+ balance = self.nodes[0].getreceivedbylabel("label")
+ assert_equal(balance, 0)
+
+ self.log.info("getreceivedbylabel returns block reward when including immature coinbase")
+ balance = self.nodes[0].getreceivedbylabel(label="label", include_immature_coinbase=True)
+ assert_equal(balance, reward)
+
+ self.log.info("listreceivedbyaddress does not include address with defaults")
+ assert_array_result(self.nodes[0].listreceivedbyaddress(),
+ {"address": address},
+ {}, True)
+
+ self.log.info("listreceivedbyaddress includes address when including immature coinbase")
+ assert_array_result(self.nodes[0].listreceivedbyaddress(minconf=1, include_immature_coinbase=True),
+ {"address": address},
+ {"address": address, "amount": reward})
+
+ self.log.info("listreceivedbylabel does not include label with defaults")
+ assert_array_result(self.nodes[0].listreceivedbylabel(),
+ {"label": label},
+ {}, True)
+
+ self.log.info("listreceivedbylabel includes label when including immature coinbase")
+ assert_array_result(self.nodes[0].listreceivedbylabel(minconf=1, include_immature_coinbase=True),
+ {"label": label},
+ {"label": label, "amount": reward})
+
+ self.log.info("Generate 100 more blocks")
+ self.generate(self.nodes[0], COINBASE_MATURITY, sync_fun=self.no_op)
+
+ self.log.info("getreceivedbyaddress returns reward with defaults")
+ balance = self.nodes[0].getreceivedbyaddress(address)
+ assert_equal(balance, reward)
+
+ self.log.info("getreceivedbylabel returns reward with defaults")
+ balance = self.nodes[0].getreceivedbylabel("label")
+ assert_equal(balance, reward)
+
+ self.log.info("listreceivedbyaddress includes address with defaults")
+ assert_array_result(self.nodes[0].listreceivedbyaddress(),
+ {"address": address},
+ {"address": address, "amount": reward})
+
+ self.log.info("listreceivedbylabel includes label with defaults")
+ assert_array_result(self.nodes[0].listreceivedbylabel(),
+ {"label": label},
+ {"label": label, "amount": reward})
+
+ self.log.info("Invalidate block that paid to address")
+ self.nodes[0].invalidateblock(hash)
+
+ self.log.info("getreceivedbyaddress does not include invalidated block when minconf is 0 when including immature coinbase")
+ balance = self.nodes[0].getreceivedbyaddress(address=address, minconf=0, include_immature_coinbase=True)
+ assert_equal(balance, 0)
+
+ self.log.info("getreceivedbylabel does not include invalidated block when minconf is 0 when including immature coinbase")
+ balance = self.nodes[0].getreceivedbylabel(label="label", minconf=0, include_immature_coinbase=True)
+ assert_equal(balance, 0)
+
+ self.log.info("listreceivedbyaddress does not include invalidated block when minconf is 0 when including immature coinbase")
+ assert_array_result(self.nodes[0].listreceivedbyaddress(minconf=0, include_immature_coinbase=True),
+ {"address": address},
+ {}, True)
+
+ self.log.info("listreceivedbylabel does not include invalidated block when minconf is 0 when including immature coinbase")
+ assert_array_result(self.nodes[0].listreceivedbylabel(minconf=0, include_immature_coinbase=True),
+ {"label": label},
+ {}, True)
+
+ # Test exclude_coinbase
+ address2 = self.nodes[1].getnewaddress(label)
+ self.generatetoaddress(self.nodes[1], COINBASE_MATURITY + 1, address2, sync_fun=self.no_op)
+
+ self.log.info("getreceivedbyaddress returns nothing when excluding coinbase")
+ balance = self.nodes[1].getreceivedbyaddress(address2)
+ assert_equal(balance, 0)
+
+ self.log.info("getreceivedbylabel returns nothing when excluding coinbase")
+ balance = self.nodes[1].getreceivedbylabel("label")
+ assert_equal(balance, 0)
+
+ self.log.info("listreceivedbyaddress does not include address when excluding coinbase")
+ assert_array_result(self.nodes[1].listreceivedbyaddress(),
+ {"address": address2},
+ {}, True)
+
+ self.log.info("listreceivedbylabel does not include label when excluding coinbase")
+ assert_array_result(self.nodes[1].listreceivedbylabel(),
+ {"label": label},
+ {}, True)
+
+ self.log.info("getreceivedbyaddress throws when setting include_immature_coinbase with deprecated exclude_coinbase")
+ assert_raises_rpc_error(-8, 'include_immature_coinbase is incompatible with deprecated exclude_coinbase', self.nodes[1].getreceivedbyaddress, address2, 1, True)
+
+
+ self.log.info("listreceivedbyaddress throws when setting include_immature_coinbase with deprecated exclude_coinbase")
+ assert_raises_rpc_error(-8, 'include_immature_coinbase is incompatible with deprecated exclude_coinbase', self.nodes[1].listreceivedbyaddress, 1, False, False, "", True)
+
+
if __name__ == '__main__':
ReceivedByTest().main()
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index 8fd15a164c..f75877f256 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -3,7 +3,10 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the listtransactions API."""
+
from decimal import Decimal
+import os
+import shutil
from test_framework.messages import (
COIN,
@@ -13,11 +16,13 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_array_result,
assert_equal,
+ assert_raises_rpc_error,
)
+
class ListTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
- self.num_nodes = 2
+ self.num_nodes = 3
# This test isn't testing txn relay/timing, so set whitelist on the
# peers for instant txn relay. This speeds up the test run time 2-3x.
self.extra_args = [["-whitelist=noban@127.0.0.1"]] * self.num_nodes
@@ -102,7 +107,8 @@ class ListTransactionsTest(BitcoinTestFramework):
{"txid": txid, "label": "watchonly"})
self.run_rbf_opt_in_test()
-
+ self.run_externally_generated_address_test()
+ self.run_invalid_parameters_test()
def run_rbf_opt_in_test(self):
"""Test the opt-in-rbf flag for sent and received transactions."""
@@ -217,5 +223,67 @@ class ListTransactionsTest(BitcoinTestFramework):
assert_equal(self.nodes[0].gettransaction(txid_3b)["bip125-replaceable"], "no")
assert_equal(self.nodes[0].gettransaction(txid_4)["bip125-replaceable"], "unknown")
+ def run_externally_generated_address_test(self):
+ """Test behavior when receiving address is not in the address book."""
+
+ self.log.info("Setup the same wallet on two nodes")
+ # refill keypool otherwise the second node wouldn't recognize addresses generated on the first nodes
+ self.nodes[0].keypoolrefill(1000)
+ self.stop_nodes()
+ wallet0 = os.path.join(self.nodes[0].datadir, self.chain, self.default_wallet_name, "wallet.dat")
+ wallet2 = os.path.join(self.nodes[2].datadir, self.chain, self.default_wallet_name, "wallet.dat")
+ shutil.copyfile(wallet0, wallet2)
+ self.start_nodes()
+ # reconnect nodes
+ self.connect_nodes(0, 1)
+ self.connect_nodes(1, 2)
+ self.connect_nodes(2, 0)
+
+ addr1 = self.nodes[0].getnewaddress("pizza1", 'legacy')
+ addr2 = self.nodes[0].getnewaddress("pizza2", 'p2sh-segwit')
+ addr3 = self.nodes[0].getnewaddress("pizza3", 'bech32')
+
+ self.log.info("Send to externally generated addresses")
+ # send to an address beyond the next to be generated to test the keypool gap
+ self.nodes[1].sendtoaddress(addr3, "0.001")
+ self.generate(self.nodes[1], 1)
+
+ # send to an address that is already marked as used due to the keypool gap mechanics
+ self.nodes[1].sendtoaddress(addr2, "0.001")
+ self.generate(self.nodes[1], 1)
+
+ # send to self transaction
+ self.nodes[0].sendtoaddress(addr1, "0.001")
+ self.generate(self.nodes[0], 1)
+
+ self.log.info("Verify listtransactions is the same regardless of where the address was generated")
+ transactions0 = self.nodes[0].listtransactions()
+ transactions2 = self.nodes[2].listtransactions()
+
+ # normalize results: remove fields that normally could differ and sort
+ def normalize_list(txs):
+ for tx in txs:
+ tx.pop('label', None)
+ tx.pop('time', None)
+ tx.pop('timereceived', None)
+ txs.sort(key=lambda x: x['txid'])
+
+ normalize_list(transactions0)
+ normalize_list(transactions2)
+ assert_equal(transactions0, transactions2)
+
+ self.log.info("Verify labels are persistent on the node that generated the addresses")
+ assert_equal(['pizza1'], self.nodes[0].getaddressinfo(addr1)['labels'])
+ assert_equal(['pizza2'], self.nodes[0].getaddressinfo(addr2)['labels'])
+ assert_equal(['pizza3'], self.nodes[0].getaddressinfo(addr3)['labels'])
+
+ def run_invalid_parameters_test(self):
+ self.log.info("Test listtransactions RPC parameter validity")
+ assert_raises_rpc_error(-8, 'Label argument must be a valid label name or "*".', self.nodes[0].listtransactions, label="")
+ self.nodes[0].listtransactions(label="*")
+ assert_raises_rpc_error(-8, "Negative count", self.nodes[0].listtransactions, count=-1)
+ assert_raises_rpc_error(-8, "Negative from", self.nodes[0].listtransactions, skip=-1)
+
+
if __name__ == '__main__':
ListTransactionsTest().main()
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index 0b868dde6c..317121eb68 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -141,7 +141,7 @@ class MultiWalletTest(BitcoinTestFramework):
# should raise rpc error if wallet path can't be created
err_code = -4 if self.options.descriptors else -1
- assert_raises_rpc_error(err_code, "boost::filesystem::create_directory:", self.nodes[0].createwallet, "w8/bad")
+ assert_raises_rpc_error(err_code, "boost::filesystem::create_director", self.nodes[0].createwallet, "w8/bad")
# check that all requested wallets were created
self.stop_node(0)
diff --git a/test/functional/wallet_signer.py b/test/functional/wallet_signer.py
index 6dadc57b1a..9e2db517b6 100755
--- a/test/functional/wallet_signer.py
+++ b/test/functional/wallet_signer.py
@@ -25,6 +25,13 @@ class WalletSignerTest(BitcoinTestFramework):
else:
return path
+ def mock_invalid_signer_path(self):
+ path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'mocks', 'invalid_signer.py')
+ if platform.system() == "Windows":
+ return "py " + path
+ else:
+ return path
+
def set_test_params(self):
self.num_nodes = 2
# The experimental syscall sandbox feature (-sandbox) is not compatible with -signer (which
@@ -48,6 +55,11 @@ class WalletSignerTest(BitcoinTestFramework):
os.remove(os.path.join(node.cwd, "mock_result"))
def run_test(self):
+ self.test_valid_signer()
+ self.restart_node(1, [f"-signer={self.mock_invalid_signer_path()}", "-keypool=10"])
+ self.test_invalid_signer()
+
+ def test_valid_signer(self):
self.log.debug(f"-signer={self.mock_signer_path()}")
# Create new wallets for an external signer.
@@ -187,5 +199,10 @@ class WalletSignerTest(BitcoinTestFramework):
# )
# self.clear_mock_result(self.nodes[4])
+ def test_invalid_signer(self):
+ self.log.debug(f"-signer={self.mock_invalid_signer_path()}")
+ self.log.info('Test invalid external signer')
+ assert_raises_rpc_error(-1, "Invalid descriptor", self.nodes[1].createwallet, wallet_name='hww_invalid', disable_private_keys=True, descriptors=True, external_signer=True)
+
if __name__ == '__main__':
WalletSignerTest().main()
diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py
index b22c171374..17eab25457 100755
--- a/test/functional/wallet_taproot.py
+++ b/test/functional/wallet_taproot.py
@@ -10,7 +10,12 @@ from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.descriptors import descsum_create
-from test_framework.script import (CScript, OP_CHECKSIG, taproot_construct)
+from test_framework.script import (
+ CScript,
+ OP_1,
+ OP_CHECKSIG,
+ taproot_construct,
+)
from test_framework.segwit_addr import encode_segwit_address
# xprvs/xpubs, and m/* derived x-only pubkeys (created using independent implementation)
@@ -165,7 +170,7 @@ def pk(hex_key):
def compute_taproot_address(pubkey, scripts):
"""Compute the address for a taproot output with given inner key and scripts."""
tap = taproot_construct(pubkey, scripts)
- assert tap.scriptPubKey[0] == 0x51
+ assert tap.scriptPubKey[0] == OP_1
assert tap.scriptPubKey[1] == 0x20
return encode_segwit_address("bcrt", 1, tap.scriptPubKey[2:])
@@ -237,20 +242,15 @@ class WalletTaprootTest(BitcoinTestFramework):
assert_equal(len(rederive), 1)
assert_equal(rederive[0], addr_g)
- # tr descriptors cannot be imported when Taproot is not active
+ # tr descriptors can be imported regardless of Taproot status
result = self.privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
assert(result[0]["success"])
result = self.pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
assert(result[0]["success"])
- if desc.startswith("tr"):
- result = self.privs_tr_disabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
- assert(not result[0]["success"])
- assert_equal(result[0]["error"]["code"], -4)
- assert_equal(result[0]["error"]["message"], "Cannot import tr() descriptor when Taproot is not active")
- result = self.pubs_tr_disabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
- assert(not result[0]["success"])
- assert_equal(result[0]["error"]["code"], -4)
- assert_equal(result[0]["error"]["message"], "Cannot import tr() descriptor when Taproot is not active")
+ result = self.privs_tr_disabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
+ assert result[0]["success"]
+ result = self.pubs_tr_disabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
+ assert result[0]["success"]
def do_test_sendtoaddress(self, comment, pattern, privmap, treefn, keys_pay, keys_change):
self.log.info("Testing %s through sendtoaddress" % comment)
diff --git a/test/functional/wallet_transactiontime_rescan.py b/test/functional/wallet_transactiontime_rescan.py
index d26d1b9bfa..21941084a3 100755
--- a/test/functional/wallet_transactiontime_rescan.py
+++ b/test/functional/wallet_transactiontime_rescan.py
@@ -10,7 +10,8 @@ import time
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
- assert_equal
+ assert_equal,
+ set_node_times,
)
@@ -35,9 +36,7 @@ class TransactionTimeRescanTest(BitcoinTestFramework):
# synchronize nodes and time
self.sync_all()
- minernode.setmocktime(cur_time)
- usernode.setmocktime(cur_time)
- restorenode.setmocktime(cur_time)
+ set_node_times(self.nodes, cur_time)
# prepare miner wallet
minernode.createwallet(wallet_name='default')
@@ -68,9 +67,7 @@ class TransactionTimeRescanTest(BitcoinTestFramework):
# 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)
+ set_node_times(self.nodes, 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)
@@ -81,9 +78,7 @@ class TransactionTimeRescanTest(BitcoinTestFramework):
# 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)
+ set_node_times(self.nodes, 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)
@@ -94,9 +89,7 @@ class TransactionTimeRescanTest(BitcoinTestFramework):
# 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)
+ set_node_times(self.nodes, 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)
@@ -126,6 +119,14 @@ class TransactionTimeRescanTest(BitcoinTestFramework):
restorenode.createwallet(wallet_name='wo', disable_private_keys=True)
restorewo_wallet = restorenode.get_wallet_rpc('wo')
+ # for descriptor wallets, the test framework maps the importaddress RPC to the
+ # importdescriptors RPC (with argument 'timestamp'='now'), which always rescans
+ # blocks of the past 2 hours, based on the current MTP timestamp; in order to avoid
+ # importing the last address (wo3), we advance the time further and generate 10 blocks
+ if self.options.descriptors:
+ set_node_times(self.nodes, cur_time + ten_days + ten_days + ten_days + ten_days)
+ self.generatetoaddress(minernode, 10, m1)
+
restorewo_wallet.importaddress(wo1, rescan=False)
restorewo_wallet.importaddress(wo2, rescan=False)
restorewo_wallet.importaddress(wo3, rescan=False)
diff --git a/test/lint/git-subtree-check.sh b/test/lint/git-subtree-check.sh
index cdaa5752ac..83816bb242 100755
--- a/test/lint/git-subtree-check.sh
+++ b/test/lint/git-subtree-check.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-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.
diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh
index ab3866d23e..69185090d1 100755
--- a/test/lint/lint-circular-dependencies.sh
+++ b/test/lint/lint-circular-dependencies.sh
@@ -15,12 +15,10 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
"index/base -> validation -> index/blockfilterindex -> index/base"
"index/coinstatsindex -> node/coinstats -> index/coinstatsindex"
"policy/fees -> txmempool -> policy/fees"
- "policy/rbf -> txmempool -> validation -> policy/rbf"
"qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel"
"qt/recentrequeststablemodel -> qt/walletmodel -> qt/recentrequeststablemodel"
"qt/sendcoinsdialog -> qt/walletmodel -> qt/sendcoinsdialog"
"qt/transactiontablemodel -> qt/walletmodel -> qt/transactiontablemodel"
- "txmempool -> validation -> txmempool"
"wallet/fees -> wallet/wallet -> wallet/fees"
"wallet/wallet -> wallet/walletdb -> wallet/wallet"
"node/coinstats -> validation -> node/coinstats"
diff --git a/test/lint/lint-files.sh b/test/lint/lint-files.sh
index f9ede4bc68..86d7fc724a 100755
--- a/test/lint/lint-files.sh
+++ b/test/lint/lint-files.sh
@@ -1,4 +1,7 @@
#!/usr/bin/env bash
+# Copyright (c) 2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C
diff --git a/test/lint/lint-git-commit-check.sh b/test/lint/lint-git-commit-check.sh
index d1ab72658b..f77373ed00 100755
--- a/test/lint/lint-git-commit-check.sh
+++ b/test/lint/lint-git-commit-check.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/lint/lint-include-guards.sh b/test/lint/lint-include-guards.sh
index 23f53f027e..f14218aa74 100755
--- a/test/lint/lint-include-guards.sh
+++ b/test/lint/lint-include-guards.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-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.
#
diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh
index b58600e6cb..7d608eed6a 100755
--- a/test/lint/lint-locale-dependence.sh
+++ b/test/lint/lint-locale-dependence.sh
@@ -37,15 +37,13 @@ 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>(...) or the ParseInt*() functions.
# TODO: Reduce KNOWN_VIOLATIONS by replacing uses of locale dependent snprintf with strprintf.
KNOWN_VIOLATIONS=(
"src/dbwrapper.cpp:.*vsnprintf"
"src/test/dbwrapper_tests.cpp:.*snprintf"
"src/test/fuzz/locale.cpp"
"src/test/fuzz/string.cpp"
- "src/torcontrol.cpp:.*strtol"
+ "src/test/util_tests.cpp"
)
REGEXP_IGNORE_EXTERNAL_DEPENDENCIES="^src/(crypto/ctaes/|leveldb/|secp256k1/|minisketch/|tinyformat.h|univalue/)"
diff --git a/test/lint/lint-shell-locale.sh b/test/lint/lint-shell-locale.sh
index bd6b6ce05c..4c6b8a57e6 100755
--- a/test/lint/lint-shell-locale.sh
+++ b/test/lint/lint-shell-locale.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018 The Bitcoin Core developers
+# Copyright (c) 2018-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.
#
diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh
index 391f4825e8..5fa104fce6 100755
--- a/test/lint/lint-shell.sh
+++ b/test/lint/lint-shell.sh
@@ -20,12 +20,13 @@ if ! command -v shellcheck > /dev/null; then
exit $EXIT_CODE
fi
-SHELLCHECK_CMD=(shellcheck --external-sources --check-sourced)
+SHELLCHECK_CMD=(shellcheck --external-sources --check-sourced --source-path=SCRIPTDIR)
EXCLUDE="--exclude=$(IFS=','; echo "${disabled[*]}")"
# Check shellcheck directive used for sourced files
mapfile -t SOURCED_FILES < <(git ls-files | xargs gawk '/^# shellcheck shell=/ {print FILENAME} {nextfile}')
+mapfile -t GUIX_FILES < <(git ls-files contrib/guix contrib/shell | xargs gawk '/^#!\/usr\/bin\/env bash/ {print FILENAME} {nextfile}')
mapfile -t FILES < <(git ls-files -- '*.sh' | grep -vE 'src/(leveldb|secp256k1|minisketch|univalue)/')
-if ! "${SHELLCHECK_CMD[@]}" "$EXCLUDE" "${SOURCED_FILES[@]}" "${FILES[@]}"; then
+if ! "${SHELLCHECK_CMD[@]}" "$EXCLUDE" "${SOURCED_FILES[@]}" "${GUIX_FILES[@]}" "${FILES[@]}"; then
EXIT_CODE=1
fi
diff --git a/test/sanitizer_suppressions/lsan b/test/sanitizer_suppressions/lsan
index d2cb618d4e..828b1676f6 100644
--- a/test/sanitizer_suppressions/lsan
+++ b/test/sanitizer_suppressions/lsan
@@ -1,7 +1,4 @@
# Suppress warnings triggered in dependencies
-leak:libqminimal
-leak:libQt5Core
-leak:libQt5Gui
leak:libQt5Widgets
# false-positive due to use of secure_allocator<>
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index 2a729c66d9..393278bd6a 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -10,44 +10,58 @@ signed-integer-overflow:policy/feerate.cpp
# -fsanitize=integer suppressions
# ===============================
+# Dependencies
+# ------------
+# Suppressions in dependencies that are developed outside this repository.
+unsigned-integer-overflow:*/include/c++/
+unsigned-integer-overflow:bench/bench.h
+# unsigned-integer-overflow in FuzzedDataProvider's ConsumeIntegralInRange
+unsigned-integer-overflow:FuzzedDataProvider.h
+unsigned-integer-overflow:leveldb/
+unsigned-integer-overflow:minisketch/
+unsigned-integer-overflow:test/fuzz/crypto_diff_fuzz_chacha20.cpp
+implicit-integer-sign-change:*/include/boost/
+implicit-integer-sign-change:*/include/c++/
+implicit-integer-sign-change:*/new_allocator.h
+implicit-integer-sign-change:crc32c/
+# implicit-integer-sign-change in FuzzedDataProvider's ConsumeIntegralInRange
+implicit-integer-sign-change:FuzzedDataProvider.h
+implicit-integer-sign-change:minisketch/
+implicit-signed-integer-truncation:leveldb/
+implicit-unsigned-integer-truncation:*/include/c++/
+implicit-unsigned-integer-truncation:leveldb/
+implicit-unsigned-integer-truncation:test/fuzz/crypto_diff_fuzz_chacha20.cpp
+# std::variant warning fixed in https://github.com/gcc-mirror/gcc/commit/074436cf8cdd2a9ce75cadd36deb8301f00e55b9
+implicit-unsigned-integer-truncation:std::__detail::__variant::_Variant_storage
+shift-base:*/include/c++/
+shift-base:leveldb/
+shift-base:minisketch/
+shift-base:test/fuzz/crypto_diff_fuzz_chacha20.cpp
# Unsigned integer overflow occurs when the result of an unsigned integer
# computation cannot be represented in its type. Unlike signed integer overflow,
# this is not undefined behavior, but it is often unintentional. The list below
# contains files in which we expect unsigned integer overflows to occur. The
# list is used to suppress -fsanitize=integer warnings when running our CI UBSan
# job.
-unsigned-integer-overflow:*/include/c++/
unsigned-integer-overflow:addrman.cpp
unsigned-integer-overflow:arith_uint256.h
-unsigned-integer-overflow:basic_string.h
-unsigned-integer-overflow:bench/bench.h
unsigned-integer-overflow:bitcoin-tx.cpp
unsigned-integer-overflow:common/bloom.cpp
unsigned-integer-overflow:chain.cpp
unsigned-integer-overflow:chain.h
-unsigned-integer-overflow:coded_stream.h
unsigned-integer-overflow:coins.cpp
unsigned-integer-overflow:compressor.cpp
unsigned-integer-overflow:core_write.cpp
unsigned-integer-overflow:crypto/
-# unsigned-integer-overflow in FuzzedDataProvider's ConsumeIntegralInRange
-unsigned-integer-overflow:FuzzedDataProvider.h
unsigned-integer-overflow:hash.cpp
-unsigned-integer-overflow:leveldb/
-unsigned-integer-overflow:minisketch/
unsigned-integer-overflow:policy/fees.cpp
unsigned-integer-overflow:prevector.h
unsigned-integer-overflow:pubkey.h
unsigned-integer-overflow:script/interpreter.cpp
-unsigned-integer-overflow:stl_bvector.h
unsigned-integer-overflow:txmempool.cpp
unsigned-integer-overflow:util/strencodings.cpp
unsigned-integer-overflow:validation.cpp
-implicit-integer-sign-change:*/include/boost/
-implicit-integer-sign-change:*/include/c++/
-implicit-integer-sign-change:*/new_allocator.h
implicit-integer-sign-change:addrman.h
-implicit-integer-sign-change:arith_uint256.cpp
implicit-integer-sign-change:bech32.cpp
implicit-integer-sign-change:common/bloom.cpp
implicit-integer-sign-change:chain.cpp
@@ -55,58 +69,29 @@ implicit-integer-sign-change:chain.h
implicit-integer-sign-change:coins.h
implicit-integer-sign-change:compat/stdin.cpp
implicit-integer-sign-change:compressor.h
-implicit-integer-sign-change:crc32c/
implicit-integer-sign-change:crypto/
-# implicit-integer-sign-change in FuzzedDataProvider's ConsumeIntegralInRange
-implicit-integer-sign-change:FuzzedDataProvider.h
implicit-integer-sign-change:key.cpp
-implicit-integer-sign-change:minisketch/
implicit-integer-sign-change:noui.cpp
implicit-integer-sign-change:policy/fees.cpp
implicit-integer-sign-change:prevector.h
implicit-integer-sign-change:script/bitcoinconsensus.cpp
implicit-integer-sign-change:script/interpreter.cpp
implicit-integer-sign-change:serialize.h
-implicit-integer-sign-change:test/arith_uint256_tests.cpp
-implicit-integer-sign-change:test/coins_tests.cpp
-implicit-integer-sign-change:test/pow_tests.cpp
-implicit-integer-sign-change:test/prevector_tests.cpp
-implicit-integer-sign-change:test/sighash_tests.cpp
-implicit-integer-sign-change:test/skiplist_tests.cpp
implicit-integer-sign-change:test/streams_tests.cpp
-implicit-integer-sign-change:test/transaction_tests.cpp
implicit-integer-sign-change:txmempool.cpp
-implicit-integer-sign-change:util/strencodings.cpp
-implicit-integer-sign-change:util/strencodings.h
-implicit-integer-sign-change:validation.cpp
implicit-integer-sign-change:zmq/zmqpublishnotifier.cpp
implicit-signed-integer-truncation,implicit-integer-sign-change:chain.h
-implicit-signed-integer-truncation,implicit-integer-sign-change:test/skiplist_tests.cpp
implicit-signed-integer-truncation:addrman.cpp
implicit-signed-integer-truncation:addrman.h
implicit-signed-integer-truncation:chain.h
implicit-signed-integer-truncation:crypto/
-implicit-signed-integer-truncation:cuckoocache.h
-implicit-signed-integer-truncation:leveldb/
-implicit-signed-integer-truncation:miner.cpp
+implicit-signed-integer-truncation:node/miner.cpp
implicit-signed-integer-truncation:net.cpp
-implicit-signed-integer-truncation:net_processing.cpp
-implicit-signed-integer-truncation:netaddress.cpp
implicit-signed-integer-truncation:streams.h
-implicit-signed-integer-truncation:test/arith_uint256_tests.cpp
-implicit-signed-integer-truncation:test/skiplist_tests.cpp
implicit-signed-integer-truncation:torcontrol.cpp
-implicit-unsigned-integer-truncation:*/include/c++/
implicit-unsigned-integer-truncation:crypto/
-implicit-unsigned-integer-truncation:leveldb/
-# std::variant warning fixed in https://github.com/gcc-mirror/gcc/commit/074436cf8cdd2a9ce75cadd36deb8301f00e55b9
-implicit-unsigned-integer-truncation:std::__detail::__variant::_Variant_storage
-shift-base:*/include/c++/
shift-base:arith_uint256.cpp
shift-base:crypto/
shift-base:hash.cpp
-shift-base:leveldb/
-shift-base:minisketch/
-shift-base:net_processing.cpp
shift-base:streams.h
shift-base:util/bip32.cpp
diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json
index cca5732aa1..c9c64274c6 100644
--- a/test/util/data/bitcoin-util-test.json
+++ b/test/util/data/bitcoin-util-test.json
@@ -418,6 +418,29 @@
},
{ "exec": "./bitcoin-tx",
"args":
+ ["-create",
+ "in=00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff:0",
+ "set=privatekeys:[\"KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn\"]",
+ "set=prevtxs:[{\"txid\":\"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff\",\"vout\":0,\"amount\":\"0\", \"scriptPubKey\":\"0014751e76e8199196d454941c45d1b3a323f1433bd6\"}]",
+ "sign=ALL",
+ "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"],
+ "output_cmp": "txcreatesignsegwit1.hex",
+ "description": "Creates a new transaction with a single witness input and a single output, and then signs the transaction"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "in=00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff:0",
+ "set=privatekeys:[\"KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn\"]",
+ "set=prevtxs:[{\"txid\":\"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff\",\"vout\":0,\"scriptPubKey\":\"0014751e76e8199196d454941c45d1b3a323f1433bd6\"}]",
+ "sign=ALL",
+ "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"],
+ "return_code": 1,
+ "error_txt": "Missing amount for CTxOut with scriptPubKey=0014751e76e8199196d454941c45d1b3a323f1433bd6",
+ "description": "Tests the check for missing input amount for witness transactions"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
["-create", "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397", "nversion=1"],
"output_cmp": "txcreateoutpubkey1.hex",
"description": "Creates a new transaction with a single pay-to-pubkey output"
diff --git a/test/util/data/txcreatesignsegwit1.hex b/test/util/data/txcreatesignsegwit1.hex
new file mode 100644
index 0000000000..45dd1f1dbf
--- /dev/null
+++ b/test/util/data/txcreatesignsegwit1.hex
@@ -0,0 +1 @@
+02000000000101ffeeddccbbaa99887766554433221100ffeeddccbbaa998877665544332211000000000000ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac0247304402202e8d8677912f73909ffbdb3ee87d10cce41d398ee206e534fa18330b566ece34022004f944f018a03c9f5b4cf0e9b0ae4f14049b55e7b6810a6ac26cd67cb4dcb31f01210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179800000000