zcashd/qa/rpc-tests/spentindex.py

186 lines
7.2 KiB
Python
Executable File

#!/usr/bin/env python3
# Copyright (c) 2019 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
#
# Test spentindex generation and fetching for insightexplorer
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import (
assert_equal,
initialize_chain_clean,
start_nodes,
stop_nodes,
connect_nodes,
wait_bitcoinds,
fail,
)
from test_framework.mininode import COIN
class SpentIndexTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 3)
def setup_network(self):
# -insightexplorer causes spentindex to be enabled (fSpentIndex = true)
self.nodes = start_nodes(
3, self.options.tmpdir,
[['-debug', '-txindex', '-experimentalfeatures', '-insightexplorer']]*3)
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[0], 2)
self.is_network_split = False
self.sync_all()
def run_test(self):
self.nodes[0].generate(105)
self.sync_all()
chain_height = self.nodes[1].getblockcount()
assert_equal(chain_height, 105)
# Test getrawtransaction changes and the getspentinfo RPC
# send coinbase to address addr1
addr1 = self.nodes[1].getnewaddress()
txid1 = self.nodes[0].sendtoaddress(addr1, 2)
self.sync_all()
block_hash1 = self.nodes[0].generate(1)
self.sync_all()
# send from addr1 to addr2
# (the only utxo on node 1 is from address addr1)
addr2 = self.nodes[2].getnewaddress()
txid2 = self.nodes[1].sendtoaddress(addr2, 1)
self.sync_all()
# addr1 to addr2 transaction is not confirmed, so it has no height
tx2 = self.nodes[2].getrawtransaction(txid2, 1)
assert('height' not in tx2)
# confirm addr1 to addr2 transaction
block_hash2 = self.nodes[0].generate(1)
self.sync_all()
# Restart all nodes to ensure index files are saved to disk and recovered
stop_nodes(self.nodes)
wait_bitcoinds()
self.setup_network()
# Check new fields added to getrawtransaction
tx1 = self.nodes[2].getrawtransaction(txid1, 1)
assert_equal(tx1['vin'][0]['value'], 10) # coinbase
assert_equal(tx1['vin'][0]['valueSat'], 10*COIN)
# we want the non-change (payment) output
vout = list(filter(lambda o: o['value'] == 2, tx1['vout']))
n = vout[0]['n']
assert_equal(vout[0]['spentTxId'], txid2)
assert_equal(vout[0]['spentIndex'], 0)
assert_equal(vout[0]['spentHeight'], 107)
assert_equal(tx1['height'], 106)
tx2 = self.nodes[2].getrawtransaction(txid2, 1)
assert_equal(tx2['vin'][0]['address'], addr1)
assert_equal(tx2['vin'][0]['value'], 2)
assert_equal(tx2['vin'][0]['valueSat'], 2*COIN)
# since this transaction's outputs haven't yet been
# spent, these fields should not be present
assert('spentTxId' not in tx2['vout'][0])
assert('spentIndex' not in tx2['vout'][0])
assert('spentHeight' not in tx2['vout'][0])
assert_equal(tx2['height'], 107)
# Given a transaction output, getspentinfo() returns a reference
# to the (later, confirmed) transaction that spent that output,
# that is, the transaction that used this output as an input.
spentinfo = self.nodes[2].getspentinfo({'txid': txid1, 'index': n})
assert_equal(spentinfo['height'], 107)
assert_equal(spentinfo['index'], 0)
assert_equal(spentinfo['txid'], txid2)
# specifying an output that hasn't been spent should fail
try:
self.nodes[1].getspentinfo({'txid': txid2, 'index': 0})
fail('getspentinfo should have thrown an exception')
except JSONRPCException as e:
assert_equal(e.error['message'], "Unable to get spent info")
block_hash_next = self.nodes[0].generate(1)
self.sync_all()
# Test the getblockdeltas RPC
blockdeltas = self.nodes[2].getblockdeltas(block_hash1[0])
assert_equal(blockdeltas['confirmations'], 3)
assert_equal(blockdeltas['height'], 106)
assert_equal(blockdeltas['version'], 4)
assert_equal(blockdeltas['hash'], block_hash1[0])
assert_equal(blockdeltas['nextblockhash'], block_hash2[0])
deltas = blockdeltas['deltas']
# block contains two transactions, coinbase, and earlier coinbase to addr1
assert_equal(len(deltas), 2)
coinbase_tx = deltas[0]
assert_equal(coinbase_tx['index'], 0)
assert_equal(len(coinbase_tx['inputs']), 0)
assert_equal(len(coinbase_tx['outputs']), 2)
assert_equal(coinbase_tx['outputs'][0]['index'], 0)
assert_equal(coinbase_tx['outputs'][1]['index'], 1)
assert_equal(coinbase_tx['outputs'][1]['satoshis'], 2.5*COIN)
to_a_tx = deltas[1]
assert_equal(to_a_tx['index'], 1)
assert_equal(to_a_tx['txid'], txid1)
assert_equal(len(to_a_tx['inputs']), 1)
assert_equal(to_a_tx['inputs'][0]['index'], 0)
assert_equal(to_a_tx['inputs'][0]['prevout'], 0)
assert_equal(to_a_tx['inputs'][0]['satoshis'], -10*COIN)
assert_equal(len(to_a_tx['outputs']), 2)
# find the nonchange output, which is the payment to addr1
out = list(filter(lambda o: o['satoshis'] == 2*COIN, to_a_tx['outputs']))
assert_equal(len(out), 1)
assert_equal(out[0]['address'], addr1)
blockdeltas = self.nodes[2].getblockdeltas(block_hash2[0])
assert_equal(blockdeltas['confirmations'], 2)
assert_equal(blockdeltas['height'], 107)
assert_equal(blockdeltas['version'], 4)
assert_equal(blockdeltas['hash'], block_hash2[0])
assert_equal(blockdeltas['previousblockhash'], block_hash1[0])
assert_equal(blockdeltas['nextblockhash'], block_hash_next[0])
deltas = blockdeltas['deltas']
assert_equal(len(deltas), 2)
coinbase_tx = deltas[0]
assert_equal(coinbase_tx['index'], 0)
assert_equal(len(coinbase_tx['inputs']), 0)
assert_equal(len(coinbase_tx['outputs']), 2)
assert_equal(coinbase_tx['outputs'][0]['index'], 0)
assert_equal(coinbase_tx['outputs'][1]['index'], 1)
assert_equal(coinbase_tx['outputs'][1]['satoshis'], 2.5*COIN)
to_b_tx = deltas[1]
assert_equal(to_b_tx['index'], 1)
assert_equal(to_b_tx['txid'], txid2)
assert_equal(len(to_b_tx['inputs']), 1)
assert_equal(to_b_tx['inputs'][0]['index'], 0)
assert_equal(to_b_tx['inputs'][0]['prevtxid'], txid1)
assert_equal(to_b_tx['inputs'][0]['satoshis'], -2*COIN)
assert_equal(len(to_b_tx['outputs']), 2)
# find the nonchange output, which is the payment to addr2
out = list(filter(lambda o: o['satoshis'] == 1*COIN, to_b_tx['outputs']))
assert_equal(len(out), 1)
assert_equal(out[0]['address'], addr2)
if __name__ == '__main__':
SpentIndexTest().main()