test: Add tests for block_info in gettxoutsetinfo

This additional data will automatically be returned if the coinstats index is used.
pull/19521/head
Fabian Jahr 4 years ago
parent 2501576ecc
commit e0938c2909
No known key found for this signature in database
GPG Key ID: F13D1E9D890798CD

@ -9,6 +9,25 @@ between a node running the coinstatsindex and a node without
the index.
"""
from decimal import Decimal
from test_framework.blocktools import (
create_block,
create_coinbase,
)
from test_framework.messages import (
COIN,
COutPoint,
CTransaction,
CTxIn,
CTxOut,
ToHex,
)
from test_framework.script import (
CScript,
OP_FALSE,
OP_RETURN,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@ -32,6 +51,13 @@ class CoinStatsIndexTest(BitcoinTestFramework):
def run_test(self):
self._test_coin_stats_index()
def block_sanity_check(self, block_info):
block_subsidy = 50
assert_equal(
block_info['prevout_spent'] + block_subsidy,
block_info['new_outputs_ex_coinbase'] + block_info['coinbase'] + block_info['unspendable']
)
def _test_coin_stats_index(self):
node = self.nodes[0]
index_node = self.nodes[1]
@ -85,5 +111,118 @@ class CoinStatsIndexTest(BitcoinTestFramework):
# It does not work without coinstatsindex
assert_raises_rpc_error(-8, "Querying specific block heights requires coinstatsindex", node.gettxoutsetinfo, hash_option, 102)
self.log.info("Test gettxoutsetinfo() with index and verbose flag")
for hash_option in index_hash_options:
# Genesis block is unspendable
res4 = index_node.gettxoutsetinfo(hash_option, 0)
assert_equal(res4['total_unspendable_amount'], 50)
assert_equal(res4['block_info'], {
'unspendable': 50,
'prevout_spent': 0,
'new_outputs_ex_coinbase': 0,
'coinbase': 0,
'unspendables': {
'genesis_block': 50,
'bip30': 0,
'scripts': 0,
'unclaimed_rewards': 0
}
})
self.block_sanity_check(res4['block_info'])
# Test an older block height that included a normal tx
res5 = index_node.gettxoutsetinfo(hash_option, 102)
assert_equal(res5['total_unspendable_amount'], 50)
assert_equal(res5['block_info'], {
'unspendable': 0,
'prevout_spent': 50,
'new_outputs_ex_coinbase': Decimal('49.99995560'),
'coinbase': Decimal('50.00004440'),
'unspendables': {
'genesis_block': 0,
'bip30': 0,
'scripts': 0,
'unclaimed_rewards': 0
}
})
self.block_sanity_check(res5['block_info'])
# Generate and send a normal tx with two outputs
tx1_inputs = []
tx1_outputs = {self.nodes[0].getnewaddress(): 21, self.nodes[0].getnewaddress(): 42}
raw_tx1 = self.nodes[0].createrawtransaction(tx1_inputs, tx1_outputs)
funded_tx1 = self.nodes[0].fundrawtransaction(raw_tx1)
signed_tx1 = self.nodes[0].signrawtransactionwithwallet(funded_tx1['hex'])
tx1_txid = self.nodes[0].sendrawtransaction(signed_tx1['hex'])
# Find the right position of the 21 BTC output
tx1_final = self.nodes[0].gettransaction(tx1_txid)
for output in tx1_final['details']:
if output['amount'] == Decimal('21.00000000') and output['category'] == 'receive':
n = output['vout']
# Generate and send another tx with an OP_RETURN output (which is unspendable)
tx2 = CTransaction()
tx2.vin.append(CTxIn(COutPoint(int(tx1_txid, 16), n), b''))
tx2.vout.append(CTxOut(int(20.99 * COIN), CScript([OP_RETURN] + [OP_FALSE]*30)))
tx2_hex = self.nodes[0].signrawtransactionwithwallet(ToHex(tx2))['hex']
self.nodes[0].sendrawtransaction(tx2_hex)
# Include both txs in a block
self.nodes[0].generate(1)
self.sync_all()
self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set", index_node.gettxoutsetinfo, 'muhash'))
for hash_option in index_hash_options:
# Check all amounts were registered correctly
res6 = index_node.gettxoutsetinfo(hash_option, 108)
assert_equal(res6['total_unspendable_amount'], Decimal('70.98999999'))
assert_equal(res6['block_info'], {
'unspendable': Decimal('20.98999999'),
'prevout_spent': 111,
'new_outputs_ex_coinbase': Decimal('89.99993620'),
'coinbase': Decimal('50.01006381'),
'unspendables': {
'genesis_block': 0,
'bip30': 0,
'scripts': Decimal('20.98999999'),
'unclaimed_rewards': 0
}
})
self.block_sanity_check(res6['block_info'])
# Create a coinbase that does not claim full subsidy and also
# has two outputs
cb = create_coinbase(109, nValue=35)
cb.vout.append(CTxOut(5 * COIN, CScript([OP_FALSE])))
cb.rehash()
# Generate a block that includes previous coinbase
tip = self.nodes[0].getbestblockhash()
block_time = self.nodes[0].getblock(tip)['time'] + 1
block = create_block(int(tip, 16), cb, block_time)
block.solve()
self.nodes[0].submitblock(ToHex(block))
self.sync_all()
self.wait_until(lambda: not try_rpc(-32603, "Unable to read UTXO set", index_node.gettxoutsetinfo, 'muhash'))
for hash_option in index_hash_options:
res7 = index_node.gettxoutsetinfo(hash_option, 109)
assert_equal(res7['total_unspendable_amount'], Decimal('80.98999999'))
assert_equal(res7['block_info'], {
'unspendable': 10,
'prevout_spent': 0,
'new_outputs_ex_coinbase': 0,
'coinbase': 40,
'unspendables': {
'genesis_block': 0,
'bip30': 0,
'scripts': 0,
'unclaimed_rewards': 10
}
})
self.block_sanity_check(res7['block_info'])
if __name__ == '__main__':
CoinStatsIndexTest().main()

@ -115,7 +115,7 @@ def script_BIP34_coinbase_height(height):
return CScript([CScriptNum(height)])
def create_coinbase(height, pubkey=None, extra_output_script=None, fees=0):
def create_coinbase(height, pubkey=None, extra_output_script=None, fees=0, nValue=50):
"""Create a coinbase transaction.
If pubkey is passed in, the coinbase output will be a P2PK output;
@ -126,10 +126,11 @@ def create_coinbase(height, pubkey=None, extra_output_script=None, fees=0):
coinbase = CTransaction()
coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), 0xffffffff))
coinbaseoutput = CTxOut()
coinbaseoutput.nValue = 50 * COIN
halvings = int(height / 150) # regtest
coinbaseoutput.nValue >>= halvings
coinbaseoutput.nValue += fees
coinbaseoutput.nValue = nValue * COIN
if nValue == 50:
halvings = int(height / 150) # regtest
coinbaseoutput.nValue >>= halvings
coinbaseoutput.nValue += fees
if pubkey is not None:
coinbaseoutput.scriptPubKey = CScript([pubkey, OP_CHECKSIG])
else:

Loading…
Cancel
Save