aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/README.md6
-rwxr-xr-xtest/functional/feature_addrman.py2
-rwxr-xr-xtest/functional/feature_taproot.py16
-rwxr-xr-xtest/functional/interface_usdt_net.py2
-rwxr-xr-xtest/functional/interface_usdt_utxocache.py40
-rwxr-xr-xtest/functional/interface_usdt_validation.py2
-rwxr-xr-xtest/functional/mempool_package_limits.py316
-rwxr-xr-xtest/functional/p2p_permissions.py3
-rwxr-xr-xtest/functional/p2p_segwit.py6
-rwxr-xr-xtest/functional/rpc_psbt.py58
-rwxr-xr-xtest/functional/rpc_signmessagewithprivkey.py22
-rwxr-xr-xtest/functional/test_framework/messages.py14
-rw-r--r--test/functional/test_framework/psbt.py131
-rw-r--r--test/functional/test_framework/util.py12
-rw-r--r--test/functional/test_framework/wallet.py58
-rwxr-xr-xtest/functional/test_runner.py3
-rwxr-xr-xtest/functional/wallet_address_types.py28
-rwxr-xr-xtest/functional/wallet_avoid_mixing_output_types.py176
-rwxr-xr-xtest/functional/wallet_listtransactions.py6
-rwxr-xr-xtest/functional/wallet_simulaterawtx.py129
-rwxr-xr-xtest/get_previous_releases.py113
21 files changed, 763 insertions, 380 deletions
diff --git a/test/README.md b/test/README.md
index 6ca7cc0016..7d4a26fb4e 100644
--- a/test/README.md
+++ b/test/README.md
@@ -95,12 +95,14 @@ Run all possible tests with
test/functional/test_runner.py --extended
```
-In order to run backwards compatibility tests, download the previous node binaries:
+In order to run backwards compatibility tests, first run:
```
-test/get_previous_releases.py -b v23.0 v22.0 v0.21.0 v0.20.1 v0.19.1 v0.18.1 v0.17.2 v0.16.3 v0.15.2 v0.14.3
+test/get_previous_releases.py -b
```
+to download the necessary previous release binaries.
+
By default, up to 4 tests will be run in parallel by test_runner. To specify
how many jobs to run, append `--jobs=n`
diff --git a/test/functional/feature_addrman.py b/test/functional/feature_addrman.py
index 5e49d0214a..63abf0d9f8 100755
--- a/test/functional/feature_addrman.py
+++ b/test/functional/feature_addrman.py
@@ -95,7 +95,7 @@ class AddrmanTest(BitcoinTestFramework):
with open(peers_dat, "wb") as f:
f.write(serialize_addrman()[:-1])
self.nodes[0].assert_start_raises_init_error(
- expected_msg=init_error("CAutoFile::read: end of file.*"),
+ expected_msg=init_error("AutoFile::read: end of file.*"),
match=ErrorMatch.FULL_REGEX,
)
diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py
index 0e44038196..67cdc5ca32 100755
--- a/test/functional/feature_taproot.py
+++ b/test/functional/feature_taproot.py
@@ -91,7 +91,11 @@ from test_framework.script_util import (
script_to_p2wsh_script,
)
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_raises_rpc_error, assert_equal
+from test_framework.util import (
+ assert_raises_rpc_error,
+ assert_equal,
+ random_bytes,
+)
from test_framework.key import generate_privkey, compute_xonly_pubkey, sign_schnorr, tweak_add_privkey, ECKey
from test_framework.address import (
hash160,
@@ -566,10 +570,6 @@ def random_checksig_style(pubkey):
ret = CScript([pubkey, opcode])
return bytes(ret)
-def random_bytes(n):
- """Return a random bytes object of length n."""
- return bytes(random.getrandbits(8) for i in range(n))
-
def bitflipper(expr):
"""Return a callable that evaluates expr and returns it with a random bitflip."""
def fn(ctx):
@@ -1131,6 +1131,12 @@ def spenders_taproot_active():
tap = taproot_construct(pubs[0], scripts)
add_spender(spenders, "alwaysvalid/notsuccessx", tap=tap, leaf="op_success", inputs=[], standard=False, failure={"leaf": "normal"}) # err_msg differs based on opcode
+ # == Test case for https://github.com/bitcoin/bitcoin/issues/24765 ==
+
+ zero_fn = lambda h: bytes([0 for _ in range(32)])
+ tap = taproot_construct(pubs[0], [("leaf", CScript([pubs[1], OP_CHECKSIG, pubs[1], OP_CHECKSIGADD, OP_2, OP_EQUAL])), zero_fn])
+ add_spender(spenders, "case24765", tap=tap, leaf="leaf", inputs=[getter("sign"), getter("sign")], key=secs[1], no_fail=True)
+
# == Legacy tests ==
# Also add a few legacy spends into the mix, so that transactions which combine taproot and pre-taproot spends get tested too.
diff --git a/test/functional/interface_usdt_net.py b/test/functional/interface_usdt_net.py
index 9522cd8c59..2235da702b 100755
--- a/test/functional/interface_usdt_net.py
+++ b/test/functional/interface_usdt_net.py
@@ -109,7 +109,7 @@ class NetTracepointTest(BitcoinTestFramework):
self.log.info(
"hook into the net:inbound_message and net:outbound_message tracepoints")
- ctx = USDT(path=str(self.options.bitcoind))
+ ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="net:inbound_message",
fn_name="trace_inbound_message")
ctx.enable_probe(probe="net:outbound_message",
diff --git a/test/functional/interface_usdt_utxocache.py b/test/functional/interface_usdt_utxocache.py
index f48ff9699d..2280de1479 100755
--- a/test/functional/interface_usdt_utxocache.py
+++ b/test/functional/interface_usdt_utxocache.py
@@ -173,7 +173,7 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
invalid_tx.vin[0].prevout.hash = int(block_1_coinbase_txid, 16)
self.log.info("hooking into the utxocache:uncache tracepoint")
- ctx = USDT(path=str(self.options.bitcoind))
+ ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="utxocache:uncache",
fn_name="trace_utxocache_uncache")
bpf = BPF(text=utxocache_changes_program, usdt_contexts=[ctx], debug=0)
@@ -238,7 +238,7 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
self.log.info(
"hook into the utxocache:add and utxocache:spent tracepoints")
- ctx = USDT(path=str(self.options.bitcoind))
+ ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="utxocache:add", fn_name="trace_utxocache_add")
ctx.enable_probe(probe="utxocache:spent",
fn_name="trace_utxocache_spent")
@@ -334,7 +334,7 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
self.log.info("test the utxocache:flush tracepoint API")
self.log.info("hook into the utxocache:flush tracepoint")
- ctx = USDT(path=str(self.options.bitcoind))
+ ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="utxocache:flush",
fn_name="trace_utxocache_flush")
bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0)
@@ -345,16 +345,17 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
# that the handle_* functions succeeded.
EXPECTED_HANDLE_FLUSH_SUCCESS = 3
handle_flush_succeeds = 0
- possible_cache_sizes = set()
- expected_flushes = []
+ expected_flushes = list()
def handle_utxocache_flush(_, data, __):
nonlocal handle_flush_succeeds
event = ctypes.cast(data, ctypes.POINTER(UTXOCacheFlush)).contents
self.log.info(f"handle_utxocache_flush(): {event}")
- expected = expected_flushes.pop(0)
- assert_equal(expected["mode"], FLUSHMODE_NAME[event.mode])
- possible_cache_sizes.remove(event.size) # fails if size not in set
+ expected_flushes.remove({
+ "mode": FLUSHMODE_NAME[event.mode],
+ "for_prune": event.for_prune,
+ "size": event.size
+ })
# sanity checks only
assert(event.memory > 0)
assert(event.duration > 0)
@@ -363,20 +364,19 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush)
self.log.info("stop the node to flush the UTXO cache")
- UTXOS_IN_CACHE = 104 # might need to be changed if the eariler tests are modified
+ UTXOS_IN_CACHE = 2 # might need to be changed if the eariler tests are modified
# A node shutdown causes two flushes. One that flushes UTXOS_IN_CACHE
# UTXOs and one that flushes 0 UTXOs. Normally the 0-UTXO-flush is the
# second flush, however it can happen that the order changes.
- possible_cache_sizes = {UTXOS_IN_CACHE, 0}
- flush_for_shutdown = {"mode": "ALWAYS", "for_prune": False}
- expected_flushes.extend([flush_for_shutdown, flush_for_shutdown])
+ expected_flushes.append({"mode": "ALWAYS", "for_prune": False, "size": UTXOS_IN_CACHE})
+ expected_flushes.append({"mode": "ALWAYS", "for_prune": False, "size": 0})
self.stop_node(0)
bpf.perf_buffer_poll(timeout=200)
+ bpf.cleanup()
self.log.info("check that we don't expect additional flushes")
assert_equal(0, len(expected_flushes))
- assert_equal(0, len(possible_cache_sizes))
self.log.info("restart the node with -prune")
self.start_node(0, ["-fastprune=1", "-prune=1"])
@@ -384,12 +384,17 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
BLOCKS_TO_MINE = 350
self.log.info(f"mine {BLOCKS_TO_MINE} blocks to be able to prune")
self.generate(self.wallet, BLOCKS_TO_MINE)
- # we added BLOCKS_TO_MINE coinbase UTXOs to the cache
- possible_cache_sizes = {BLOCKS_TO_MINE}
- expected_flushes.append(
- {"mode": "NONE", "for_prune": True, "size_fn": lambda x: x == BLOCKS_TO_MINE})
+
+ self.log.info("test the utxocache:flush tracepoint API with pruning")
+ self.log.info("hook into the utxocache:flush tracepoint")
+ ctx = USDT(pid=self.nodes[0].process.pid)
+ ctx.enable_probe(probe="utxocache:flush",
+ fn_name="trace_utxocache_flush")
+ bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0)
+ bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush)
self.log.info(f"prune blockchain to trigger a flush for pruning")
+ expected_flushes.append({"mode": "NONE", "for_prune": True, "size": 0})
self.nodes[0].pruneblockchain(315)
bpf.perf_buffer_poll(timeout=500)
@@ -398,7 +403,6 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
self.log.info(
f"check that we don't expect additional flushes and that the handle_* function succeeded")
assert_equal(0, len(expected_flushes))
- assert_equal(0, len(possible_cache_sizes))
assert_equal(EXPECTED_HANDLE_FLUSH_SUCCESS, handle_flush_succeeds)
diff --git a/test/functional/interface_usdt_validation.py b/test/functional/interface_usdt_validation.py
index d11809273b..fb1a91b914 100755
--- a/test/functional/interface_usdt_validation.py
+++ b/test/functional/interface_usdt_validation.py
@@ -94,7 +94,7 @@ class ValidationTracepointTest(BitcoinTestFramework):
expected_blocks = list()
self.log.info("hook into the validation:block_connected tracepoint")
- ctx = USDT(path=str(self.options.bitcoind))
+ ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="validation:block_connected",
fn_name="trace_block_connected")
bpf = BPF(text=validation_blockconnected_program,
diff --git a/test/functional/mempool_package_limits.py b/test/functional/mempool_package_limits.py
index 89a5c83826..1f12e93982 100755
--- a/test/functional/mempool_package_limits.py
+++ b/test/functional/mempool_package_limits.py
@@ -6,28 +6,16 @@
from decimal import Decimal
-from test_framework.address import ADDRESS_BCRT1_P2WSH_OP_TRUE
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import (
COIN,
- CTransaction,
- CTxInWitness,
- tx_from_hex,
WITNESS_SCALE_FACTOR,
)
-from test_framework.script import (
- CScript,
- OP_TRUE,
-)
from test_framework.util import (
assert_equal,
)
-from test_framework.wallet import (
- bulk_transaction,
- create_child_with_parents,
- make_chain,
- DEFAULT_FEE,
-)
+from test_framework.wallet import MiniWallet
class MempoolPackageLimitsTest(BitcoinTestFramework):
def set_test_params(self):
@@ -35,19 +23,10 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
self.setup_clean_chain = True
def run_test(self):
- self.log.info("Generate blocks to create UTXOs")
- node = self.nodes[0]
- self.privkeys = [node.get_deterministic_priv_key().key]
- self.address = node.get_deterministic_priv_key().address
- self.coins = []
- # The last 100 coinbase transactions are premature
- for b in self.generatetoaddress(node, 200, self.address)[:100]:
- coinbase = node.getblock(blockhash=b, verbosity=2)["tx"][0]
- self.coins.append({
- "txid": coinbase["txid"],
- "amount": coinbase["vout"][0]["value"],
- "scriptPubKey": coinbase["vout"][0]["scriptPubKey"],
- })
+ self.wallet = MiniWallet(self.nodes[0])
+ # Add enough mature utxos to the wallet so that all txs spend confirmed coins.
+ self.generate(self.wallet, 35)
+ self.generate(self.nodes[0], COINBASE_MATURITY)
self.test_chain_limits()
self.test_desc_count_limits()
@@ -56,30 +35,22 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
self.test_anc_count_limits_2()
self.test_anc_count_limits_bushy()
- # The node will accept our (nonstandard) extra large OP_RETURN outputs
- self.restart_node(0, extra_args=["-acceptnonstdtxn=1"])
+ # The node will accept (nonstandard) extra large OP_RETURN outputs
+ self.restart_node(0, extra_args=["-datacarriersize=100000"])
self.test_anc_size_limits()
self.test_desc_size_limits()
def test_chain_limits_helper(self, mempool_count, package_count):
node = self.nodes[0]
assert_equal(0, node.getmempoolinfo()["size"])
- first_coin = self.coins.pop()
- spk = None
- txid = first_coin["txid"]
chain_hex = []
- chain_txns = []
- value = first_coin["amount"]
-
- for i in range(mempool_count + package_count):
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk)
- txid = tx.rehash()
- if i < mempool_count:
- node.sendrawtransaction(txhex)
- assert_equal(node.getmempoolentry(txid)["ancestorcount"], i + 1)
- else:
- chain_hex.append(txhex)
- chain_txns.append(tx)
+
+ chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=mempool_count)
+ # in-package transactions
+ for _ in range(package_count):
+ tx = self.wallet.create_self_transfer(utxo_to_spend=chaintip_utxo)
+ chaintip_utxo = tx["new_utxo"]
+ chain_hex.append(tx["hex"])
testres_too_long = node.testmempoolaccept(rawtxs=chain_hex)
for txres in testres_too_long:
assert_equal(txres["package-error"], "package-mempool-limits")
@@ -125,49 +96,20 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
assert_equal(0, node.getmempoolinfo()["size"])
self.log.info("Check that in-mempool and in-package descendants are calculated properly in packages")
# Top parent in mempool, M1
- first_coin = self.coins.pop()
- parent_value = (first_coin["amount"] - Decimal("0.0002")) / 2 # Deduct reasonable fee and make 2 outputs
- inputs = [{"txid": first_coin["txid"], "vout": 0}]
- outputs = [{self.address : parent_value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE : parent_value}]
- rawtx = node.createrawtransaction(inputs, outputs)
-
- parent_signed = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=self.privkeys)
- assert parent_signed["complete"]
- parent_tx = tx_from_hex(parent_signed["hex"])
- parent_txid = parent_tx.rehash()
- node.sendrawtransaction(parent_signed["hex"])
+ m1_utxos = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2)['new_utxos']
package_hex = []
-
- # Chain A
- spk = parent_tx.vout[0].scriptPubKey.hex()
- value = parent_value
- txid = parent_txid
- for i in range(12):
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk)
- txid = tx.rehash()
- if i < 11: # M2a... M12a
- node.sendrawtransaction(txhex)
- else: # Pa
- package_hex.append(txhex)
-
- # Chain B
- value = parent_value - Decimal("0.0001")
- rawtx_b = node.createrawtransaction([{"txid": parent_txid, "vout": 1}], {self.address : value})
- tx_child_b = tx_from_hex(rawtx_b) # M2b
- tx_child_b.wit.vtxinwit = [CTxInWitness()]
- tx_child_b.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
- tx_child_b_hex = tx_child_b.serialize().hex()
- node.sendrawtransaction(tx_child_b_hex)
- spk = tx_child_b.vout[0].scriptPubKey.hex()
- txid = tx_child_b.rehash()
- for i in range(12):
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk)
- txid = tx.rehash()
- if i < 11: # M3b... M13b
- node.sendrawtransaction(txhex)
- else: # Pb
- package_hex.append(txhex)
+ # Chain A (M2a... M12a)
+ chain_a_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=11, utxo_to_spend=m1_utxos[0])
+ # Pa
+ pa_hex = self.wallet.create_self_transfer(utxo_to_spend=chain_a_tip_utxo)["hex"]
+ package_hex.append(pa_hex)
+
+ # Chain B (M2b... M13b)
+ chain_b_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12, utxo_to_spend=m1_utxos[1])
+ # Pb
+ pb_hex = self.wallet.create_self_transfer(utxo_to_spend=chain_b_tip_utxo)["hex"]
+ package_hex.append(pb_hex)
assert_equal(24, node.getmempoolinfo()["size"])
assert_equal(2, len(package_hex))
@@ -200,41 +142,18 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
node = self.nodes[0]
package_hex = []
# M1
- first_coin_a = self.coins.pop()
- parent_value = (first_coin_a["amount"] - DEFAULT_FEE) / 2 # Deduct reasonable fee and make 2 outputs
- inputs = [{"txid": first_coin_a["txid"], "vout": 0}]
- outputs = [{self.address : parent_value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE : parent_value}]
- rawtx = node.createrawtransaction(inputs, outputs)
-
- parent_signed = node.signrawtransactionwithkey(hexstring=rawtx, privkeys=self.privkeys)
- assert parent_signed["complete"]
- parent_tx = tx_from_hex(parent_signed["hex"])
- parent_txid = parent_tx.rehash()
- node.sendrawtransaction(parent_signed["hex"])
+ m1_utxos = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2)['new_utxos']
# Chain M2...M24
- spk = parent_tx.vout[0].scriptPubKey.hex()
- value = parent_value
- txid = parent_txid
- for i in range(23): # M2...M24
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk)
- txid = tx.rehash()
- node.sendrawtransaction(txhex)
+ self.wallet.send_self_transfer_chain(from_node=node, chain_length=23, utxo_to_spend=m1_utxos[0])
# P1
- value_p1 = (parent_value - DEFAULT_FEE)
- rawtx_p1 = node.createrawtransaction([{"txid": parent_txid, "vout": 1}], [{self.address : value_p1}])
- tx_child_p1 = tx_from_hex(rawtx_p1)
- tx_child_p1.wit.vtxinwit = [CTxInWitness()]
- tx_child_p1.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
- tx_child_p1_hex = tx_child_p1.serialize().hex()
- txid_child_p1 = tx_child_p1.rehash()
- package_hex.append(tx_child_p1_hex)
- tx_child_p1_spk = tx_child_p1.vout[0].scriptPubKey.hex()
+ p1_tx = self.wallet.create_self_transfer(utxo_to_spend=m1_utxos[1])
+ package_hex.append(p1_tx["hex"])
# P2
- (_, tx_child_p2_hex, _, _) = make_chain(node, self.address, self.privkeys, txid_child_p1, value_p1, 0, tx_child_p1_spk)
- package_hex.append(tx_child_p2_hex)
+ p2_tx = self.wallet.create_self_transfer(utxo_to_spend=p1_tx["new_utxo"])
+ package_hex.append(p2_tx["hex"])
assert_equal(24, node.getmempoolinfo()["size"])
assert_equal(2, len(package_hex))
@@ -266,32 +185,21 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
node = self.nodes[0]
assert_equal(0, node.getmempoolinfo()["size"])
package_hex = []
- parents_tx = []
- values = []
- scripts = []
+ pc_parent_utxos = []
self.log.info("Check that in-mempool and in-package ancestors are calculated properly in packages")
# Two chains of 13 transactions each
for _ in range(2):
- spk = None
- top_coin = self.coins.pop()
- txid = top_coin["txid"]
- value = top_coin["amount"]
- for i in range(13):
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk)
- txid = tx.rehash()
- if i < 12:
- node.sendrawtransaction(txhex)
- else: # Save the 13th transaction for the package
- package_hex.append(txhex)
- parents_tx.append(tx)
- scripts.append(spk)
- values.append(value)
+ chain_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12)
+ # Save the 13th transaction for the package
+ tx = self.wallet.create_self_transfer(utxo_to_spend=chain_tip_utxo)
+ package_hex.append(tx["hex"])
+ pc_parent_utxos.append(tx["new_utxo"])
# Child Pc
- child_hex = create_child_with_parents(node, self.address, self.privkeys, parents_tx, values, scripts)
- package_hex.append(child_hex)
+ pc_hex = self.wallet.create_self_transfer_multi(utxos_to_spend=pc_parent_utxos)["hex"]
+ package_hex.append(pc_hex)
assert_equal(24, node.getmempoolinfo()["size"])
assert_equal(3, len(package_hex))
@@ -321,45 +229,29 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
"""
node = self.nodes[0]
assert_equal(0, node.getmempoolinfo()["size"])
- parents_tx = []
- values = []
- scripts = []
+ pc_parent_utxos = []
self.log.info("Check that in-mempool and in-package ancestors are calculated properly in packages")
# Two chains of 12 transactions each
for _ in range(2):
- spk = None
- top_coin = self.coins.pop()
- txid = top_coin["txid"]
- value = top_coin["amount"]
- for i in range(12):
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk)
- txid = tx.rehash()
- value -= Decimal("0.0001")
- node.sendrawtransaction(txhex)
- if i == 11:
- # last 2 transactions will be the parents of Pc
- parents_tx.append(tx)
- values.append(value)
- scripts.append(spk)
+ chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12)
+ # last 2 transactions will be the parents of Pc
+ pc_parent_utxos.append(chaintip_utxo)
# Child Pc
- pc_hex = create_child_with_parents(node, self.address, self.privkeys, parents_tx, values, scripts)
- pc_tx = tx_from_hex(pc_hex)
- pc_value = sum(values) - Decimal("0.0002")
- pc_spk = pc_tx.vout[0].scriptPubKey.hex()
+ pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=pc_parent_utxos)
# Child Pd
- (_, pd_hex, _, _) = make_chain(node, self.address, self.privkeys, pc_tx.rehash(), pc_value, 0, pc_spk)
+ pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0])
assert_equal(24, node.getmempoolinfo()["size"])
- testres_too_long = node.testmempoolaccept(rawtxs=[pc_hex, pd_hex])
+ testres_too_long = node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])
for txres in testres_too_long:
assert_equal(txres["package-error"], "package-mempool-limits")
# Clear mempool and check that the package passes now
self.generate(node, 1)
- assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=[pc_hex, pd_hex])])
+ assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])])
def test_anc_count_limits_bushy(self):
"""Create a tree with 20 transactions in the mempool and 6 in the package:
@@ -375,31 +267,18 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
node = self.nodes[0]
assert_equal(0, node.getmempoolinfo()["size"])
package_hex = []
- parent_txns = []
- parent_values = []
- scripts = []
+ pc_parent_utxos = []
for _ in range(5): # Make package transactions P0 ... P4
- gp_tx = []
- gp_values = []
- gp_scripts = []
+ pc_grandparent_utxos = []
for _ in range(4): # Make mempool transactions M(4i+1)...M(4i+4)
- parent_coin = self.coins.pop()
- value = parent_coin["amount"]
- txid = parent_coin["txid"]
- (tx, txhex, value, spk) = make_chain(node, self.address, self.privkeys, txid, value)
- gp_tx.append(tx)
- gp_values.append(value)
- gp_scripts.append(spk)
- node.sendrawtransaction(txhex)
+ pc_grandparent_utxos.append(self.wallet.send_self_transfer(from_node=node)["new_utxo"])
# Package transaction Pi
- pi_hex = create_child_with_parents(node, self.address, self.privkeys, gp_tx, gp_values, gp_scripts)
- package_hex.append(pi_hex)
- pi_tx = tx_from_hex(pi_hex)
- parent_txns.append(pi_tx)
- parent_values.append(Decimal(pi_tx.vout[0].nValue) / COIN)
- scripts.append(pi_tx.vout[0].scriptPubKey.hex())
+ pi_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=pc_grandparent_utxos)
+ package_hex.append(pi_tx["hex"])
+ pc_parent_utxos.append(pi_tx["new_utxos"][0])
# Package transaction PC
- package_hex.append(create_child_with_parents(node, self.address, self.privkeys, parent_txns, parent_values, scripts))
+ pc_hex = self.wallet.create_self_transfer_multi(utxos_to_spend=pc_parent_utxos)["hex"]
+ package_hex.append(pc_hex)
assert_equal(20, node.getmempoolinfo()["size"])
assert_equal(6, len(package_hex))
@@ -424,51 +303,30 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
"""
node = self.nodes[0]
assert_equal(0, node.getmempoolinfo()["size"])
- parents_tx = []
- values = []
- scripts = []
+ parent_utxos = []
target_weight = WITNESS_SCALE_FACTOR * 1000 * 30 # 30KvB
high_fee = Decimal("0.003") # 10 sats/vB
self.log.info("Check that in-mempool and in-package ancestor size limits are calculated properly in packages")
# Mempool transactions A and B
for _ in range(2):
- spk = None
- top_coin = self.coins.pop()
- txid = top_coin["txid"]
- value = top_coin["amount"]
- (tx, _, _, _) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk, high_fee)
- bulked_tx = bulk_transaction(tx, node, target_weight, self.privkeys)
- node.sendrawtransaction(bulked_tx.serialize().hex())
- parents_tx.append(bulked_tx)
- values.append(Decimal(bulked_tx.vout[0].nValue) / COIN)
- scripts.append(bulked_tx.vout[0].scriptPubKey.hex())
+ bulked_tx = self.wallet.create_self_transfer(target_weight=target_weight)
+ self.wallet.sendrawtransaction(from_node=node, tx_hex=bulked_tx["hex"])
+ parent_utxos.append(bulked_tx["new_utxo"])
# Package transaction C
- small_pc_hex = create_child_with_parents(node, self.address, self.privkeys, parents_tx, values, scripts, high_fee)
- pc_tx = bulk_transaction(tx_from_hex(small_pc_hex), node, target_weight, self.privkeys)
- pc_value = Decimal(pc_tx.vout[0].nValue) / COIN
- pc_spk = pc_tx.vout[0].scriptPubKey.hex()
- pc_hex = pc_tx.serialize().hex()
+ pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=int(high_fee * COIN), target_weight=target_weight)
# Package transaction D
- (small_pd, _, val, spk) = make_chain(node, self.address, self.privkeys, pc_tx.rehash(), pc_value, 0, pc_spk, high_fee)
- prevtxs = [{
- "txid": pc_tx.rehash(),
- "vout": 0,
- "scriptPubKey": spk,
- "amount": val,
- }]
- pd_tx = bulk_transaction(small_pd, node, target_weight, self.privkeys, prevtxs)
- pd_hex = pd_tx.serialize().hex()
+ pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0], target_weight=target_weight)
assert_equal(2, node.getmempoolinfo()["size"])
- testres_too_heavy = node.testmempoolaccept(rawtxs=[pc_hex, pd_hex])
+ testres_too_heavy = node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])
for txres in testres_too_heavy:
assert_equal(txres["package-error"], "package-mempool-limits")
# Clear mempool and check that the package passes now
self.generate(node, 1)
- assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=[pc_hex, pd_hex])])
+ assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])])
def test_desc_size_limits(self):
"""Create 3 mempool transactions and 2 package transactions (25KvB each):
@@ -486,50 +344,18 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
high_fee = Decimal("0.0021") # 10 sats/vB
self.log.info("Check that in-mempool and in-package descendant sizes are calculated properly in packages")
# Top parent in mempool, Ma
- first_coin = self.coins.pop()
- parent_value = (first_coin["amount"] - high_fee) / 2 # Deduct fee and make 2 outputs
- inputs = [{"txid": first_coin["txid"], "vout": 0}]
- outputs = [{self.address : parent_value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE: parent_value}]
- rawtx = node.createrawtransaction(inputs, outputs)
- parent_tx = bulk_transaction(tx_from_hex(rawtx), node, target_weight, self.privkeys)
- node.sendrawtransaction(parent_tx.serialize().hex())
+ ma_tx = self.wallet.create_self_transfer_multi(num_outputs=2, fee_per_output=int(high_fee / 2 * COIN), target_weight=target_weight)
+ self.wallet.sendrawtransaction(from_node=node, tx_hex=ma_tx["hex"])
package_hex = []
for j in range(2): # Two legs (left and right)
# Mempool transaction (Mb and Mc)
- mempool_tx = CTransaction()
- spk = parent_tx.vout[j].scriptPubKey.hex()
- value = Decimal(parent_tx.vout[j].nValue) / COIN
- txid = parent_tx.rehash()
- prevtxs = [{
- "txid": txid,
- "vout": j,
- "scriptPubKey": spk,
- "amount": value,
- }]
- if j == 0: # normal key
- (tx_small, _, _, _) = make_chain(node, self.address, self.privkeys, txid, value, j, spk, high_fee)
- mempool_tx = bulk_transaction(tx_small, node, target_weight, self.privkeys, prevtxs)
- else: # OP_TRUE
- inputs = [{"txid": txid, "vout": 1}]
- outputs = {self.address: value - high_fee}
- small_tx = tx_from_hex(node.createrawtransaction(inputs, outputs))
- mempool_tx = bulk_transaction(small_tx, node, target_weight, None, prevtxs)
- node.sendrawtransaction(mempool_tx.serialize().hex())
+ mempool_tx = self.wallet.create_self_transfer(utxo_to_spend=ma_tx["new_utxos"][j], target_weight=target_weight)
+ self.wallet.sendrawtransaction(from_node=node, tx_hex=mempool_tx["hex"])
# Package transaction (Pd and Pe)
- spk = mempool_tx.vout[0].scriptPubKey.hex()
- value = Decimal(mempool_tx.vout[0].nValue) / COIN
- txid = mempool_tx.rehash()
- (tx_small, _, _, _) = make_chain(node, self.address, self.privkeys, txid, value, 0, spk, high_fee)
- prevtxs = [{
- "txid": txid,
- "vout": 0,
- "scriptPubKey": spk,
- "amount": value,
- }]
- package_tx = bulk_transaction(tx_small, node, target_weight, self.privkeys, prevtxs)
- package_hex.append(package_tx.serialize().hex())
+ package_tx = self.wallet.create_self_transfer(utxo_to_spend=mempool_tx["new_utxo"], target_weight=target_weight)
+ package_hex.append(package_tx["hex"])
assert_equal(3, node.getmempoolinfo()["size"])
assert_equal(2, len(package_hex))
diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py
index 185011c2df..453a0920cc 100755
--- a/test/functional/p2p_permissions.py
+++ b/test/functional/p2p_permissions.py
@@ -111,7 +111,8 @@ class P2PPermissionsTests(BitcoinTestFramework):
'vout': 0,
}], outputs=[{
ADDRESS_BCRT1_P2WSH_OP_TRUE: 5,
- }]),
+ }],
+ replaceable=False),
)
tx.wit.vtxinwit = [CTxInWitness()]
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index db6954ccf6..311b0b67db 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -245,7 +245,7 @@ class SegWitTest(BitcoinTestFramework):
self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=P2P_SERVICES)
# self.old_node sets only NODE_NETWORK
self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)
- # self.std_node is for testing node1 (fRequireStandard=true)
+ # self.std_node is for testing node1 (requires standard txs)
self.std_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=P2P_SERVICES)
# self.std_wtx_node is for testing node1 with wtxid relay
self.std_wtx_node = self.nodes[1].add_p2p_connection(TestP2PConn(wtxidrelay=True), services=P2P_SERVICES)
@@ -1382,7 +1382,7 @@ class SegWitTest(BitcoinTestFramework):
tx3.vout.append(CTxOut(total_value - 1000, script_pubkey))
tx3.rehash()
- # First we test this transaction against fRequireStandard=true node
+ # First we test this transaction against std_node
# making sure the txid is added to the reject filter
self.std_node.announce_tx_and_wait_for_getdata(tx3)
test_transaction_acceptance(self.nodes[1], self.std_node, tx3, with_witness=True, accepted=False, reason="bad-txns-nonstandard-inputs")
@@ -1390,7 +1390,7 @@ class SegWitTest(BitcoinTestFramework):
self.std_node.announce_tx_and_wait_for_getdata(tx3, success=False)
# Spending a higher version witness output is not allowed by policy,
- # even with fRequireStandard=false.
+ # even with the node that accepts non-standard txs.
test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=False, reason="reserved for soft-fork upgrades")
# Building a block with the transaction must be valid, however.
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 93b8d81959..43a73671a5 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -11,10 +11,23 @@ from itertools import product
from test_framework.descriptors import descsum_create
from test_framework.key import ECKey, H_POINT
from test_framework.messages import (
+ COutPoint,
+ CTransaction,
+ CTxIn,
+ CTxOut,
MAX_BIP125_RBF_SEQUENCE,
WITNESS_SCALE_FACTOR,
ser_compact_size,
)
+from test_framework.psbt import (
+ PSBT,
+ PSBTMap,
+ PSBT_GLOBAL_UNSIGNED_TX,
+ PSBT_IN_RIPEMD160,
+ PSBT_IN_SHA256,
+ PSBT_IN_HASH160,
+ PSBT_IN_HASH256,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_approx,
@@ -23,6 +36,7 @@ from test_framework.util import (
assert_raises_rpc_error,
find_output,
find_vout_for_address,
+ random_bytes,
)
from test_framework.wallet_util import bytes_to_wif
@@ -453,7 +467,7 @@ class PSBTTest(BitcoinTestFramework):
# Creator Tests
for creator in creators:
- created_tx = self.nodes[0].createpsbt(creator['inputs'], creator['outputs'])
+ created_tx = self.nodes[0].createpsbt(inputs=creator['inputs'], outputs=creator['outputs'], replaceable=False)
assert_equal(created_tx, creator['result'])
# Signer tests
@@ -775,5 +789,47 @@ class PSBTTest(BitcoinTestFramework):
self.nodes[0].sendrawtransaction(rawtx)
self.generate(self.nodes[0], 1)
+ self.log.info("Test decoding PSBT with per-input preimage types")
+ # note that the decodepsbt RPC doesn't check whether preimages and hashes match
+ hash_ripemd160, preimage_ripemd160 = random_bytes(20), random_bytes(50)
+ hash_sha256, preimage_sha256 = random_bytes(32), random_bytes(50)
+ hash_hash160, preimage_hash160 = random_bytes(20), random_bytes(50)
+ hash_hash256, preimage_hash256 = random_bytes(32), random_bytes(50)
+
+ tx = CTransaction()
+ tx.vin = [CTxIn(outpoint=COutPoint(hash=int('aa' * 32, 16), n=0), scriptSig=b""),
+ CTxIn(outpoint=COutPoint(hash=int('bb' * 32, 16), n=0), scriptSig=b""),
+ CTxIn(outpoint=COutPoint(hash=int('cc' * 32, 16), n=0), scriptSig=b""),
+ CTxIn(outpoint=COutPoint(hash=int('dd' * 32, 16), n=0), scriptSig=b"")]
+ tx.vout = [CTxOut(nValue=0, scriptPubKey=b"")]
+ psbt = PSBT()
+ psbt.g = PSBTMap({PSBT_GLOBAL_UNSIGNED_TX: tx.serialize()})
+ psbt.i = [PSBTMap({bytes([PSBT_IN_RIPEMD160]) + hash_ripemd160: preimage_ripemd160}),
+ PSBTMap({bytes([PSBT_IN_SHA256]) + hash_sha256: preimage_sha256}),
+ PSBTMap({bytes([PSBT_IN_HASH160]) + hash_hash160: preimage_hash160}),
+ PSBTMap({bytes([PSBT_IN_HASH256]) + hash_hash256: preimage_hash256})]
+ psbt.o = [PSBTMap()]
+ res_inputs = self.nodes[0].decodepsbt(psbt.to_base64())["inputs"]
+ assert_equal(len(res_inputs), 4)
+ preimage_keys = ["ripemd160_preimages", "sha256_preimages", "hash160_preimages", "hash256_preimages"]
+ expected_hashes = [hash_ripemd160, hash_sha256, hash_hash160, hash_hash256]
+ expected_preimages = [preimage_ripemd160, preimage_sha256, preimage_hash160, preimage_hash256]
+ for res_input, preimage_key, hash, preimage in zip(res_inputs, preimage_keys, expected_hashes, expected_preimages):
+ assert preimage_key in res_input
+ assert_equal(len(res_input[preimage_key]), 1)
+ assert hash.hex() in res_input[preimage_key]
+ assert_equal(res_input[preimage_key][hash.hex()], preimage.hex())
+
+ self.log.info("Test that combining PSBTs with different transactions fails")
+ tx = CTransaction()
+ tx.vin = [CTxIn(outpoint=COutPoint(hash=int('aa' * 32, 16), n=0), scriptSig=b"")]
+ tx.vout = [CTxOut(nValue=0, scriptPubKey=b"")]
+ psbt1 = PSBT(g=PSBTMap({PSBT_GLOBAL_UNSIGNED_TX: tx.serialize()}), i=[PSBTMap()], o=[PSBTMap()]).to_base64()
+ tx.vout[0].nValue += 1 # slightly modify tx
+ psbt2 = PSBT(g=PSBTMap({PSBT_GLOBAL_UNSIGNED_TX: tx.serialize()}), i=[PSBTMap()], o=[PSBTMap()]).to_base64()
+ assert_raises_rpc_error(-8, "PSBTs not compatible (different transactions)", self.nodes[0].combinepsbt, [psbt1, psbt2])
+ assert_equal(self.nodes[0].combinepsbt([psbt1, psbt1]), psbt1)
+
+
if __name__ == '__main__':
PSBTTest().main()
diff --git a/test/functional/rpc_signmessagewithprivkey.py b/test/functional/rpc_signmessagewithprivkey.py
index 80555eab75..6635da150f 100755
--- a/test/functional/rpc_signmessagewithprivkey.py
+++ b/test/functional/rpc_signmessagewithprivkey.py
@@ -4,27 +4,44 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test RPC commands for signing messages with private key."""
+from test_framework.descriptors import (
+ descsum_create,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
+
class SignMessagesWithPrivTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
+ def addresses_from_privkey(self, priv_key):
+ '''Return addresses for a given WIF private key in legacy (P2PKH),
+ nested segwit (P2SH-P2WPKH) and native segwit (P2WPKH) formats.'''
+ descriptors = f'pkh({priv_key})', f'sh(wpkh({priv_key}))', f'wpkh({priv_key})'
+ return [self.nodes[0].deriveaddresses(descsum_create(desc))[0] for desc in descriptors]
+
def run_test(self):
message = 'This is just a test message'
self.log.info('test signing with priv_key')
priv_key = 'cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N'
- address = 'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB'
expected_signature = 'INbVnW4e6PeRmsv2Qgu8NuopvrVjkcxob+sX8OcZG0SALhWybUjzMLPdAsXI46YZGb0KQTRii+wWIQzRpG/U+S0='
signature = self.nodes[0].signmessagewithprivkey(priv_key, message)
assert_equal(expected_signature, signature)
- assert self.nodes[0].verifymessage(address, signature, message)
+
+ self.log.info('test that verifying with P2PKH address succeeds')
+ addresses = self.addresses_from_privkey(priv_key)
+ assert_equal(addresses[0], 'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB')
+ assert self.nodes[0].verifymessage(addresses[0], signature, message)
+
+ self.log.info('test that verifying with non-P2PKH addresses throws error')
+ for non_p2pkh_address in addresses[1:]:
+ assert_raises_rpc_error(-3, "Address does not refer to key", self.nodes[0].verifymessage, non_p2pkh_address, signature, message)
self.log.info('test parameter validity and error codes')
# signmessagewithprivkey has two required parameters
@@ -41,5 +58,6 @@ class SignMessagesWithPrivTest(BitcoinTestFramework):
# malformed signature provided
assert_raises_rpc_error(-3, "Malformed base64 encoding", self.nodes[0].verifymessage, 'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB', "invalid_sig", message)
+
if __name__ == '__main__':
SignMessagesWithPrivTest().main()
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index e6d9f9ae3a..4a68312379 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -208,6 +208,20 @@ def tx_from_hex(hex_string):
return from_hex(CTransaction(), hex_string)
+# like from_hex, but without the hex part
+def from_binary(cls, stream):
+ """deserialize a binary stream (or bytes object) into an object"""
+ # handle bytes object by turning it into a stream
+ was_bytes = isinstance(stream, bytes)
+ if was_bytes:
+ stream = BytesIO(stream)
+ obj = cls()
+ obj.deserialize(stream)
+ if was_bytes:
+ assert len(stream.read()) == 0
+ return obj
+
+
# Objects that map to bitcoind objects, which can be serialized/deserialized
diff --git a/test/functional/test_framework/psbt.py b/test/functional/test_framework/psbt.py
new file mode 100644
index 0000000000..68945e7e84
--- /dev/null
+++ b/test/functional/test_framework/psbt.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python3
+# Copyright (c) 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.
+
+import base64
+
+from .messages import (
+ CTransaction,
+ deser_string,
+ from_binary,
+ ser_compact_size,
+)
+
+
+# global types
+PSBT_GLOBAL_UNSIGNED_TX = 0x00
+PSBT_GLOBAL_XPUB = 0x01
+PSBT_GLOBAL_TX_VERSION = 0x02
+PSBT_GLOBAL_FALLBACK_LOCKTIME = 0x03
+PSBT_GLOBAL_INPUT_COUNT = 0x04
+PSBT_GLOBAL_OUTPUT_COUNT = 0x05
+PSBT_GLOBAL_TX_MODIFIABLE = 0x06
+PSBT_GLOBAL_VERSION = 0xfb
+PSBT_GLOBAL_PROPRIETARY = 0xfc
+
+# per-input types
+PSBT_IN_NON_WITNESS_UTXO = 0x00
+PSBT_IN_WITNESS_UTXO = 0x01
+PSBT_IN_PARTIAL_SIG = 0x02
+PSBT_IN_SIGHASH_TYPE = 0x03
+PSBT_IN_REDEEM_SCRIPT = 0x04
+PSBT_IN_WITNESS_SCRIPT = 0x05
+PSBT_IN_BIP32_DERIVATION = 0x06
+PSBT_IN_FINAL_SCRIPTSIG = 0x07
+PSBT_IN_FINAL_SCRIPTWITNESS = 0x08
+PSBT_IN_POR_COMMITMENT = 0x09
+PSBT_IN_RIPEMD160 = 0x0a
+PSBT_IN_SHA256 = 0x0b
+PSBT_IN_HASH160 = 0x0c
+PSBT_IN_HASH256 = 0x0d
+PSBT_IN_PREVIOUS_TXID = 0x0e
+PSBT_IN_OUTPUT_INDEX = 0x0f
+PSBT_IN_SEQUENCE = 0x10
+PSBT_IN_REQUIRED_TIME_LOCKTIME = 0x11
+PSBT_IN_REQUIRED_HEIGHT_LOCKTIME = 0x12
+PSBT_IN_TAP_KEY_SIG = 0x13
+PSBT_IN_TAP_SCRIPT_SIG = 0x14
+PSBT_IN_TAP_LEAF_SCRIPT = 0x15
+PSBT_IN_TAP_BIP32_DERIVATION = 0x16
+PSBT_IN_TAP_INTERNAL_KEY = 0x17
+PSBT_IN_TAP_MERKLE_ROOT = 0x18
+PSBT_IN_PROPRIETARY = 0xfc
+
+# per-output types
+PSBT_OUT_REDEEM_SCRIPT = 0x00
+PSBT_OUT_WITNESS_SCRIPT = 0x01
+PSBT_OUT_BIP32_DERIVATION = 0x02
+PSBT_OUT_AMOUNT = 0x03
+PSBT_OUT_SCRIPT = 0x04
+PSBT_OUT_TAP_INTERNAL_KEY = 0x05
+PSBT_OUT_TAP_TREE = 0x06
+PSBT_OUT_TAP_BIP32_DERIVATION = 0x07
+PSBT_OUT_PROPRIETARY = 0xfc
+
+
+class PSBTMap:
+ """Class for serializing and deserializing PSBT maps"""
+
+ def __init__(self, map=None):
+ self.map = map if map is not None else {}
+
+ def deserialize(self, f):
+ m = {}
+ while True:
+ k = deser_string(f)
+ if len(k) == 0:
+ break
+ v = deser_string(f)
+ if len(k) == 1:
+ k = k[0]
+ assert k not in m
+ m[k] = v
+ self.map = m
+
+ def serialize(self):
+ m = b""
+ for k,v in self.map.items():
+ if isinstance(k, int) and 0 <= k and k <= 255:
+ k = bytes([k])
+ m += ser_compact_size(len(k)) + k
+ m += ser_compact_size(len(v)) + v
+ m += b"\x00"
+ return m
+
+class PSBT:
+ """Class for serializing and deserializing PSBTs"""
+
+ def __init__(self, *, g=None, i=None, o=None):
+ self.g = g if g is not None else PSBTMap()
+ self.i = i if i is not None else []
+ self.o = o if o is not None else []
+ self.tx = None
+
+ def deserialize(self, f):
+ assert f.read(5) == b"psbt\xff"
+ self.g = from_binary(PSBTMap, f)
+ assert 0 in self.g.map
+ self.tx = from_binary(CTransaction, self.g.map[0])
+ self.i = [from_binary(PSBTMap, f) for _ in self.tx.vin]
+ self.o = [from_binary(PSBTMap, f) for _ in self.tx.vout]
+ return self
+
+ def serialize(self):
+ assert isinstance(self.g, PSBTMap)
+ assert isinstance(self.i, list) and all(isinstance(x, PSBTMap) for x in self.i)
+ assert isinstance(self.o, list) and all(isinstance(x, PSBTMap) for x in self.o)
+ assert 0 in self.g.map
+ tx = from_binary(CTransaction, self.g.map[0])
+ assert len(tx.vin) == len(self.i)
+ assert len(tx.vout) == len(self.o)
+
+ psbt = [x.serialize() for x in [self.g] + self.i + self.o]
+ return b"psbt\xff" + b"".join(psbt)
+
+ def to_base64(self):
+ return base64.b64encode(self.serialize()).decode("utf8")
+
+ @classmethod
+ def from_base64(cls, b64psbt):
+ return from_binary(cls, base64.b64decode(b64psbt))
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 58528b7858..bfc835f272 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -12,6 +12,7 @@ import inspect
import json
import logging
import os
+import random
import re
import time
import unittest
@@ -28,6 +29,10 @@ logger = logging.getLogger("TestFramework.utils")
def assert_approx(v, vexp, vspan=0.00001):
"""Assert that `v` is within `vspan` of `vexp`"""
+ if isinstance(v, Decimal) or isinstance(vexp, Decimal):
+ v=Decimal(v)
+ vexp=Decimal(vexp)
+ vspan=Decimal(vspan)
if v < vexp - vspan:
raise AssertionError("%s < [%s..%s]" % (str(v), str(vexp - vspan), str(vexp + vspan)))
if v > vexp + vspan:
@@ -286,6 +291,13 @@ def sha256sum_file(filename):
d = f.read(4096)
return h.digest()
+
+# TODO: Remove and use random.randbytes(n) instead, available in Python 3.9
+def random_bytes(n):
+ """Return a random bytes object of length n."""
+ return bytes(random.getrandbits(8) for i in range(n))
+
+
# RPC/P2P connection constants and functions
############################################
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 2164627781..374fda5c23 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -7,7 +7,6 @@
from copy import deepcopy
from decimal import Decimal
from enum import Enum
-from random import choice
from typing import (
Any,
List,
@@ -40,6 +39,7 @@ from test_framework.script import (
LegacySignatureHash,
LEAF_VERSION_TAPSCRIPT,
OP_NOP,
+ OP_RETURN,
OP_TRUE,
SIGHASH_ALL,
taproot_construct,
@@ -104,6 +104,18 @@ class MiniWallet:
def _create_utxo(self, *, txid, vout, value, height):
return {"txid": txid, "vout": vout, "value": value, "height": height}
+ def _bulk_tx(self, tx, target_weight):
+ """Pad a transaction with extra outputs until it reaches a target weight (or higher).
+ returns the tx
+ """
+ tx.vout.append(CTxOut(nValue=0, scriptPubKey=CScript([OP_RETURN, b'a'])))
+ dummy_vbytes = (target_weight - tx.get_weight() + 3) // 4
+ tx.vout[-1].scriptPubKey = CScript([OP_RETURN, b'a' * dummy_vbytes])
+ # Lower bound should always be off by at most 3
+ assert_greater_than_or_equal(tx.get_weight(), target_weight)
+ # Higher bound should always be off by at most 3 + 12 weight (for encoding the length)
+ assert_greater_than_or_equal(target_weight + 15, tx.get_weight())
+
def get_balance(self):
return sum(u['value'] for u in self._utxos)
@@ -235,6 +247,7 @@ class MiniWallet:
amount_per_output=0,
sequence=0,
fee_per_output=1000,
+ target_weight=0
):
"""
Create and return a transaction that spends the given UTXOs and creates a
@@ -265,6 +278,10 @@ class MiniWallet:
outputs_value_total = inputs_value_total - fee_per_output * num_outputs
for o in tx.vout:
o.nValue = amount_per_output or (outputs_value_total // num_outputs)
+
+ if target_weight:
+ self._bulk_tx(tx, target_weight)
+
txid = tx.rehash()
return {
"new_utxos": [self._create_utxo(
@@ -278,7 +295,7 @@ class MiniWallet:
"tx": tx,
}
- def create_self_transfer(self, *, fee_rate=Decimal("0.003"), fee=Decimal("0"), utxo_to_spend=None, locktime=0, sequence=0):
+ def create_self_transfer(self, *, fee_rate=Decimal("0.003"), fee=Decimal("0"), utxo_to_spend=None, locktime=0, sequence=0, target_weight=0):
"""Create and return a tx with the specified fee. If fee is 0, use fee_rate, where the resulting fee may be exact or at most one satoshi higher than needed."""
utxo_to_spend = utxo_to_spend or self.get_utxo()
assert fee_rate >= 0
@@ -305,9 +322,13 @@ class MiniWallet:
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key]
else:
assert False
- tx_hex = tx.serialize().hex()
assert_equal(tx.get_vsize(), vsize)
+
+ if target_weight:
+ self._bulk_tx(tx, target_weight)
+
+ tx_hex = tx.serialize().hex()
new_utxo = self._create_utxo(txid=tx.rehash(), vout=0, value=send_value, height=0)
return {"txid": new_utxo["txid"], "wtxid": tx.getwtxid(), "hex": tx_hex, "tx": tx, "new_utxo": new_utxo}
@@ -317,6 +338,17 @@ class MiniWallet:
self.scan_tx(from_node.decoderawtransaction(tx_hex))
return txid
+ def send_self_transfer_chain(self, *, from_node, chain_length, utxo_to_spend=None):
+ """Create and send a "chain" of chain_length transactions. The nth transaction in
+ the chain is a child of the n-1th transaction and parent of the n+1th transaction.
+
+ Returns the chaintip (nth) utxo
+ """
+ chaintip_utxo = utxo_to_spend or self.get_utxo()
+ for _ in range(chain_length):
+ chaintip_utxo = self.send_self_transfer(utxo_to_spend=chaintip_utxo, from_node=from_node)["new_utxo"]
+ return chaintip_utxo
+
def getnewdestination(address_type='bech32m'):
"""Generate a random destination of the specified type and return the
@@ -409,23 +441,3 @@ def create_raw_chain(node, first_coin, address, privkeys, chain_length=25):
chain_txns.append(tx)
return (chain_hex, chain_txns)
-
-def bulk_transaction(tx, node, target_weight, privkeys, prevtxs=None):
- """Pad a transaction with extra outputs until it reaches a target weight (or higher).
- returns CTransaction object
- """
- tx_heavy = deepcopy(tx)
- assert_greater_than_or_equal(target_weight, tx_heavy.get_weight())
- while tx_heavy.get_weight() < target_weight:
- random_spk = "6a4d0200" # OP_RETURN OP_PUSH2 512 bytes
- for _ in range(512*2):
- random_spk += choice("0123456789ABCDEF")
- tx_heavy.vout.append(CTxOut(0, bytes.fromhex(random_spk)))
- # Re-sign the transaction
- if privkeys:
- signed = node.signrawtransactionwithkey(tx_heavy.serialize().hex(), privkeys, prevtxs)
- return tx_from_hex(signed["hex"])
- # OP_TRUE
- tx_heavy.wit.vtxinwit = [CTxInWitness()]
- tx_heavy.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
- return tx_heavy
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index c5a69afa6e..2b365d8d10 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -156,6 +156,7 @@ BASE_SCRIPTS = [
'mempool_spend_coinbase.py',
'wallet_avoidreuse.py --legacy-wallet',
'wallet_avoidreuse.py --descriptors',
+ 'wallet_avoid_mixing_output_types.py --descriptors',
'mempool_reorg.py',
'mempool_persist.py',
'p2p_block_sync.py',
@@ -264,6 +265,8 @@ BASE_SCRIPTS = [
'wallet_implicitsegwit.py --legacy-wallet',
'rpc_named_arguments.py',
'feature_startupnotify.py',
+ 'wallet_simulaterawtx.py --legacy-wallet',
+ 'wallet_simulaterawtx.py --descriptors',
'wallet_listsinceblock.py --legacy-wallet',
'wallet_listsinceblock.py --descriptors',
'wallet_listdescriptors.py --descriptors',
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index f7c80f805c..5b836f693f 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -345,31 +345,19 @@ class AddressTypeTest(BitcoinTestFramework):
self.log.info("Nodes with addresstype=legacy never use a P2WPKH change output (unless changetype is set otherwise):")
self.test_change_output_type(0, [to_address_bech32_1], 'legacy')
- if self.options.descriptors:
- self.log.info("Nodes with addresstype=p2sh-segwit match the change output")
- self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
- self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
- self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
- self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
- else:
- self.log.info("Nodes with addresstype=p2sh-segwit match the change output")
- self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
- self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
- self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
- self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
+ self.log.info("Nodes with addresstype=p2sh-segwit match the change output")
+ self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
+ self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
+ self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
+ self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
self.log.info("Nodes with change_type=bech32 always use a P2WPKH change output:")
self.test_change_output_type(2, [to_address_bech32_1], 'bech32')
self.test_change_output_type(2, [to_address_p2sh], 'bech32')
- if self.options.descriptors:
- self.log.info("Nodes with addresstype=bech32 match the change output (unless changetype is set otherwise):")
- self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
- self.test_change_output_type(3, [to_address_p2sh], 'p2sh-segwit')
- else:
- self.log.info("Nodes with addresstype=bech32 match the change output (unless changetype is set otherwise):")
- self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
- self.test_change_output_type(3, [to_address_p2sh], 'p2sh-segwit')
+ self.log.info("Nodes with addresstype=bech32 match the change output (unless changetype is set otherwise):")
+ self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
+ self.test_change_output_type(3, [to_address_p2sh], 'p2sh-segwit')
self.log.info('getrawchangeaddress defaults to addresstype if -changetype is not set and argument is absent')
self.test_address(3, self.nodes[3].getrawchangeaddress(), multisig=False, typ='bech32')
diff --git a/test/functional/wallet_avoid_mixing_output_types.py b/test/functional/wallet_avoid_mixing_output_types.py
new file mode 100755
index 0000000000..46f41d9c22
--- /dev/null
+++ b/test/functional/wallet_avoid_mixing_output_types.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or https://www.opensource.org/licenses/mit-license.php.
+"""Test output type mixing during coin selection
+
+A wallet may have different types of UTXOs to choose from during coin selection,
+where output type is one of the following:
+ - BECH32M
+ - BECH32
+ - P2SH-SEGWIT
+ - LEGACY
+
+This test verifies that mixing different output types is avoided unless
+absolutely necessary. Both wallets start with zero funds. Alice mines
+enough blocks to have spendable coinbase outputs. Alice sends three
+random value payments which sum to 10BTC for each output type to Bob,
+for a total of 40BTC in Bob's wallet.
+
+Bob then sends random valued payments back to Alice, some of which need
+unconfirmed change, and we verify that none of these payments contain mixed
+inputs. Finally, Bob sends the remainder of his funds, which requires mixing.
+
+The payment values are random, but chosen such that they sum up to a specified
+total. This ensures we are not relying on specific values for the UTXOs,
+but still know when to expect mixing due to the wallet being close to empty.
+
+"""
+
+import random
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.blocktools import COINBASE_MATURITY
+
+ADDRESS_TYPES = [
+ "bech32m",
+ "bech32",
+ "p2sh-segwit",
+ "legacy",
+]
+
+
+def is_bech32_address(node, addr):
+ """Check if an address contains a bech32 output."""
+ addr_info = node.getaddressinfo(addr)
+ return addr_info['desc'].startswith('wpkh(')
+
+
+def is_bech32m_address(node, addr):
+ """Check if an address contains a bech32m output."""
+ addr_info = node.getaddressinfo(addr)
+ return addr_info['desc'].startswith('tr(')
+
+
+def is_p2sh_segwit_address(node, addr):
+ """Check if an address contains a P2SH-Segwit output.
+ Note: this function does not actually determine the type
+ of P2SH output, but is sufficient for this test in that
+ we are only generating P2SH-Segwit outputs.
+ """
+ addr_info = node.getaddressinfo(addr)
+ return addr_info['desc'].startswith('sh(wpkh(')
+
+
+def is_legacy_address(node, addr):
+ """Check if an address contains a legacy output."""
+ addr_info = node.getaddressinfo(addr)
+ return addr_info['desc'].startswith('pkh(')
+
+
+def is_same_type(node, tx):
+ """Check that all inputs are of the same OutputType"""
+ vins = node.getrawtransaction(tx, True)['vin']
+ inputs = []
+ for vin in vins:
+ prev_tx, n = vin['txid'], vin['vout']
+ inputs.append(
+ node.getrawtransaction(
+ prev_tx,
+ True,
+ )['vout'][n]['scriptPubKey']['address']
+ )
+ has_legacy = False
+ has_p2sh = False
+ has_bech32 = False
+ has_bech32m = False
+
+ for addr in inputs:
+ if is_legacy_address(node, addr):
+ has_legacy = True
+ if is_p2sh_segwit_address(node, addr):
+ has_p2sh = True
+ if is_bech32_address(node, addr):
+ has_bech32 = True
+ if is_bech32m_address(node, addr):
+ has_bech32m = True
+
+ return (sum([has_legacy, has_p2sh, has_bech32, has_bech32m]) == 1)
+
+
+def generate_payment_values(n, m):
+ """Return a randomly chosen list of n positive integers summing to m.
+ Each such list is equally likely to occur."""
+
+ dividers = sorted(random.sample(range(1, m), n - 1))
+ return [a - b for a, b in zip(dividers + [m], [0] + dividers)]
+
+
+class AddressInputTypeGrouping(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 2
+ self.extra_args = [
+ [
+ "-addresstype=bech32",
+ "-whitelist=noban@127.0.0.1",
+ "-txindex",
+ ],
+ [
+ "-addresstype=p2sh-segwit",
+ "-whitelist=noban@127.0.0.1",
+ "-txindex",
+ ],
+ ]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def make_payment(self, A, B, v, addr_type):
+ fee_rate = random.randint(1, 20)
+ self.log.debug(f"Making payment of {v} BTC at fee_rate {fee_rate}")
+ tx = B.sendtoaddress(
+ address=A.getnewaddress(address_type=addr_type),
+ amount=v,
+ fee_rate=fee_rate,
+ )
+ return tx
+
+ def run_test(self):
+
+ # alias self.nodes[i] to A, B for readability
+ A, B = self.nodes[0], self.nodes[1]
+ self.generate(A, COINBASE_MATURITY + 5)
+
+ self.log.info("Creating mixed UTXOs in B's wallet")
+ for v in generate_payment_values(3, 10):
+ self.log.debug(f"Making payment of {v} BTC to legacy")
+ A.sendtoaddress(B.getnewaddress(address_type="legacy"), v)
+
+ for v in generate_payment_values(3, 10):
+ self.log.debug(f"Making payment of {v} BTC to p2sh")
+ A.sendtoaddress(B.getnewaddress(address_type="p2sh-segwit"), v)
+
+ for v in generate_payment_values(3, 10):
+ self.log.debug(f"Making payment of {v} BTC to bech32")
+ A.sendtoaddress(B.getnewaddress(address_type="bech32"), v)
+
+ for v in generate_payment_values(3, 10):
+ self.log.debug(f"Making payment of {v} BTC to bech32m")
+ A.sendtoaddress(B.getnewaddress(address_type="bech32m"), v)
+
+ self.generate(A, 1)
+
+ self.log.info("Sending payments from B to A")
+ for v in generate_payment_values(5, 9):
+ tx = self.make_payment(
+ A, B, v, random.choice(ADDRESS_TYPES)
+ )
+ self.generate(A, 1)
+ assert is_same_type(B, tx)
+
+ tx = self.make_payment(A, B, 30.99, random.choice(ADDRESS_TYPES))
+ assert not is_same_type(B, tx)
+
+
+if __name__ == '__main__':
+ AddressInputTypeGrouping().main()
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index f75877f256..7c16b6328d 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -25,7 +25,7 @@ class ListTransactionsTest(BitcoinTestFramework):
self.num_nodes = 3
# This test isn't testing txn relay/timing, so set whitelist on the
# peers for instant txn relay. This speeds up the test run time 2-3x.
- self.extra_args = [["-whitelist=noban@127.0.0.1"]] * self.num_nodes
+ self.extra_args = [["-whitelist=noban@127.0.0.1", "-walletrbf=0"]] * self.num_nodes
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
@@ -146,7 +146,7 @@ class ListTransactionsTest(BitcoinTestFramework):
# Create tx2 using createrawtransaction
inputs = [{"txid": utxo_to_use["txid"], "vout": utxo_to_use["vout"]}]
outputs = {self.nodes[0].getnewaddress(): 0.999}
- tx2 = self.nodes[1].createrawtransaction(inputs, outputs)
+ tx2 = self.nodes[1].createrawtransaction(inputs=inputs, outputs=outputs, replaceable=False)
tx2_signed = self.nodes[1].signrawtransactionwithwallet(tx2)["hex"]
txid_2 = self.nodes[1].sendrawtransaction(tx2_signed)
@@ -178,7 +178,7 @@ class ListTransactionsTest(BitcoinTestFramework):
utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_3)
inputs = [{"txid": txid_3, "vout": utxo_to_use["vout"]}]
outputs = {self.nodes[0].getnewaddress(): 0.997}
- tx4 = self.nodes[1].createrawtransaction(inputs, outputs)
+ tx4 = self.nodes[1].createrawtransaction(inputs=inputs, outputs=outputs, replaceable=False)
tx4_signed = self.nodes[1].signrawtransactionwithwallet(tx4)["hex"]
txid_4 = self.nodes[1].sendrawtransaction(tx4_signed)
diff --git a/test/functional/wallet_simulaterawtx.py b/test/functional/wallet_simulaterawtx.py
new file mode 100755
index 0000000000..a408b99515
--- /dev/null
+++ b/test/functional/wallet_simulaterawtx.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test simulaterawtransaction.
+"""
+
+from decimal import Decimal
+from test_framework.blocktools import COINBASE_MATURITY
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_approx,
+ assert_equal,
+ assert_raises_rpc_error,
+)
+
+class SimulateTxTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def setup_network(self, split=False):
+ self.setup_nodes()
+
+ def run_test(self):
+ node = self.nodes[0]
+
+ self.generate(node, 1, sync_fun=self.no_op) # Leave IBD
+
+ node.createwallet(wallet_name='w0')
+ node.createwallet(wallet_name='w1')
+ node.createwallet(wallet_name='w2', disable_private_keys=True)
+ w0 = node.get_wallet_rpc('w0')
+ w1 = node.get_wallet_rpc('w1')
+ w2 = node.get_wallet_rpc('w2')
+
+ self.generatetoaddress(node, COINBASE_MATURITY + 1, w0.getnewaddress())
+ assert_equal(w0.getbalance(), 50.0)
+ assert_equal(w1.getbalance(), 0.0)
+
+ address1 = w1.getnewaddress()
+ address2 = w1.getnewaddress()
+
+ # Add address1 as watch-only to w2
+ w2.importpubkey(pubkey=w1.getaddressinfo(address1)["pubkey"])
+
+ tx1 = node.createrawtransaction([], [{address1: 5.0}])
+ tx2 = node.createrawtransaction([], [{address2: 10.0}])
+
+ # w0 should be unaffected, w2 should see +5 for tx1
+ assert_equal(w0.simulaterawtransaction([tx1])["balance_change"], 0.0)
+ assert_equal(w2.simulaterawtransaction([tx1])["balance_change"], 5.0)
+
+ # w1 should see +5 balance for tx1
+ assert_equal(w1.simulaterawtransaction([tx1])["balance_change"], 5.0)
+
+ # w0 should be unaffected, w2 should see +5 for both transactions
+ assert_equal(w0.simulaterawtransaction([tx1, tx2])["balance_change"], 0.0)
+ assert_equal(w2.simulaterawtransaction([tx1, tx2])["balance_change"], 5.0)
+
+ # w1 should see +15 balance for both transactions
+ assert_equal(w1.simulaterawtransaction([tx1, tx2])["balance_change"], 15.0)
+
+ # w0 funds transaction; it should now see a decrease in (tx fee and payment), and w1 should see the same as above
+ funding = w0.fundrawtransaction(tx1)
+ tx1 = funding["hex"]
+ tx1changepos = funding["changepos"]
+ bitcoin_fee = Decimal(funding["fee"])
+
+ # w0 sees fee + 5 btc decrease, w2 sees + 5 btc
+ assert_approx(w0.simulaterawtransaction([tx1])["balance_change"], -(Decimal("5") + bitcoin_fee))
+ assert_approx(w2.simulaterawtransaction([tx1])["balance_change"], Decimal("5"))
+
+ # w1 sees same as before
+ assert_equal(w1.simulaterawtransaction([tx1])["balance_change"], 5.0)
+
+ # same inputs (tx) more than once should error
+ assert_raises_rpc_error(-8, "Transaction(s) are spending the same output more than once", w0.simulaterawtransaction, [tx1,tx1])
+
+ tx1ob = node.decoderawtransaction(tx1)
+ tx1hex = tx1ob["txid"]
+ tx1vout = 1 - tx1changepos
+ # tx3 spends new w1 UTXO paying to w0
+ tx3 = node.createrawtransaction([{"txid": tx1hex, "vout": tx1vout}], {w0.getnewaddress(): 4.9999})
+ # tx4 spends new w1 UTXO paying to w1
+ tx4 = node.createrawtransaction([{"txid": tx1hex, "vout": tx1vout}], {w1.getnewaddress(): 4.9999})
+
+ # on their own, both should fail due to missing input(s)
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w0.simulaterawtransaction, [tx3])
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w1.simulaterawtransaction, [tx3])
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w0.simulaterawtransaction, [tx4])
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w1.simulaterawtransaction, [tx4])
+
+ # they should succeed when including tx1:
+ # wallet tx3 tx4
+ # w0 -5 - bitcoin_fee + 4.9999 -5 - bitcoin_fee
+ # w1 0 +4.9999
+ assert_approx(w0.simulaterawtransaction([tx1, tx3])["balance_change"], -Decimal("5") - bitcoin_fee + Decimal("4.9999"))
+ assert_approx(w1.simulaterawtransaction([tx1, tx3])["balance_change"], 0)
+ assert_approx(w0.simulaterawtransaction([tx1, tx4])["balance_change"], -Decimal("5") - bitcoin_fee)
+ assert_approx(w1.simulaterawtransaction([tx1, tx4])["balance_change"], Decimal("4.9999"))
+
+ # they should fail if attempting to include both tx3 and tx4
+ assert_raises_rpc_error(-8, "Transaction(s) are spending the same output more than once", w0.simulaterawtransaction, [tx1, tx3, tx4])
+ assert_raises_rpc_error(-8, "Transaction(s) are spending the same output more than once", w1.simulaterawtransaction, [tx1, tx3, tx4])
+
+ # send tx1 to avoid reusing same UTXO below
+ node.sendrawtransaction(w0.signrawtransactionwithwallet(tx1)["hex"])
+ self.generate(node, 1, sync_fun=self.no_op) # Confirm tx to trigger error below
+ self.sync_all()
+
+ # w0 funds transaction 2; it should now see a decrease in (tx fee and payment), and w1 should see the same as above
+ funding = w0.fundrawtransaction(tx2)
+ tx2 = funding["hex"]
+ bitcoin_fee2 = Decimal(funding["fee"])
+ assert_approx(w0.simulaterawtransaction([tx2])["balance_change"], -(Decimal("10") + bitcoin_fee2))
+ assert_approx(w1.simulaterawtransaction([tx2])["balance_change"], +(Decimal("10")))
+ assert_approx(w2.simulaterawtransaction([tx2])["balance_change"], 0)
+
+ # w0-w2 error due to tx1 already being mined
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w0.simulaterawtransaction, [tx1, tx2])
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w1.simulaterawtransaction, [tx1, tx2])
+ assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w2.simulaterawtransaction, [tx1, tx2])
+
+if __name__ == '__main__':
+ SimulateTxTest().main()
diff --git a/test/get_previous_releases.py b/test/get_previous_releases.py
index 7b7cfbfef5..c983dce619 100755
--- a/test/get_previous_releases.py
+++ b/test/get_previous_releases.py
@@ -20,66 +20,66 @@ import sys
import hashlib
SHA256_SUMS = {
- "0e2819135366f150d9906e294b61dff58fd1996ebd26c2f8e979d6c0b7a79580": "bitcoin-0.14.3-aarch64-linux-gnu.tar.gz",
- "d86fc90824a85c38b25c8488115178d5785dbc975f5ff674f9f5716bc8ad6e65": "bitcoin-0.14.3-arm-linux-gnueabihf.tar.gz",
- "1b0a7408c050e3d09a8be8e21e183ef7ee570385dc41216698cc3ab392a484e7": "bitcoin-0.14.3-osx64.tar.gz",
- "706e0472dbc933ed2757650d54cbcd780fd3829ebf8f609b32780c7eedebdbc9": "bitcoin-0.14.3-x86_64-linux-gnu.tar.gz",
+ "0e2819135366f150d9906e294b61dff58fd1996ebd26c2f8e979d6c0b7a79580": {"tag": "v0.14.3", "tarball": "bitcoin-0.14.3-aarch64-linux-gnu.tar.gz"},
+ "d86fc90824a85c38b25c8488115178d5785dbc975f5ff674f9f5716bc8ad6e65": {"tag": "v0.14.3", "tarball": "bitcoin-0.14.3-arm-linux-gnueabihf.tar.gz"},
+ "1b0a7408c050e3d09a8be8e21e183ef7ee570385dc41216698cc3ab392a484e7": {"tag": "v0.14.3", "tarball": "bitcoin-0.14.3-osx64.tar.gz"},
+ "706e0472dbc933ed2757650d54cbcd780fd3829ebf8f609b32780c7eedebdbc9": {"tag": "v0.14.3", "tarball": "bitcoin-0.14.3-x86_64-linux-gnu.tar.gz"},
#
- "d40f18b4e43c6e6370ef7db9131f584fbb137276ec2e3dba67a4b267f81cb644": "bitcoin-0.15.2-aarch64-linux-gnu.tar.gz",
- "54fb877a148a6ad189a1e1ab1ff8b11181e58ff2aaf430da55b3fd46ae549a6b": "bitcoin-0.15.2-arm-linux-gnueabihf.tar.gz",
- "87e9340ff3d382d543b2b69112376077f0c8b4f7450d372e83b68f5a1e22b2df": "bitcoin-0.15.2-osx64.tar.gz",
- "566be44190fd76daa01f13d428939dadfb8e3daacefc8fa17f433cad28f73bd5": "bitcoin-0.15.2-x86_64-linux-gnu.tar.gz",
+ "d40f18b4e43c6e6370ef7db9131f584fbb137276ec2e3dba67a4b267f81cb644": {"tag": "v0.15.2", "tarball": "bitcoin-0.15.2-aarch64-linux-gnu.tar.gz"},
+ "54fb877a148a6ad189a1e1ab1ff8b11181e58ff2aaf430da55b3fd46ae549a6b": {"tag": "v0.15.2", "tarball": "bitcoin-0.15.2-arm-linux-gnueabihf.tar.gz"},
+ "87e9340ff3d382d543b2b69112376077f0c8b4f7450d372e83b68f5a1e22b2df": {"tag": "v0.15.2", "tarball": "bitcoin-0.15.2-osx64.tar.gz"},
+ "566be44190fd76daa01f13d428939dadfb8e3daacefc8fa17f433cad28f73bd5": {"tag": "v0.15.2", "tarball": "bitcoin-0.15.2-x86_64-linux-gnu.tar.gz"},
#
- "0768c6c15caffbaca6524824c9563b42c24f70633c681c2744649158aa3fd484": "bitcoin-0.16.3-aarch64-linux-gnu.tar.gz",
- "fb2818069854a6ad20ea03b28b55dbd35d8b1f7d453e90b83eace5d0098a2a87": "bitcoin-0.16.3-arm-linux-gnueabihf.tar.gz",
- "78c3bff3b619a19aed575961ea43cc9e142959218835cf51aede7f0b764fc25d": "bitcoin-0.16.3-osx64.tar.gz",
- "5d422a9d544742bc0df12427383f9c2517433ce7b58cf672b9a9b17c2ef51e4f": "bitcoin-0.16.3-x86_64-linux-gnu.tar.gz",
+ "0768c6c15caffbaca6524824c9563b42c24f70633c681c2744649158aa3fd484": {"tag": "v0.16.3", "tarball": "bitcoin-0.16.3-aarch64-linux-gnu.tar.gz"},
+ "fb2818069854a6ad20ea03b28b55dbd35d8b1f7d453e90b83eace5d0098a2a87": {"tag": "v0.16.3", "tarball": "bitcoin-0.16.3-arm-linux-gnueabihf.tar.gz"},
+ "78c3bff3b619a19aed575961ea43cc9e142959218835cf51aede7f0b764fc25d": {"tag": "v0.16.3", "tarball": "bitcoin-0.16.3-osx64.tar.gz"},
+ "5d422a9d544742bc0df12427383f9c2517433ce7b58cf672b9a9b17c2ef51e4f": {"tag": "v0.16.3", "tarball": "bitcoin-0.16.3-x86_64-linux-gnu.tar.gz"},
#
- "5a6b35d1a348a402f2d2d6ab5aed653a1a1f13bc63aaaf51605e3501b0733b7a": "bitcoin-0.17.2-aarch64-linux-gnu.tar.gz",
- "d1913a5d19c8e8da4a67d1bd5205d03c8614dfd2e02bba2fe3087476643a729e": "bitcoin-0.17.2-arm-linux-gnueabihf.tar.gz",
- "a783ba20706dbfd5b47fbedf42165fce70fbbc7d78003305d964f6b3da14887f": "bitcoin-0.17.2-osx64.tar.gz",
- "943f9362b9f11130177839116f48f809d83478b4c28591d486ee9a7e35179da6": "bitcoin-0.17.2-x86_64-linux-gnu.tar.gz",
+ "5a6b35d1a348a402f2d2d6ab5aed653a1a1f13bc63aaaf51605e3501b0733b7a": {"tag": "v0.17.2", "tarball": "bitcoin-0.17.2-aarch64-linux-gnu.tar.gz"},
+ "d1913a5d19c8e8da4a67d1bd5205d03c8614dfd2e02bba2fe3087476643a729e": {"tag": "v0.17.2", "tarball": "bitcoin-0.17.2-arm-linux-gnueabihf.tar.gz"},
+ "a783ba20706dbfd5b47fbedf42165fce70fbbc7d78003305d964f6b3da14887f": {"tag": "v0.17.2", "tarball": "bitcoin-0.17.2-osx64.tar.gz"},
+ "943f9362b9f11130177839116f48f809d83478b4c28591d486ee9a7e35179da6": {"tag": "v0.17.2", "tarball": "bitcoin-0.17.2-x86_64-linux-gnu.tar.gz"},
#
- "88f343af72803b851c7da13874cc5525026b0b55e63e1b5e1298390c4688adc6": "bitcoin-0.18.1-aarch64-linux-gnu.tar.gz",
- "cc7d483e4b20c5dabd4dcaf304965214cf4934bcc029ca99cbc9af00d3771a1f": "bitcoin-0.18.1-arm-linux-gnueabihf.tar.gz",
- "b7bbcee7a7540f711b171d6981f939ca8482005fde22689bc016596d80548bb1": "bitcoin-0.18.1-osx64.tar.gz",
- "425ee5ec631ae8da71ebc1c3f5c0269c627cf459379b9b030f047107a28e3ef8": "bitcoin-0.18.1-riscv64-linux-gnu.tar.gz",
- "600d1db5e751fa85903e935a01a74f5cc57e1e7473c15fd3e17ed21e202cfe5a": "bitcoin-0.18.1-x86_64-linux-gnu.tar.gz",
+ "88f343af72803b851c7da13874cc5525026b0b55e63e1b5e1298390c4688adc6": {"tag": "v0.18.1", "tarball": "bitcoin-0.18.1-aarch64-linux-gnu.tar.gz"},
+ "cc7d483e4b20c5dabd4dcaf304965214cf4934bcc029ca99cbc9af00d3771a1f": {"tag": "v0.18.1", "tarball": "bitcoin-0.18.1-arm-linux-gnueabihf.tar.gz"},
+ "b7bbcee7a7540f711b171d6981f939ca8482005fde22689bc016596d80548bb1": {"tag": "v0.18.1", "tarball": "bitcoin-0.18.1-osx64.tar.gz"},
+ "425ee5ec631ae8da71ebc1c3f5c0269c627cf459379b9b030f047107a28e3ef8": {"tag": "v0.18.1", "tarball": "bitcoin-0.18.1-riscv64-linux-gnu.tar.gz"},
+ "600d1db5e751fa85903e935a01a74f5cc57e1e7473c15fd3e17ed21e202cfe5a": {"tag": "v0.18.1", "tarball": "bitcoin-0.18.1-x86_64-linux-gnu.tar.gz"},
#
- "3a80431717842672df682bdb619e66523b59541483297772a7969413be3502ff": "bitcoin-0.19.1-aarch64-linux-gnu.tar.gz",
- "657f28213823d240dd3324d14829702f9ad6f0710f8bdd1c379cb3c447197f48": "bitcoin-0.19.1-arm-linux-gnueabihf.tar.gz",
- "1ae1b87de26487075cd2fd22e0d4ead87d969bd55c44f2f1d873ecdc6147ebb3": "bitcoin-0.19.1-osx64.tar.gz",
- "aa7a9563b48aa79252c8e7b6a41c07a5441bd9f14c5e4562cc72720ea6cb0ee5": "bitcoin-0.19.1-riscv64-linux-gnu.tar.gz",
- "5fcac9416e486d4960e1a946145566350ca670f9aaba99de6542080851122e4c": "bitcoin-0.19.1-x86_64-linux-gnu.tar.gz",
+ "3a80431717842672df682bdb619e66523b59541483297772a7969413be3502ff": {"tag": "v0.19.1", "tarball": "bitcoin-0.19.1-aarch64-linux-gnu.tar.gz"},
+ "657f28213823d240dd3324d14829702f9ad6f0710f8bdd1c379cb3c447197f48": {"tag": "v0.19.1", "tarball": "bitcoin-0.19.1-arm-linux-gnueabihf.tar.gz"},
+ "1ae1b87de26487075cd2fd22e0d4ead87d969bd55c44f2f1d873ecdc6147ebb3": {"tag": "v0.19.1", "tarball": "bitcoin-0.19.1-osx64.tar.gz"},
+ "aa7a9563b48aa79252c8e7b6a41c07a5441bd9f14c5e4562cc72720ea6cb0ee5": {"tag": "v0.19.1", "tarball": "bitcoin-0.19.1-riscv64-linux-gnu.tar.gz"},
+ "5fcac9416e486d4960e1a946145566350ca670f9aaba99de6542080851122e4c": {"tag": "v0.19.1", "tarball": "bitcoin-0.19.1-x86_64-linux-gnu.tar.gz"},
#
- "60c93e3462c303eb080be7cf623f1a7684b37fd47a018ad3848bc23e13c84e1c": "bitcoin-0.20.1-aarch64-linux-gnu.tar.gz",
- "55b577e0fb306fb429d4be6c9316607753e8543e5946b542d75d876a2f08654c": "bitcoin-0.20.1-arm-linux-gnueabihf.tar.gz",
- "b9024dde373ea7dad707363e07ec7e265383204127539ae0c234bff3a61da0d1": "bitcoin-0.20.1-osx64.tar.gz",
- "fa71cb52ee5e0459cbf5248cdec72df27995840c796f58b304607a1ed4c165af": "bitcoin-0.20.1-riscv64-linux-gnu.tar.gz",
- "376194f06596ecfa40331167c39bc70c355f960280bd2a645fdbf18f66527397": "bitcoin-0.20.1-x86_64-linux-gnu.tar.gz",
+ "60c93e3462c303eb080be7cf623f1a7684b37fd47a018ad3848bc23e13c84e1c": {"tag": "v0.20.1", "tarball": "bitcoin-0.20.1-aarch64-linux-gnu.tar.gz"},
+ "55b577e0fb306fb429d4be6c9316607753e8543e5946b542d75d876a2f08654c": {"tag": "v0.20.1", "tarball": "bitcoin-0.20.1-arm-linux-gnueabihf.tar.gz"},
+ "b9024dde373ea7dad707363e07ec7e265383204127539ae0c234bff3a61da0d1": {"tag": "v0.20.1", "tarball": "bitcoin-0.20.1-osx64.tar.gz"},
+ "fa71cb52ee5e0459cbf5248cdec72df27995840c796f58b304607a1ed4c165af": {"tag": "v0.20.1", "tarball": "bitcoin-0.20.1-riscv64-linux-gnu.tar.gz"},
+ "376194f06596ecfa40331167c39bc70c355f960280bd2a645fdbf18f66527397": {"tag": "v0.20.1", "tarball": "bitcoin-0.20.1-x86_64-linux-gnu.tar.gz"},
- "43416854330914992bbba2d0e9adf2a6fff4130be9af8ae2ef1186e743d9a3fe": "bitcoin-0.21.0-aarch64-linux-gnu.tar.gz",
- "f028af308eda45a3c4c90f9332f96b075bf21e3495c945ebce48597151808176": "bitcoin-0.21.0-arm-linux-gnueabihf.tar.gz",
- "695fb624fa6423f5da4f443b60763dd1d77488bfe5ef63760904a7b54e91298d": "bitcoin-0.21.0-osx64.tar.gz",
- "f8b2adfeae021a672effbc7bd40d5c48d6b94e53b2dd660f787340bf1a52e4e9": "bitcoin-0.21.0-riscv64-linux-gnu.tar.gz",
- "da7766775e3f9c98d7a9145429f2be8297c2672fe5b118fd3dc2411fb48e0032": "bitcoin-0.21.0-x86_64-linux-gnu.tar.gz",
+ "43416854330914992bbba2d0e9adf2a6fff4130be9af8ae2ef1186e743d9a3fe": {"tag": "v0.21.0", "tarball": "bitcoin-0.21.0-aarch64-linux-gnu.tar.gz"},
+ "f028af308eda45a3c4c90f9332f96b075bf21e3495c945ebce48597151808176": {"tag": "v0.21.0", "tarball": "bitcoin-0.21.0-arm-linux-gnueabihf.tar.gz"},
+ "695fb624fa6423f5da4f443b60763dd1d77488bfe5ef63760904a7b54e91298d": {"tag": "v0.21.0", "tarball": "bitcoin-0.21.0-osx64.tar.gz"},
+ "f8b2adfeae021a672effbc7bd40d5c48d6b94e53b2dd660f787340bf1a52e4e9": {"tag": "v0.21.0", "tarball": "bitcoin-0.21.0-riscv64-linux-gnu.tar.gz"},
+ "da7766775e3f9c98d7a9145429f2be8297c2672fe5b118fd3dc2411fb48e0032": {"tag": "v0.21.0", "tarball": "bitcoin-0.21.0-x86_64-linux-gnu.tar.gz"},
- "ac718fed08570a81b3587587872ad85a25173afa5f9fbbd0c03ba4d1714cfa3e": "bitcoin-22.0-aarch64-linux-gnu.tar.gz",
- "b8713c6c5f03f5258b54e9f436e2ed6d85449aa24c2c9972f91963d413e86311": "bitcoin-22.0-arm-linux-gnueabihf.tar.gz",
- "2744d199c3343b2d94faffdfb2c94d75a630ba27301a70e47b0ad30a7e0155e9": "bitcoin-22.0-osx64.tar.gz",
- "2cca5f99007d060aca9d8c7cbd035dfe2f040dd8200b210ce32cdf858479f70d": "bitcoin-22.0-powerpc64-linux-gnu.tar.gz",
- "91b1e012975c5a363b5b5fcc81b5b7495e86ff703ec8262d4b9afcfec633c30d": "bitcoin-22.0-powerpc64le-linux-gnu.tar.gz",
- "9cc3a62c469fe57e11485fdd32c916f10ce7a2899299855a2e479256ff49ff3c": "bitcoin-22.0-riscv64-linux-gnu.tar.gz",
- "59ebd25dd82a51638b7a6bb914586201e67db67b919b2a1ff08925a7936d1b16": "bitcoin-22.0-x86_64-linux-gnu.tar.gz",
+ "ac718fed08570a81b3587587872ad85a25173afa5f9fbbd0c03ba4d1714cfa3e": {"tag": "v22.0", "tarball": "bitcoin-22.0-aarch64-linux-gnu.tar.gz"},
+ "b8713c6c5f03f5258b54e9f436e2ed6d85449aa24c2c9972f91963d413e86311": {"tag": "v22.0", "tarball": "bitcoin-22.0-arm-linux-gnueabihf.tar.gz"},
+ "2744d199c3343b2d94faffdfb2c94d75a630ba27301a70e47b0ad30a7e0155e9": {"tag": "v22.0", "tarball": "bitcoin-22.0-osx64.tar.gz"},
+ "2cca5f99007d060aca9d8c7cbd035dfe2f040dd8200b210ce32cdf858479f70d": {"tag": "v22.0", "tarball": "bitcoin-22.0-powerpc64-linux-gnu.tar.gz"},
+ "91b1e012975c5a363b5b5fcc81b5b7495e86ff703ec8262d4b9afcfec633c30d": {"tag": "v22.0", "tarball": "bitcoin-22.0-powerpc64le-linux-gnu.tar.gz"},
+ "9cc3a62c469fe57e11485fdd32c916f10ce7a2899299855a2e479256ff49ff3c": {"tag": "v22.0", "tarball": "bitcoin-22.0-riscv64-linux-gnu.tar.gz"},
+ "59ebd25dd82a51638b7a6bb914586201e67db67b919b2a1ff08925a7936d1b16": {"tag": "v22.0", "tarball": "bitcoin-22.0-x86_64-linux-gnu.tar.gz"},
- "06f4c78271a77752ba5990d60d81b1751507f77efda1e5981b4e92fd4d9969fb": "bitcoin-23.0-aarch64-linux-gnu.tar.gz",
- "952c574366aff76f6d6ad1c9ee45a361d64fa04155e973e926dfe7e26f9703a3": "bitcoin-23.0-arm-linux-gnueabihf.tar.gz",
- "7c8bc63731aa872b7b334a8a7d96e33536ad77d49029bad179b09dca32cd77ac": "bitcoin-23.0-arm64-apple-darwin.tar.gz",
- "2caa5898399e415f61d9af80a366a3008e5856efa15aaff74b88acf429674c99": "bitcoin-23.0-powerpc64-linux-gnu.tar.gz",
- "217dd0469d0f4962d22818c368358575f6a0abcba8804807bb75325eb2f28b19": "bitcoin-23.0-powerpc64le-linux-gnu.tar.gz",
- "078f96b1e92895009c798ab827fb3fde5f6719eee886bd0c0e93acab18ea4865": "bitcoin-23.0-riscv64-linux-gnu.tar.gz",
- "c816780583009a9dad426dc0c183c89be9da98906e1e2c7ebae91041c1aaaaf3": "bitcoin-23.0-x86_64-apple-darwin.tar.gz",
- "2cca490c1f2842884a3c5b0606f179f9f937177da4eadd628e3f7fd7e25d26d0": "bitcoin-23.0-x86_64-linux-gnu.tar.gz",
+ "06f4c78271a77752ba5990d60d81b1751507f77efda1e5981b4e92fd4d9969fb": {"tag": "v23.0", "tarball": "bitcoin-23.0-aarch64-linux-gnu.tar.gz"},
+ "952c574366aff76f6d6ad1c9ee45a361d64fa04155e973e926dfe7e26f9703a3": {"tag": "v23.0", "tarball": "bitcoin-23.0-arm-linux-gnueabihf.tar.gz"},
+ "7c8bc63731aa872b7b334a8a7d96e33536ad77d49029bad179b09dca32cd77ac": {"tag": "v23.0", "tarball": "bitcoin-23.0-arm64-apple-darwin.tar.gz"},
+ "2caa5898399e415f61d9af80a366a3008e5856efa15aaff74b88acf429674c99": {"tag": "v23.0", "tarball": "bitcoin-23.0-powerpc64-linux-gnu.tar.gz"},
+ "217dd0469d0f4962d22818c368358575f6a0abcba8804807bb75325eb2f28b19": {"tag": "v23.0", "tarball": "bitcoin-23.0-powerpc64le-linux-gnu.tar.gz"},
+ "078f96b1e92895009c798ab827fb3fde5f6719eee886bd0c0e93acab18ea4865": {"tag": "v23.0", "tarball": "bitcoin-23.0-riscv64-linux-gnu.tar.gz"},
+ "c816780583009a9dad426dc0c183c89be9da98906e1e2c7ebae91041c1aaaaf3": {"tag": "v23.0", "tarball": "bitcoin-23.0-x86_64-apple-darwin.tar.gz"},
+ "2cca490c1f2842884a3c5b0606f179f9f937177da4eadd628e3f7fd7e25d26d0": {"tag": "v23.0", "tarball": "bitcoin-23.0-x86_64-linux-gnu.tar.gz"},
}
@@ -135,7 +135,7 @@ def download_binary(tag, args) -> int:
hasher.update(afile.read())
tarballHash = hasher.hexdigest()
- if tarballHash not in SHA256_SUMS or SHA256_SUMS[tarballHash] != tarball:
+ if tarballHash not in SHA256_SUMS or SHA256_SUMS[tarballHash]['tarball'] != tarball:
if tarball in SHA256_SUMS.values():
print("Checksum did not match")
return 1
@@ -260,7 +260,12 @@ if __name__ == '__main__':
help='download release binary.')
parser.add_argument('-t', '--target-dir', action='store',
help='target directory.', default='releases')
- parser.add_argument('tags', nargs='+',
- help="release tags. e.g.: v0.18.1 v0.20.0rc2")
+ parser.add_argument('tags', nargs='*', default=set(
+ [v['tag'] for v in SHA256_SUMS.values()]
+ ),
+ help='release tags. e.g.: v0.18.1 v0.20.0rc2 '
+ '(if not specified, the full list needed for'
+ 'backwards compatibility tests will be used)'
+ )
args = parser.parse_args()
sys.exit(main(args))