Changeset View
Changeset View
Standalone View
Standalone View
test/functional/feature_coinstatsindex.py
Show All 24 Lines | def set_test_params(self): | ||||
self.num_nodes = 2 | self.num_nodes = 2 | ||||
self.supports_cli = False | self.supports_cli = False | ||||
self.extra_args = [ | self.extra_args = [ | ||||
[ | [ | ||||
"-automaticunparking=1", | "-automaticunparking=1", | ||||
], | ], | ||||
[ | [ | ||||
"-coinstatsindex", | "-coinstatsindex", | ||||
] | ], | ||||
] | ] | ||||
def run_test(self): | def run_test(self): | ||||
self.wallet = MiniWallet(self.nodes[0]) | self.wallet = MiniWallet(self.nodes[0]) | ||||
self._test_coin_stats_index() | self._test_coin_stats_index() | ||||
self._test_use_index_option() | self._test_use_index_option() | ||||
self._test_reorg_index() | self._test_reorg_index() | ||||
self._test_index_rejects_hash_serialized() | self._test_index_rejects_hash_serialized() | ||||
def block_sanity_check(self, block_info): | def block_sanity_check(self, block_info): | ||||
block_subsidy = 50_000_000 | block_subsidy = 50_000_000 | ||||
assert_equal( | assert_equal( | ||||
block_info['prevout_spent'] + block_subsidy, | block_info["prevout_spent"] + block_subsidy, | ||||
block_info['new_outputs_ex_coinbase'] + block_info['coinbase'] | block_info["new_outputs_ex_coinbase"] | ||||
+ block_info['unspendable'] | + block_info["coinbase"] | ||||
+ block_info["unspendable"], | |||||
) | ) | ||||
def _test_coin_stats_index(self): | def _test_coin_stats_index(self): | ||||
node = self.nodes[0] | node = self.nodes[0] | ||||
index_node = self.nodes[1] | index_node = self.nodes[1] | ||||
# Both none and muhash options allow the usage of the index | # Both none and muhash options allow the usage of the index | ||||
index_hash_options = ['none', 'muhash'] | index_hash_options = ["none", "muhash"] | ||||
# Generate a normal transaction and mine it | # Generate a normal transaction and mine it | ||||
self.generate(self.wallet, 101) | self.generate(self.wallet, 101) | ||||
self.wallet.send_self_transfer(from_node=node) | self.wallet.send_self_transfer(from_node=node) | ||||
self.generate(node, 1) | self.generate(node, 1) | ||||
self.log.info( | self.log.info( | ||||
"Test that gettxoutsetinfo() output is consistent with or without coinstatsindex option") | "Test that gettxoutsetinfo() output is consistent with or without" | ||||
self.wait_until(lambda: not try_rpc(-32603, | " coinstatsindex option" | ||||
"Unable to read UTXO set", node.gettxoutsetinfo)) | ) | ||||
res0 = node.gettxoutsetinfo('none') | self.wait_until( | ||||
lambda: not try_rpc(-32603, "Unable to read UTXO set", node.gettxoutsetinfo) | |||||
) | |||||
res0 = node.gettxoutsetinfo("none") | |||||
# The fields 'disk_size' and 'transactions' do not exist on the index | # The fields 'disk_size' and 'transactions' do not exist on the index | ||||
del res0['disk_size'], res0['transactions'] | del res0["disk_size"], res0["transactions"] | ||||
self.wait_until(lambda: not try_rpc(-32603, | self.wait_until( | ||||
"Unable to read UTXO set", | lambda: not try_rpc( | ||||
index_node.gettxoutsetinfo, | -32603, "Unable to read UTXO set", index_node.gettxoutsetinfo, "muhash" | ||||
'muhash')) | ) | ||||
) | |||||
for hash_option in index_hash_options: | for hash_option in index_hash_options: | ||||
res1 = index_node.gettxoutsetinfo(hash_option) | res1 = index_node.gettxoutsetinfo(hash_option) | ||||
# The fields 'block_info' and 'total_unspendable_amount' only exist | # The fields 'block_info' and 'total_unspendable_amount' only exist | ||||
# on the index | # on the index | ||||
del res1['block_info'], res1['total_unspendable_amount'] | del res1["block_info"], res1["total_unspendable_amount"] | ||||
res1.pop('muhash', None) | res1.pop("muhash", None) | ||||
# Everything left should be the same | # Everything left should be the same | ||||
assert_equal(res1, res0) | assert_equal(res1, res0) | ||||
self.log.info( | self.log.info( | ||||
"Test that gettxoutsetinfo() can get fetch data on specific " | "Test that gettxoutsetinfo() can get fetch data on specific " | ||||
"heights with index") | "heights with index" | ||||
) | |||||
# Generate a new tip | # Generate a new tip | ||||
self.generate(node, 5) | self.generate(node, 5) | ||||
self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set", | self.wait_until( | ||||
index_node.gettxoutsetinfo, | lambda: not try_rpc( | ||||
'muhash')) | -32603, "Unable to read UTXO set", index_node.gettxoutsetinfo, "muhash" | ||||
) | |||||
) | |||||
for hash_option in index_hash_options: | for hash_option in index_hash_options: | ||||
# Fetch old stats by height | # Fetch old stats by height | ||||
res2 = index_node.gettxoutsetinfo(hash_option, 102) | res2 = index_node.gettxoutsetinfo(hash_option, 102) | ||||
del res2['block_info'], res2['total_unspendable_amount'] | del res2["block_info"], res2["total_unspendable_amount"] | ||||
res2.pop('muhash', None) | res2.pop("muhash", None) | ||||
assert_equal(res0, res2) | assert_equal(res0, res2) | ||||
# Fetch old stats by hash | # Fetch old stats by hash | ||||
res3 = index_node.gettxoutsetinfo(hash_option, res0['bestblock']) | res3 = index_node.gettxoutsetinfo(hash_option, res0["bestblock"]) | ||||
del res3['block_info'], res3['total_unspendable_amount'] | del res3["block_info"], res3["total_unspendable_amount"] | ||||
res3.pop('muhash', None) | res3.pop("muhash", None) | ||||
assert_equal(res0, res3) | assert_equal(res0, res3) | ||||
# It does not work without coinstatsindex | # It does not work without coinstatsindex | ||||
assert_raises_rpc_error( | assert_raises_rpc_error( | ||||
-8, "Querying specific block heights requires coinstatsindex", | -8, | ||||
node.gettxoutsetinfo, hash_option, 102) | "Querying specific block heights requires coinstatsindex", | ||||
node.gettxoutsetinfo, | |||||
hash_option, | |||||
102, | |||||
) | |||||
self.log.info("Test gettxoutsetinfo() with index and verbose flag") | self.log.info("Test gettxoutsetinfo() with index and verbose flag") | ||||
for hash_option in index_hash_options: | for hash_option in index_hash_options: | ||||
# Genesis block is unspendable | # Genesis block is unspendable | ||||
res4 = index_node.gettxoutsetinfo(hash_option, 0) | res4 = index_node.gettxoutsetinfo(hash_option, 0) | ||||
assert_equal(res4['total_unspendable_amount'], 50_000_000) | assert_equal(res4["total_unspendable_amount"], 50_000_000) | ||||
assert_equal(res4['block_info'], { | assert_equal( | ||||
'unspendable': 50_000_000, | res4["block_info"], | ||||
'prevout_spent': 0, | { | ||||
'new_outputs_ex_coinbase': 0, | "unspendable": 50_000_000, | ||||
'coinbase': 0, | "prevout_spent": 0, | ||||
'unspendables': { | "new_outputs_ex_coinbase": 0, | ||||
'genesis_block': 50_000_000, | "coinbase": 0, | ||||
'bip30': 0, | "unspendables": { | ||||
'scripts': 0, | "genesis_block": 50_000_000, | ||||
'unclaimed_rewards': 0 | "bip30": 0, | ||||
} | "scripts": 0, | ||||
}) | "unclaimed_rewards": 0, | ||||
self.block_sanity_check(res4['block_info']) | }, | ||||
}, | |||||
) | |||||
self.block_sanity_check(res4["block_info"]) | |||||
# Test an older block height that included a normal tx | # Test an older block height that included a normal tx | ||||
res5 = index_node.gettxoutsetinfo(hash_option, 102) | res5 = index_node.gettxoutsetinfo(hash_option, 102) | ||||
assert_equal(res5['total_unspendable_amount'], 50_000_000) | assert_equal(res5["total_unspendable_amount"], 50_000_000) | ||||
assert_equal(res5['block_info'], { | assert_equal( | ||||
'unspendable': 0, | res5["block_info"], | ||||
'prevout_spent': 50_000_000, | { | ||||
'new_outputs_ex_coinbase': Decimal('49999700.00'), | "unspendable": 0, | ||||
'coinbase': Decimal('50000300.00'), | "prevout_spent": 50_000_000, | ||||
'unspendables': { | "new_outputs_ex_coinbase": Decimal("49999700.00"), | ||||
'genesis_block': 0, | "coinbase": Decimal("50000300.00"), | ||||
'bip30': 0, | "unspendables": { | ||||
'scripts': 0, | "genesis_block": 0, | ||||
'unclaimed_rewards': 0, | "bip30": 0, | ||||
} | "scripts": 0, | ||||
}) | "unclaimed_rewards": 0, | ||||
self.block_sanity_check(res5['block_info']) | }, | ||||
}, | |||||
) | |||||
self.block_sanity_check(res5["block_info"]) | |||||
# Generate and send a normal tx with two outputs | # Generate and send a normal tx with two outputs | ||||
tx1_txid, tx1_vout = self.wallet.send_to( | tx1_txid, tx1_vout = self.wallet.send_to( | ||||
from_node=node, | from_node=node, | ||||
scriptPubKey=self.wallet.get_scriptPubKey(), | scriptPubKey=self.wallet.get_scriptPubKey(), | ||||
amount=21_000_000 * XEC, | amount=21_000_000 * XEC, | ||||
) | ) | ||||
# Find the right position of the 21 MegXEC output | # Find the right position of the 21 MegXEC output | ||||
tx1_out_21 = self.wallet.get_utxo(txid=tx1_txid, vout=tx1_vout) | tx1_out_21 = self.wallet.get_utxo(txid=tx1_txid, vout=tx1_vout) | ||||
# Generate and send another tx with an OP_RETURN output (which is | # Generate and send another tx with an OP_RETURN output (which is | ||||
# unspendable) | # unspendable) | ||||
tx2 = self.wallet.create_self_transfer( | tx2 = self.wallet.create_self_transfer( | ||||
from_node=self.nodes[0], utxo_to_spend=tx1_out_21)['tx'] | from_node=self.nodes[0], utxo_to_spend=tx1_out_21 | ||||
tx2.vout = [CTxOut(int(20_990_000 * XEC), | )["tx"] | ||||
CScript([OP_RETURN] + [OP_FALSE] * 50))] | tx2.vout = [ | ||||
CTxOut(int(20_990_000 * XEC), CScript([OP_RETURN] + [OP_FALSE] * 50)) | |||||
] | |||||
tx2_hex = tx2.serialize().hex() | tx2_hex = tx2.serialize().hex() | ||||
self.nodes[0].sendrawtransaction(tx2_hex) | self.nodes[0].sendrawtransaction(tx2_hex) | ||||
# Include both txs in a block | # Include both txs in a block | ||||
self.generate(self.nodes[0], 1) | self.generate(self.nodes[0], 1) | ||||
self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set", | self.wait_until( | ||||
index_node.gettxoutsetinfo, 'muhash')) | lambda: not try_rpc( | ||||
-32603, "Unable to read UTXO set", index_node.gettxoutsetinfo, "muhash" | |||||
) | |||||
) | |||||
for hash_option in index_hash_options: | for hash_option in index_hash_options: | ||||
# Check all amounts were registered correctly | # Check all amounts were registered correctly | ||||
res6 = index_node.gettxoutsetinfo(hash_option, 108) | res6 = index_node.gettxoutsetinfo(hash_option, 108) | ||||
assert_equal(res6["total_unspendable_amount"], Decimal("70990000.00")) | |||||
assert_equal( | assert_equal( | ||||
res6['total_unspendable_amount'], | res6["block_info"], | ||||
Decimal('70990000.00')) | { | ||||
assert_equal(res6['block_info'], { | "unspendable": Decimal("20990000.00"), | ||||
'unspendable': Decimal('20990000.00'), | "prevout_spent": 71_000_000, | ||||
'prevout_spent': 71_000_000, | "new_outputs_ex_coinbase": Decimal("49999990.00"), | ||||
'new_outputs_ex_coinbase': Decimal('49999990.00'), | "coinbase": Decimal("50010010.00"), | ||||
'coinbase': Decimal('50010010.00'), | "unspendables": { | ||||
'unspendables': { | "genesis_block": 0, | ||||
'genesis_block': 0, | "bip30": 0, | ||||
'bip30': 0, | "scripts": Decimal("20990000.00"), | ||||
'scripts': Decimal('20990000.00'), | "unclaimed_rewards": 0, | ||||
'unclaimed_rewards': 0, | }, | ||||
} | }, | ||||
}) | ) | ||||
self.block_sanity_check(res6['block_info']) | self.block_sanity_check(res6["block_info"]) | ||||
# Create a coinbase that does not claim full subsidy and also | # Create a coinbase that does not claim full subsidy and also | ||||
# has two outputs | # has two outputs | ||||
cb = create_coinbase(109, nValue=35_000_000) | cb = create_coinbase(109, nValue=35_000_000) | ||||
cb.vout.append(CTxOut(5_000_000 * XEC, CScript([OP_FALSE]))) | cb.vout.append(CTxOut(5_000_000 * XEC, CScript([OP_FALSE]))) | ||||
cb.rehash() | cb.rehash() | ||||
# Generate a block that includes previous coinbase | # Generate a block that includes previous coinbase | ||||
tip = self.nodes[0].getbestblockhash() | tip = self.nodes[0].getbestblockhash() | ||||
block_time = self.nodes[0].getblock(tip)['time'] + 1 | block_time = self.nodes[0].getblock(tip)["time"] + 1 | ||||
block = create_block(int(tip, 16), cb, block_time) | block = create_block(int(tip, 16), cb, block_time) | ||||
block.solve() | block.solve() | ||||
self.nodes[0].submitblock(ToHex(block)) | self.nodes[0].submitblock(ToHex(block)) | ||||
self.sync_all() | self.sync_all() | ||||
self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set", | self.wait_until( | ||||
index_node.gettxoutsetinfo, 'muhash')) | lambda: not try_rpc( | ||||
-32603, "Unable to read UTXO set", index_node.gettxoutsetinfo, "muhash" | |||||
) | |||||
) | |||||
for hash_option in index_hash_options: | for hash_option in index_hash_options: | ||||
res7 = index_node.gettxoutsetinfo(hash_option, 109) | res7 = index_node.gettxoutsetinfo(hash_option, 109) | ||||
assert_equal(res7["total_unspendable_amount"], Decimal("80990000.00")) | |||||
assert_equal( | assert_equal( | ||||
res7['total_unspendable_amount'], | res7["block_info"], | ||||
Decimal('80990000.00')) | { | ||||
assert_equal(res7['block_info'], { | "unspendable": 10_000_000, | ||||
'unspendable': 10_000_000, | "prevout_spent": 0, | ||||
'prevout_spent': 0, | "new_outputs_ex_coinbase": 0, | ||||
'new_outputs_ex_coinbase': 0, | "coinbase": 40_000_000, | ||||
'coinbase': 40_000_000, | "unspendables": { | ||||
'unspendables': { | "genesis_block": 0, | ||||
'genesis_block': 0, | "bip30": 0, | ||||
'bip30': 0, | "scripts": 0, | ||||
'scripts': 0, | "unclaimed_rewards": 10_000_000, | ||||
'unclaimed_rewards': 10_000_000 | }, | ||||
} | }, | ||||
}) | ) | ||||
self.block_sanity_check(res7['block_info']) | self.block_sanity_check(res7["block_info"]) | ||||
self.log.info("Test that the index is robust across restarts") | self.log.info("Test that the index is robust across restarts") | ||||
res8 = index_node.gettxoutsetinfo('muhash') | res8 = index_node.gettxoutsetinfo("muhash") | ||||
self.restart_node(1, extra_args=self.extra_args[1]) | self.restart_node(1, extra_args=self.extra_args[1]) | ||||
res9 = index_node.gettxoutsetinfo('muhash') | res9 = index_node.gettxoutsetinfo("muhash") | ||||
assert_equal(res8, res9) | assert_equal(res8, res9) | ||||
self.generate(index_node, 1, sync_fun=self.no_op) | self.generate(index_node, 1, sync_fun=self.no_op) | ||||
self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set", | self.wait_until( | ||||
index_node.gettxoutsetinfo, 'muhash')) | lambda: not try_rpc( | ||||
res10 = index_node.gettxoutsetinfo('muhash') | -32603, "Unable to read UTXO set", index_node.gettxoutsetinfo, "muhash" | ||||
assert res8['txouts'] < res10['txouts'] | ) | ||||
) | |||||
res10 = index_node.gettxoutsetinfo("muhash") | |||||
assert res8["txouts"] < res10["txouts"] | |||||
def _test_use_index_option(self): | def _test_use_index_option(self): | ||||
self.log.info("Test use_index option for nodes running the index") | self.log.info("Test use_index option for nodes running the index") | ||||
self.connect_nodes(0, 1) | self.connect_nodes(0, 1) | ||||
self.nodes[0].waitforblockheight(110) | self.nodes[0].waitforblockheight(110) | ||||
res = self.nodes[0].gettxoutsetinfo('muhash') | res = self.nodes[0].gettxoutsetinfo("muhash") | ||||
option_res = self.nodes[1].gettxoutsetinfo( | option_res = self.nodes[1].gettxoutsetinfo( | ||||
hash_type='muhash', hash_or_height=None, use_index=False) | hash_type="muhash", hash_or_height=None, use_index=False | ||||
del res['disk_size'], option_res['disk_size'] | ) | ||||
del res["disk_size"], option_res["disk_size"] | |||||
assert_equal(res, option_res) | assert_equal(res, option_res) | ||||
def _test_reorg_index(self): | def _test_reorg_index(self): | ||||
self.log.info("Test that index can handle reorgs") | self.log.info("Test that index can handle reorgs") | ||||
# Generate two block, let the index catch up, then invalidate the | # Generate two block, let the index catch up, then invalidate the | ||||
# blocks | # blocks | ||||
index_node = self.nodes[1] | index_node = self.nodes[1] | ||||
reorg_blocks = self.generatetoaddress( | reorg_blocks = self.generatetoaddress(index_node, 2, getnewdestination()[2]) | ||||
index_node, 2, getnewdestination()[2]) | |||||
reorg_block = reorg_blocks[1] | reorg_block = reorg_blocks[1] | ||||
self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set", | self.wait_until( | ||||
index_node.gettxoutsetinfo, 'muhash')) | lambda: not try_rpc( | ||||
res_invalid = index_node.gettxoutsetinfo('muhash') | -32603, "Unable to read UTXO set", index_node.gettxoutsetinfo, "muhash" | ||||
) | |||||
) | |||||
res_invalid = index_node.gettxoutsetinfo("muhash") | |||||
index_node.invalidateblock(reorg_blocks[0]) | index_node.invalidateblock(reorg_blocks[0]) | ||||
assert_equal(index_node.gettxoutsetinfo('muhash')['height'], 110) | assert_equal(index_node.gettxoutsetinfo("muhash")["height"], 110) | ||||
# Add two new blocks | # Add two new blocks | ||||
block = self.generate(index_node, 2, sync_fun=self.no_op)[1] | block = self.generate(index_node, 2, sync_fun=self.no_op)[1] | ||||
self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set", | self.wait_until( | ||||
index_node.gettxoutsetinfo, 'muhash')) | lambda: not try_rpc( | ||||
-32603, "Unable to read UTXO set", index_node.gettxoutsetinfo, "muhash" | |||||
) | |||||
) | |||||
res = index_node.gettxoutsetinfo( | res = index_node.gettxoutsetinfo( | ||||
hash_type='muhash', hash_or_height=None, use_index=False) | hash_type="muhash", hash_or_height=None, use_index=False | ||||
) | |||||
# Test that the result of the reorged block is not returned for its old | # Test that the result of the reorged block is not returned for its old | ||||
# block height | # block height | ||||
res2 = index_node.gettxoutsetinfo( | res2 = index_node.gettxoutsetinfo(hash_type="muhash", hash_or_height=112) | ||||
hash_type='muhash', hash_or_height=112) | |||||
assert_equal(res["bestblock"], block) | assert_equal(res["bestblock"], block) | ||||
assert_equal(res["muhash"], res2["muhash"]) | assert_equal(res["muhash"], res2["muhash"]) | ||||
assert res["muhash"] != res_invalid["muhash"] | assert res["muhash"] != res_invalid["muhash"] | ||||
# Test that requesting reorged out block by hash is still returning | # Test that requesting reorged out block by hash is still returning | ||||
# correct results | # correct results | ||||
res_invalid2 = index_node.gettxoutsetinfo( | res_invalid2 = index_node.gettxoutsetinfo( | ||||
hash_type='muhash', hash_or_height=reorg_block) | hash_type="muhash", hash_or_height=reorg_block | ||||
) | |||||
assert_equal(res_invalid2["muhash"], res_invalid["muhash"]) | assert_equal(res_invalid2["muhash"], res_invalid["muhash"]) | ||||
assert res["muhash"] != res_invalid2["muhash"] | assert res["muhash"] != res_invalid2["muhash"] | ||||
# Add another block, so we don't depend on reconsiderblock remembering | # Add another block, so we don't depend on reconsiderblock remembering | ||||
# which blocks were touched by invalidateblock | # which blocks were touched by invalidateblock | ||||
self.generate(index_node, 1) | self.generate(index_node, 1) | ||||
# Ensure that removing and re-adding blocks yields consistent results | # Ensure that removing and re-adding blocks yields consistent results | ||||
block = index_node.getblockhash(99) | block = index_node.getblockhash(99) | ||||
index_node.invalidateblock(block) | index_node.invalidateblock(block) | ||||
self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set", | self.wait_until( | ||||
index_node.gettxoutsetinfo, 'muhash')) | lambda: not try_rpc( | ||||
-32603, "Unable to read UTXO set", index_node.gettxoutsetinfo, "muhash" | |||||
) | |||||
) | |||||
index_node.reconsiderblock(block) | index_node.reconsiderblock(block) | ||||
self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set", | self.wait_until( | ||||
index_node.gettxoutsetinfo, 'muhash')) | lambda: not try_rpc( | ||||
res3 = index_node.gettxoutsetinfo( | -32603, "Unable to read UTXO set", index_node.gettxoutsetinfo, "muhash" | ||||
hash_type='muhash', hash_or_height=112) | ) | ||||
) | |||||
res3 = index_node.gettxoutsetinfo(hash_type="muhash", hash_or_height=112) | |||||
assert_equal(res2, res3) | assert_equal(res2, res3) | ||||
self.log.info( | self.log.info("Test that a node aware of stale blocks syncs them as well") | ||||
"Test that a node aware of stale blocks syncs them as well") | |||||
node = self.nodes[0] | node = self.nodes[0] | ||||
# Ensure the node is aware of a stale block prior to restart | # Ensure the node is aware of a stale block prior to restart | ||||
node.getblock(reorg_block) | node.getblock(reorg_block) | ||||
self.restart_node(0, ["-coinstatsindex"]) | self.restart_node(0, ["-coinstatsindex"]) | ||||
self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set", | self.wait_until( | ||||
node.gettxoutsetinfo, 'muhash')) | lambda: not try_rpc( | ||||
assert_raises_rpc_error(-32603, "Unable to read UTXO set", | -32603, "Unable to read UTXO set", node.gettxoutsetinfo, "muhash" | ||||
node.gettxoutsetinfo, 'muhash', reorg_block) | ) | ||||
) | |||||
assert_raises_rpc_error( | |||||
-32603, | |||||
"Unable to read UTXO set", | |||||
node.gettxoutsetinfo, | |||||
"muhash", | |||||
reorg_block, | |||||
) | |||||
def _test_index_rejects_hash_serialized(self): | def _test_index_rejects_hash_serialized(self): | ||||
self.log.info( | self.log.info( | ||||
"Test that the rpc raises if the legacy hash is passed with the index") | "Test that the rpc raises if the legacy hash is passed with the index" | ||||
) | |||||
msg = "hash_serialized hash type cannot be queried for a specific block" | msg = "hash_serialized hash type cannot be queried for a specific block" | ||||
assert_raises_rpc_error(-8, msg, | assert_raises_rpc_error( | ||||
-8, | |||||
msg, | |||||
self.nodes[1].gettxoutsetinfo, | self.nodes[1].gettxoutsetinfo, | ||||
hash_type='hash_serialized', hash_or_height=111) | hash_type="hash_serialized", | ||||
hash_or_height=111, | |||||
) | |||||
for use_index in {True, False, None}: | for use_index in {True, False, None}: | ||||
assert_raises_rpc_error(-8, msg, | assert_raises_rpc_error( | ||||
-8, | |||||
msg, | |||||
self.nodes[1].gettxoutsetinfo, | self.nodes[1].gettxoutsetinfo, | ||||
hash_type='hash_serialized', | hash_type="hash_serialized", | ||||
hash_or_height=111, use_index=use_index) | hash_or_height=111, | ||||
use_index=use_index, | |||||
) | |||||
if __name__ == '__main__': | if __name__ == "__main__": | ||||
CoinStatsIndexTest().main() | CoinStatsIndexTest().main() |