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_psbt.json13
-rwxr-xr-xtest/functional/feature_bind_extra.py2
-rwxr-xr-xtest/functional/feature_block.py13
-rwxr-xr-xtest/functional/feature_blockfilterindex_prune.py25
-rwxr-xr-xtest/functional/feature_cltv.py9
-rwxr-xr-xtest/functional/feature_coinstatsindex.py4
-rwxr-xr-xtest/functional/feature_csv_activation.py2
-rwxr-xr-xtest/functional/feature_dersig.py2
-rwxr-xr-xtest/functional/feature_fee_estimation.py200
-rwxr-xr-xtest/functional/feature_init.py80
-rwxr-xr-xtest/functional/feature_maxuploadtarget.py2
-rwxr-xr-xtest/functional/feature_pruning.py22
-rwxr-xr-xtest/functional/feature_rbf.py15
-rwxr-xr-xtest/functional/feature_startupnotify.py41
-rwxr-xr-xtest/functional/feature_taproot.py7
-rwxr-xr-xtest/functional/feature_utxo_set_hash.py4
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py2
-rwxr-xr-xtest/functional/interface_rest.py31
-rwxr-xr-xtest/functional/mempool_accept.py81
-rwxr-xr-xtest/functional/mempool_reorg.py11
-rwxr-xr-xtest/functional/mempool_spend_coinbase.py2
-rwxr-xr-xtest/functional/mempool_updatefromblock.py2
-rwxr-xr-xtest/functional/mining_basic.py12
-rwxr-xr-xtest/functional/mocks/invalid_signer.py65
-rwxr-xr-xtest/functional/p2p_add_connections.py26
-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_timeouts.py43
-rwxr-xr-xtest/functional/rpc_blockchain.py2
-rwxr-xr-xtest/functional/rpc_createmultisig.py16
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py76
-rwxr-xr-xtest/functional/rpc_generate.py2
-rwxr-xr-xtest/functional/rpc_generateblock.py4
-rwxr-xr-xtest/functional/rpc_getblockfrompeer.py2
-rwxr-xr-xtest/functional/rpc_getblockstats.py8
-rwxr-xr-xtest/functional/rpc_getdescriptorinfo.py4
-rwxr-xr-xtest/functional/rpc_psbt.py91
-rwxr-xr-xtest/functional/rpc_scantxoutset.py156
-rw-r--r--test/functional/test_framework/blocktools.py5
-rwxr-xr-xtest/functional/test_framework/messages.py9
-rwxr-xr-xtest/functional/test_framework/test_node.py60
-rw-r--r--test/functional/test_framework/util.py8
-rw-r--r--test/functional/test_framework/wallet.py55
-rwxr-xr-xtest/functional/test_runner.py67
-rwxr-xr-xtest/functional/tool_wallet.py6
-rwxr-xr-xtest/functional/wallet_address_types.py20
-rwxr-xr-xtest/functional/wallet_backup.py24
-rwxr-xr-xtest/functional/wallet_groups.py15
-rwxr-xr-xtest/functional/wallet_hd.py2
-rwxr-xr-xtest/functional/wallet_listtransactions.py9
-rwxr-xr-xtest/functional/wallet_multiwallet.py2
-rwxr-xr-xtest/functional/wallet_send.py40
-rwxr-xr-xtest/functional/wallet_signer.py17
-rwxr-xr-xtest/lint/commit-script-check.sh5
-rwxr-xr-xtest/lint/git-subtree-check.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.sh1
-rwxr-xr-xtest/lint/lint-shell-locale.sh2
-rw-r--r--test/sanitizer_suppressions/lsan3
-rw-r--r--test/sanitizer_suppressions/ubsan67
-rw-r--r--test/util/data/bitcoin-util-test.json23
-rw-r--r--test/util/data/txcreatesignsegwit1.hex1
68 files changed, 1027 insertions, 583 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_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_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_block.py b/test/functional/feature_block.py
index a3253763bd..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)
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 eb90b2c598..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,7 +115,7 @@ 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)
@@ -145,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 8afd0ff74a..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"]
]
diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py
index c200445e81..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):
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index b7cb32c842..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'],
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
index cffbd40271..4b56b0c26b 100755
--- a/test/functional/feature_init.py
+++ b/test/functional/feature_init.py
@@ -44,80 +44,56 @@ class InitStressTest(BitcoinTestFramework):
def sigterm_node():
node.process.terminate()
node.process.wait()
- node.debug_log_path.unlink()
- node.debug_log_path.touch()
def check_clean_start():
"""Ensure that node restarts successfully after various interrupts."""
- # TODO: add -txindex=1 to fully test index initiatlization.
- # See https://github.com/bitcoin/bitcoin/pull/23289#discussion_r735159180 for
- # a discussion of the related bug.
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',
- 'loadblk thread start',
- # TODO: reenable - see above TODO
- # 'txindex thread start',
+ '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(
- # TODO: add -txindex=1 to fully test index initiatlization.
- # extra_args=['-txindex=1'],
- )
- logfile = open(node.debug_log_path, 'r', encoding='utf8')
+ node.start(extra_args=['-txindex=1'])
- MAX_SECS_TO_WAIT = 30
- start = time.time()
- num_lines = 0
-
- while True:
- line = logfile.readline()
- if line:
- num_lines += 1
-
- if line and terminate_line.lower() in line.lower():
- self.log.debug(f"Terminating node after {num_lines} log lines seen")
- sigterm_node()
- break
-
- if (time.time() - start) > MAX_SECS_TO_WAIT:
- raise AssertionError(
- f"missed line {terminate_line}; terminating now after {num_lines} lines")
-
- if node.process.poll() is not None:
- raise AssertionError(f"node failed to start (line: '{terminate_line}')")
+ 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()
- num_total_logs = len(node.debug_log_path.read_text().splitlines())
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):
- terminate_after = random.randint(1, num_total_logs)
- self.log.debug(f"Starting node and will exit after {terminate_after} lines")
- node.start(
- # TODO: add -txindex=1 to fully test index initiatlization.
- # extra_args=['-txindex=1'],
- )
- logfile = open(node.debug_log_path, 'r', encoding='utf8')
+ 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()
@@ -128,7 +104,8 @@ class InitStressTest(BitcoinTestFramework):
if line:
num_lines += 1
- if num_lines >= terminate_after or (time.time() - start) > MAX_SECS_TO_WAIT:
+ 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
@@ -148,11 +125,12 @@ class InitStressTest(BitcoinTestFramework):
}
for file_patt, err_fragment in files_to_disturb.items():
- target_file = list(node.chain_path.glob(file_patt))[0]
+ target_files = list(node.chain_path.glob(file_patt))
- self.log.info(f"Tweaking file to ensure failure {target_file}")
- bak_path = str(target_file) + ".bak"
- target_file.rename(bak_path)
+ 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.
@@ -166,14 +144,16 @@ class InitStressTest(BitcoinTestFramework):
# investigate doing this later.
node.assert_start_raises_init_error(
- # TODO: add -txindex=1 to fully test index initiatlization.
- # extra_args=['-txindex=1'],
+ extra_args=['-txindex=1'],
expected_msg=err_fragment,
match=ErrorMatch.PARTIAL_REGEX,
)
- self.log.info(f"Restoring file from {bak_path} and restarting")
- Path(bak_path).rename(target_file)
+ 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)
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 5722e71c7a..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()
@@ -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 e9da6edaf6..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,
@@ -1516,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()
@@ -1604,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))
@@ -1664,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/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index 2ea9ebfc98..db5564ac50 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -140,7 +140,7 @@ class TestBitcoinCli(BitcoinTestFramework):
if self.is_specified_wallet_compiled():
self.log.info("Test -getinfo and bitcoin-cli getwalletinfo return expected wallet info")
- # Explicitely set the output type in order to have constintent tx vsize / fees
+ # 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)
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/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_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/mempool_updatefromblock.py b/test/functional/mempool_updatefromblock.py
index 16c15e3f74..51de582ce0 100755
--- a/test/functional/mempool_updatefromblock.py
+++ b/test/functional/mempool_updatefromblock.py
@@ -17,7 +17,7 @@ from test_framework.util import assert_equal
class MempoolUpdateFromBlockTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['-limitdescendantsize=1000', '-limitancestorsize=1000']]
+ self.extra_args = [['-limitdescendantsize=1000', '-limitancestorsize=1000', '-limitancestorcount=100']]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
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 b86502dc85..f4462673f2 100755
--- a/test/functional/p2p_add_connections.py
+++ b/test/functional/p2p_add_connections.py
@@ -1,13 +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 check_node_connections
-
+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):
@@ -85,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_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/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index 8f7d5114fa..4dd4899f74 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -329,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_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 17d11a3ceb..759e43194b 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -4,8 +4,10 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the fundrawtransaction RPC."""
+
from decimal import Decimal
from itertools import product
+from math import ceil
from test_framework.descriptors import descsum_create
from test_framework.key import ECKey
@@ -571,12 +573,12 @@ class RawTransactionsTest(BitcoinTestFramework):
if self.options.descriptors:
self.nodes[1].walletpassphrase('test', 10)
self.nodes[1].importdescriptors([{
- 'desc': descsum_create('tr(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/0h/*h)'),
+ 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/0h/*h)'),
'timestamp': 'now',
'active': True
},
{
- 'desc': descsum_create('tr(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/1h/*h)'),
+ 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/1h/*h)'),
'timestamp': 'now',
'active': True,
'internal': True
@@ -778,18 +780,11 @@ class RawTransactionsTest(BitcoinTestFramework):
for param, zero_value in product(["fee_rate", "feeRate"], [0, 0.000, 0.00000000, "0", "0.000", "0.00000000"]):
assert_equal(self.nodes[3].fundrawtransaction(rawtx, {param: zero_value})["fee"], 0)
- if self.options.descriptors:
- # With no arguments passed, expect fee of 153 satoshis as descriptor wallets now have a taproot output.
- assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000153, vspan=0.00000001)
- # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
- result = node.fundrawtransaction(rawtx, {"fee_rate": 10000})
- assert_approx(result["fee"], vexp=0.0153, vspan=0.0001)
- else:
- # With no arguments passed, expect fee of 141 satoshis as legacy wallets only support up to segwit v0.
- assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001)
- # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
- result = node.fundrawtransaction(rawtx, {"fee_rate": 10000})
- assert_approx(result["fee"], vexp=0.0141, vspan=0.0001)
+ # With no arguments passed, expect fee of 141 satoshis.
+ assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001)
+ # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
+ result = node.fundrawtransaction(rawtx, {"fee_rate": 10000})
+ assert_approx(result["fee"], vexp=0.0141, vspan=0.0001)
self.log.info("Test fundrawtxn with invalid estimate_mode settings")
for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
@@ -1010,7 +1005,7 @@ class RawTransactionsTest(BitcoinTestFramework):
ext_utxo = self.nodes[0].listunspent(addresses=[addr])[0]
# An external input without solving data should result in an error
- raw_tx = wallet.createrawtransaction([ext_utxo], {self.nodes[0].getnewaddress(): 15})
+ raw_tx = wallet.createrawtransaction([ext_utxo], {self.nodes[0].getnewaddress(): ext_utxo["amount"] / 2})
assert_raises_rpc_error(-4, "Insufficient funds", wallet.fundrawtransaction, raw_tx)
# Error conditions
@@ -1018,6 +1013,12 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-5, "'01234567890a0b0c0d0e0f' is not a valid public key", wallet.fundrawtransaction, raw_tx, {"solving_data": {"pubkeys":["01234567890a0b0c0d0e0f"]}})
assert_raises_rpc_error(-5, "'not a script' is not hex", wallet.fundrawtransaction, raw_tx, {"solving_data": {"scripts":["not a script"]}})
assert_raises_rpc_error(-8, "Unable to parse descriptor 'not a descriptor'", wallet.fundrawtransaction, raw_tx, {"solving_data": {"descriptors":["not a descriptor"]}})
+ assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"]}]})
+ assert_raises_rpc_error(-8, "Invalid parameter, vout cannot be negative", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": -1}]})
+ assert_raises_rpc_error(-8, "Invalid parameter, missing weight key", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"]}]})
+ assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be less than 165", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 164}]})
+ assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be less than 165", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": -1}]})
+ assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be greater than", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 400001}]})
# But funding should work when the solving data is provided
funded_tx = wallet.fundrawtransaction(raw_tx, {"solving_data": {"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]}})
@@ -1027,10 +1028,45 @@ class RawTransactionsTest(BitcoinTestFramework):
assert signed_tx['complete']
funded_tx = wallet.fundrawtransaction(raw_tx, {"solving_data": {"descriptors": [desc]}})
- signed_tx = wallet.signrawtransactionwithwallet(funded_tx['hex'])
- assert not signed_tx['complete']
- signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx['hex'])
- assert signed_tx['complete']
+ signed_tx1 = wallet.signrawtransactionwithwallet(funded_tx['hex'])
+ assert not signed_tx1['complete']
+ signed_tx2 = self.nodes[0].signrawtransactionwithwallet(signed_tx1['hex'])
+ assert signed_tx2['complete']
+
+ unsigned_weight = self.nodes[0].decoderawtransaction(signed_tx1["hex"])["weight"]
+ signed_weight = self.nodes[0].decoderawtransaction(signed_tx2["hex"])["weight"]
+ # Input's weight is difference between weight of signed and unsigned,
+ # and the weight of stuff that didn't change (prevout, sequence, 1 byte of scriptSig)
+ input_weight = signed_weight - unsigned_weight + (41 * 4)
+ low_input_weight = input_weight // 2
+ high_input_weight = input_weight * 2
+
+ # Funding should also work if the input weight is provided
+ funded_tx = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}]})
+ signed_tx = wallet.signrawtransactionwithwallet(funded_tx["hex"])
+ signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx["hex"])
+ assert_equal(self.nodes[0].testmempoolaccept([signed_tx["hex"]])[0]["allowed"], True)
+ assert_equal(signed_tx["complete"], True)
+ # Reducing the weight should have a lower fee
+ funded_tx2 = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}]})
+ assert_greater_than(funded_tx["fee"], funded_tx2["fee"])
+ # Increasing the weight should have a higher fee
+ funded_tx2 = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}]})
+ assert_greater_than(funded_tx2["fee"], funded_tx["fee"])
+ # The provided weight should override the calculated weight when solving data is provided
+ funded_tx3 = wallet.fundrawtransaction(raw_tx, {"solving_data": {"descriptors": [desc]}, "input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}]})
+ assert_equal(funded_tx2["fee"], funded_tx3["fee"])
+ # The feerate should be met
+ funded_tx4 = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], "fee_rate": 10})
+ input_add_weight = high_input_weight - (41 * 4)
+ tx4_weight = wallet.decoderawtransaction(funded_tx4["hex"])["weight"] + input_add_weight
+ tx4_vsize = int(ceil(tx4_weight / 4))
+ assert_fee_amount(funded_tx4["fee"], tx4_vsize, Decimal(0.0001))
+
+ # Funding with weight at csuint boundaries should not cause problems
+ funded_tx = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 255}]})
+ funded_tx = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 65539}]})
+
self.nodes[2].unloadwallet("extfund")
def test_include_unsafe(self):
@@ -1080,7 +1116,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Make sure the default wallet will not be loaded when restarted with a high minrelaytxfee
self.nodes[0].unloadwallet(self.default_wallet_name, False)
feerate = Decimal("0.1")
- self.restart_node(0, [f"-minrelaytxfee={feerate}", "-discardfee=0", "-changetype=bech32", "-addresstype=bech32"]) # Set high minrelayfee, set discardfee to 0 for easier calculation
+ self.restart_node(0, [f"-minrelaytxfee={feerate}", "-discardfee=0"]) # Set high minrelayfee, set discardfee to 0 for easier calculation
self.nodes[0].loadwallet(self.default_wallet_name, True)
funds = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
diff --git a/test/functional/rpc_generate.py b/test/functional/rpc_generate.py
index ac44f0b7f7..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."""
diff --git a/test/functional/rpc_generateblock.py b/test/functional/rpc_generateblock.py
index 7aede0e947..7eeb745817 100755
--- a/test/functional/rpc_generateblock.py
+++ b/test/functional/rpc_generateblock.py
@@ -63,7 +63,7 @@ class GenerateBlockTest(BitcoinTestFramework):
assert_equal(block['tx'][1], txid)
self.log.info('Generate block with raw tx')
- rawtx = miniwallet.create_self_transfer(from_node=node)['hex']
+ rawtx = miniwallet.create_self_transfer()['hex']
hash = self.generateblock(node, address, [rawtx])['hash']
block = node.getblock(hash, 1)
@@ -74,7 +74,7 @@ class GenerateBlockTest(BitcoinTestFramework):
self.log.info('Fail to generate block with out of order txs')
txid1 = miniwallet.send_self_transfer(from_node=node)['txid']
utxo1 = miniwallet.get_utxo(txid=txid1)
- rawtx2 = miniwallet.create_self_transfer(from_node=node, utxo_to_spend=utxo1)['hex']
+ 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')
diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py
index 1ecf9c1057..b65322d920 100755
--- a/test/functional/rpc_getblockfrompeer.py
+++ b/test/functional/rpc_getblockfrompeer.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 the getblockfrompeer RPC."""
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_psbt.py b/test/functional/rpc_psbt.py
index a8034849cc..b037807b53 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -457,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
@@ -606,11 +606,15 @@ class PSBTTest(BitcoinTestFramework):
assert_raises_rpc_error(-25, 'Inputs missing or spent', self.nodes[0].walletprocesspsbt, 'cHNidP8BAJoCAAAAAkvEW8NnDtdNtDpsmze+Ht2LH35IJcKv00jKAlUs21RrAwAAAAD/////S8Rbw2cO1020OmybN74e3Ysffkglwq/TSMoCVSzbVGsBAAAAAP7///8CwLYClQAAAAAWABSNJKzjaUb3uOxixsvh1GGE3fW7zQD5ApUAAAAAFgAUKNw0x8HRctAgmvoevm4u1SbN7XIAAAAAAAEAnQIAAAACczMa321tVHuN4GKWKRncycI22aX3uXgwSFUKM2orjRsBAAAAAP7///9zMxrfbW1Ue43gYpYpGdzJwjbZpfe5eDBIVQozaiuNGwAAAAAA/v///wIA+QKVAAAAABl2qRT9zXUVA8Ls5iVqynLHe5/vSe1XyYisQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAAAAAQEfQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAA==')
- # Test that we can fund psbts with external inputs specified
+ self.log.info("Test that we can fund psbts with external inputs specified")
+
eckey = ECKey()
eckey.generate()
privkey = bytes_to_wif(eckey.get_bytes())
+ self.nodes[1].createwallet("extfund")
+ wallet = self.nodes[1].get_wallet_rpc("extfund")
+
# Make a weird but signable script. sh(pkh()) descriptor accomplishes this
desc = descsum_create("sh(pkh({}))".format(privkey))
if self.options.descriptors:
@@ -622,26 +626,97 @@ class PSBTTest(BitcoinTestFramework):
addr_info = self.nodes[0].getaddressinfo(addr)
self.nodes[0].sendtoaddress(addr, 10)
+ self.nodes[0].sendtoaddress(wallet.getnewaddress(), 10)
self.generate(self.nodes[0], 6)
ext_utxo = self.nodes[0].listunspent(addresses=[addr])[0]
# An external input without solving data should result in an error
- assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[1].walletcreatefundedpsbt, [ext_utxo], {self.nodes[0].getnewaddress(): 10 + ext_utxo['amount']}, 0, {'add_inputs': True})
+ assert_raises_rpc_error(-4, "Insufficient funds", wallet.walletcreatefundedpsbt, [ext_utxo], {self.nodes[0].getnewaddress(): 15})
# But funding should work when the solving data is provided
- psbt = self.nodes[1].walletcreatefundedpsbt([ext_utxo], {self.nodes[0].getnewaddress(): 15}, 0, {'add_inputs': True, "solving_data": {"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]}})
- signed = self.nodes[1].walletprocesspsbt(psbt['psbt'])
+ psbt = wallet.walletcreatefundedpsbt([ext_utxo], {self.nodes[0].getnewaddress(): 15}, 0, {"add_inputs": True, "solving_data": {"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]}})
+ signed = wallet.walletprocesspsbt(psbt['psbt'])
assert not signed['complete']
signed = self.nodes[0].walletprocesspsbt(signed['psbt'])
assert signed['complete']
self.nodes[0].finalizepsbt(signed['psbt'])
- psbt = self.nodes[1].walletcreatefundedpsbt([ext_utxo], {self.nodes[0].getnewaddress(): 15}, 0, {'add_inputs': True, "solving_data":{"descriptors": [desc]}})
- signed = self.nodes[1].walletprocesspsbt(psbt['psbt'])
+ psbt = wallet.walletcreatefundedpsbt([ext_utxo], {self.nodes[0].getnewaddress(): 15}, 0, {"add_inputs": True, "solving_data":{"descriptors": [desc]}})
+ signed = wallet.walletprocesspsbt(psbt['psbt'])
assert not signed['complete']
signed = self.nodes[0].walletprocesspsbt(signed['psbt'])
assert signed['complete']
- self.nodes[0].finalizepsbt(signed['psbt'])
+ final = self.nodes[0].finalizepsbt(signed['psbt'], False)
+
+ dec = self.nodes[0].decodepsbt(signed["psbt"])
+ for i, txin in enumerate(dec["tx"]["vin"]):
+ if txin["txid"] == ext_utxo["txid"] and txin["vout"] == ext_utxo["vout"]:
+ input_idx = i
+ break
+ psbt_in = dec["inputs"][input_idx]
+ # Calculate the input weight
+ # (prevout + sequence + length of scriptSig + 2 bytes buffer) * 4 + len of scriptwitness
+ len_scriptsig = len(psbt_in["final_scriptSig"]["hex"]) // 2 if "final_scriptSig" in psbt_in else 0
+ len_scriptwitness = len(psbt_in["final_scriptwitness"]["hex"]) // 2 if "final_scriptwitness" in psbt_in else 0
+ input_weight = ((41 + len_scriptsig + 2) * 4) + len_scriptwitness
+ low_input_weight = input_weight // 2
+ high_input_weight = input_weight * 2
+
+ # Input weight error conditions
+ assert_raises_rpc_error(
+ -8,
+ "Input weights should be specified in inputs rather than in options.",
+ wallet.walletcreatefundedpsbt,
+ inputs=[ext_utxo],
+ outputs={self.nodes[0].getnewaddress(): 15},
+ options={"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 1000}]}
+ )
+
+ # Funding should also work if the input weight is provided
+ psbt = wallet.walletcreatefundedpsbt(
+ inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}],
+ outputs={self.nodes[0].getnewaddress(): 15},
+ options={"add_inputs": True}
+ )
+ signed = wallet.walletprocesspsbt(psbt["psbt"])
+ signed = self.nodes[0].walletprocesspsbt(signed["psbt"])
+ final = self.nodes[0].finalizepsbt(signed["psbt"])
+ assert self.nodes[0].testmempoolaccept([final["hex"]])[0]["allowed"]
+ # Reducing the weight should have a lower fee
+ psbt2 = wallet.walletcreatefundedpsbt(
+ inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}],
+ outputs={self.nodes[0].getnewaddress(): 15},
+ options={"add_inputs": True}
+ )
+ assert_greater_than(psbt["fee"], psbt2["fee"])
+ # Increasing the weight should have a higher fee
+ psbt2 = wallet.walletcreatefundedpsbt(
+ inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}],
+ outputs={self.nodes[0].getnewaddress(): 15},
+ options={"add_inputs": True}
+ )
+ assert_greater_than(psbt2["fee"], psbt["fee"])
+ # The provided weight should override the calculated weight when solving data is provided
+ psbt3 = wallet.walletcreatefundedpsbt(
+ inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}],
+ outputs={self.nodes[0].getnewaddress(): 15},
+ options={'add_inputs': True, "solving_data":{"descriptors": [desc]}}
+ )
+ assert_equal(psbt2["fee"], psbt3["fee"])
+
+ # Import the external utxo descriptor so that we can sign for it from the test wallet
+ if self.options.descriptors:
+ res = wallet.importdescriptors([{"desc": desc, "timestamp": "now"}])
+ else:
+ res = wallet.importmulti([{"desc": desc, "timestamp": "now"}])
+ assert res[0]["success"]
+ # The provided weight should override the calculated weight for a wallet input
+ psbt3 = wallet.walletcreatefundedpsbt(
+ inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}],
+ outputs={self.nodes[0].getnewaddress(): 15},
+ options={"add_inputs": True}
+ )
+ assert_equal(psbt2["fee"], psbt3["fee"])
if __name__ == '__main__':
PSBTTest().main()
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 caa9b86969..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,
@@ -128,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:
@@ -156,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/test_node.py b/test/functional/test_framework/test_node.py
index b3279666b2..0b9154a030 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -389,14 +389,17 @@ class TestNode():
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
- with open(self.debug_log_path, encoding='utf-8') as dl:
- dl.seek(0, 2)
- prev_size = dl.tell()
+ prev_size = self.debug_log_bytes()
yield
@@ -419,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):
"""
@@ -578,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.
@@ -590,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 c3a9029d55..195af14914 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -379,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")
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 0a764a1755..eb2d030f4a 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -257,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',
@@ -304,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',
@@ -528,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)))
@@ -648,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:
@@ -668,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 afe4dba7b4..2cb9dc4523 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -390,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 eb6e497951..f7c80f805c 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -346,13 +346,13 @@ class AddressTypeTest(BitcoinTestFramework):
self.test_change_output_type(0, [to_address_bech32_1], 'legacy')
if self.options.descriptors:
- self.log.info("Nodes with addresstype=p2sh-segwit only use a bech32m change output if any destination address is bech32:")
+ 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], 'bech32m')
- self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32m')
- self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32m')
+ 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 only use a P2WPKH change output if any destination address is bech32:")
+ 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')
@@ -363,13 +363,13 @@ class AddressTypeTest(BitcoinTestFramework):
self.test_change_output_type(2, [to_address_p2sh], 'bech32')
if self.options.descriptors:
- self.log.info("Nodes with addresstype=bech32 always use either a bech32 or bech32m change output (unless changetype is set otherwise):")
- self.test_change_output_type(3, [to_address_bech32_1], 'bech32m')
- self.test_change_output_type(3, [to_address_p2sh], 'bech32')
+ 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 always use a P2WPKH change output (unless changetype is set otherwise):")
+ 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], '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')
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_groups.py b/test/functional/wallet_groups.py
index 9052bc7f7f..eb305c5fa2 100755
--- a/test/functional/wallet_groups.py
+++ b/test/functional/wallet_groups.py
@@ -108,17 +108,10 @@ class WalletGroupTest(BitcoinTestFramework):
assert_equal(input_addrs[0], input_addrs[1])
# Node 2 enforces avoidpartialspends so needs no checking here
- if self.options.descriptors:
- # Descriptor wallets will use Taproot change by default which has different fees
- tx4_ungrouped_fee = 3060
- tx4_grouped_fee = 4400
- tx5_6_ungrouped_fee = 5760
- tx5_6_grouped_fee = 8480
- else:
- tx4_ungrouped_fee = 2820
- tx4_grouped_fee = 4160
- tx5_6_ungrouped_fee = 5520
- tx5_6_grouped_fee = 8240
+ 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()
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index d78afb4212..ac878ea0aa 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -136,7 +136,7 @@ class WalletHDTest(BitcoinTestFramework):
keypath = self.nodes[1].getaddressinfo(out['scriptPubKey']['address'])['hdkeypath']
if self.options.descriptors:
- assert_equal(keypath[0:14], "m/86'/1'/0'/1/")
+ assert_equal(keypath[0:14], "m/84'/1'/0'/1/")
else:
assert_equal(keypath[0:7], "m/0'/1'")
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index 1b29d163c2..f75877f256 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -16,6 +16,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_array_result,
assert_equal,
+ assert_raises_rpc_error,
)
@@ -107,6 +108,7 @@ class ListTransactionsTest(BitcoinTestFramework):
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."""
@@ -275,6 +277,13 @@ class ListTransactionsTest(BitcoinTestFramework):
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_send.py b/test/functional/wallet_send.py
index d77d554baa..843a9f52b7 100755
--- a/test/functional/wallet_send.py
+++ b/test/functional/wallet_send.py
@@ -518,5 +518,45 @@ class WalletSendTest(BitcoinTestFramework):
assert signed["complete"]
self.nodes[0].finalizepsbt(signed["psbt"])
+ dec = self.nodes[0].decodepsbt(signed["psbt"])
+ for i, txin in enumerate(dec["tx"]["vin"]):
+ if txin["txid"] == ext_utxo["txid"] and txin["vout"] == ext_utxo["vout"]:
+ input_idx = i
+ break
+ psbt_in = dec["inputs"][input_idx]
+ # Calculate the input weight
+ # (prevout + sequence + length of scriptSig + 2 bytes buffer) * 4 + len of scriptwitness
+ len_scriptsig = len(psbt_in["final_scriptSig"]["hex"]) // 2 if "final_scriptSig" in psbt_in else 0
+ len_scriptwitness = len(psbt_in["final_scriptwitness"]["hex"]) // 2 if "final_scriptwitness" in psbt_in else 0
+ input_weight = ((41 + len_scriptsig + 2) * 4) + len_scriptwitness
+
+ # Input weight error conditions
+ assert_raises_rpc_error(
+ -8,
+ "Input weights should be specified in inputs rather than in options.",
+ ext_wallet.send,
+ outputs={self.nodes[0].getnewaddress(): 15},
+ options={"inputs": [ext_utxo], "input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 1000}]}
+ )
+
+ # Funding should also work when input weights are provided
+ res = self.test_send(
+ from_wallet=ext_wallet,
+ to_wallet=self.nodes[0],
+ amount=15,
+ inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}],
+ add_inputs=True,
+ psbt=True,
+ include_watching=True,
+ fee_rate=10
+ )
+ signed = ext_wallet.walletprocesspsbt(res["psbt"])
+ signed = ext_fund.walletprocesspsbt(res["psbt"])
+ assert signed["complete"]
+ tx = self.nodes[0].finalizepsbt(signed["psbt"])
+ testres = self.nodes[0].testmempoolaccept([tx["hex"]])[0]
+ assert_equal(testres["allowed"], True)
+ assert_fee_amount(testres["fees"]["base"], testres["vsize"], Decimal(0.0001))
+
if __name__ == '__main__':
WalletSendTest().main()
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/lint/commit-script-check.sh b/test/lint/commit-script-check.sh
index 6a8a15d05c..9449b393f1 100755
--- a/test/lint/commit-script-check.sh
+++ b/test/lint/commit-script-check.sh
@@ -17,6 +17,11 @@ if test -z "$1"; then
exit 1
fi
+if ! sed --help 2>&1 | grep -q 'GNU'; then
+ echo "Error: the installed sed package is not compatible. Please make sure you have GNU sed installed in your system.";
+ exit 1;
+fi
+
RET=0
PREV_BRANCH=$(git name-rev --name-only HEAD)
PREV_HEAD=$(git rev-parse HEAD)
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-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 661bc35175..7d608eed6a 100755
--- a/test/lint/lint-locale-dependence.sh
+++ b/test/lint/lint-locale-dependence.sh
@@ -43,6 +43,7 @@ KNOWN_VIOLATIONS=(
"src/test/dbwrapper_tests.cpp:.*snprintf"
"src/test/fuzz/locale.cpp"
"src/test/fuzz/string.cpp"
+ "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/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 bb7a1a5f45..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,56 +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:leveldb/
implicit-signed-integer-truncation:node/miner.cpp
implicit-signed-integer-truncation:net.cpp
-implicit-signed-integer-truncation:net_processing.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