#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Copyright (c) 2016-2020 The Hush developers # Distributed under the GPLv3 software license, see the accompanying # file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html # Base class for RPC testing # Add python-bitcoinrpc to module search path: import os import sys import shutil import tempfile import traceback from authproxy import JSONRPCException from util import assert_equal, check_json_precision, \ initialize_chain, initialize_chain_clean, \ start_nodes, connect_nodes_bi, stop_nodes, \ sync_blocks, sync_mempools, wait_bitcoinds class BitcoinTestFramework(object): # These may be over-ridden by subclasses: def run_test(self): for node in self.nodes: assert_equal(node.getblockcount(), 200) assert_equal(node.getbalance(), 25*10) def add_options(self, parser): pass def setup_chain(self): print("Initializing test directory "+self.options.tmpdir) initialize_chain(self.options.tmpdir) def setup_nodes(self): return start_nodes(4, self.options.tmpdir) def setup_network(self, split = False): self.nodes = self.setup_nodes() # Connect the nodes as a "chain". This allows us # to split the network between nodes 1 and 2 to get # two halves that can work on competing chains. # If we joined network halves, connect the nodes from the joint # on outward. This ensures that chains are properly reorganised. if not split: connect_nodes_bi(self.nodes, 1, 2) sync_blocks(self.nodes[1:3]) sync_mempools(self.nodes[1:3]) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 2, 3) self.is_network_split = split self.sync_all() def split_network(self): """ Split the network of four nodes into nodes 0/1 and 2/3. """ assert not self.is_network_split stop_nodes(self.nodes) wait_bitcoinds() self.setup_network(True) def sync_all(self): if self.is_network_split: sync_blocks(self.nodes[:2]) sync_blocks(self.nodes[2:]) sync_mempools(self.nodes[:2]) sync_mempools(self.nodes[2:]) else: sync_blocks(self.nodes) sync_mempools(self.nodes) def join_network(self): """ Join the (previously split) network halves together. """ assert self.is_network_split stop_nodes(self.nodes) wait_bitcoinds() self.setup_network(False) def main(self): import optparse parser = optparse.OptionParser(usage="%prog [options]") parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true", help="Leave komodods and test.* datadir on exit or error") parser.add_option("--noshutdown", dest="noshutdown", default=False, action="store_true", help="Don't stop komodods after the test execution") parser.add_option("--srcdir", dest="srcdir", default="../../src", help="Source directory containing komodod/komodo-cli (default: %default)") parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"), help="Root directory for datadirs") parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true", help="Print out all RPC calls as they are made") self.add_options(parser) (self.options, self.args) = parser.parse_args() if self.options.trace_rpc: import logging logging.basicConfig(level=logging.DEBUG) os.environ['PATH'] = self.options.srcdir+":"+os.environ['PATH'] check_json_precision() success = False try: if not os.path.isdir(self.options.tmpdir): os.makedirs(self.options.tmpdir) self.setup_chain() self.setup_network() self.run_test() success = True except JSONRPCException as e: print("JSONRPC error: "+e.error['message']) traceback.print_tb(sys.exc_info()[2]) except AssertionError as e: print("Assertion failed: "+e.message) traceback.print_tb(sys.exc_info()[2]) except Exception as e: print("Unexpected exception caught during testing: "+str(e)) traceback.print_tb(sys.exc_info()[2]) if not self.options.noshutdown: print("Stopping nodes") stop_nodes(self.nodes) wait_bitcoinds() else: print("Note: komodods were not stopped and may still be running") if not self.options.nocleanup and not self.options.noshutdown: print("Cleaning up") shutil.rmtree(self.options.tmpdir) if success: print("Tests successful") sys.exit(0) else: print("Failed") sys.exit(1) # Test framework for doing p2p comparison testing, which sets up some komodod # binaries: # 1 binary: test binary # 2 binaries: 1 test binary, 1 ref binary # n>2 binaries: 1 test binary, n-1 ref binaries class ComparisonTestFramework(BitcoinTestFramework): # Can override the num_nodes variable to indicate how many nodes to run. def __init__(self): self.num_nodes = 2 def add_options(self, parser): parser.add_option("--testbinary", dest="testbinary", default=os.getenv("BITCOIND", "komodod"), help="bitcoind binary to test") parser.add_option("--refbinary", dest="refbinary", default=os.getenv("BITCOIND", "komodod"), help="bitcoind binary to use for reference nodes (if any)") def setup_chain(self): print "Initializing test directory "+self.options.tmpdir initialize_chain_clean(self.options.tmpdir, self.num_nodes) def setup_network(self): self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes, binary=[self.options.testbinary] + [self.options.refbinary]*(self.num_nodes-1)) class HushTestFramework(BitcoinTestFramework): def __init__(self): self.num_nodes = 2 def setup_chain(self): print("Initializing Hush regtest directory "+self.options.tmpdir) initialize_chain_clean(self.options.tmpdir, self.num_nodes) def setup_network(self, split = False): print("Setting up Hush regtest network...") self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D" self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf" self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9" self.addr1 = "RXEXoa1nRmKhMbuZovpcYwQMsicwzccZBp" self.pubkey1 = "024026d4ad4ecfc1f705a9b42ca64af6d2ad947509c085534a30b8861d756c6ff0" self.privkey1 = "UtdydP56pGTFmawHzHr1wDrc4oUwCNW1ttX8Pc3KrvH3MA8P49Wi" self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[ # always give -ac_name as first extra_arg and port as third '-ac_name=REGTEST', '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', '-port=64367', '-rpcport=64368', '-regtest', '-addressindex=1', '-spentindex=1', '-ac_supply=5555555', '-ac_reward=10000000000000', '-pubkey=' + self.pubkey, '-ac_cc=2', '-whitelist=127.0.0.1', '-debug', '--daemon', '-rpcuser=rt', '-rpcpassword=rt' ], ['-ac_name=REGTEST', '-conf='+self.options.tmpdir+'/node1/REGTEST.conf', '-port=64365', '-rpcport=64366', '-regtest', '-addressindex=1', '-spentindex=1', '-ac_supply=5555555', '-ac_reward=10000000000000', '-pubkey=' + self.pubkey1, '-ac_cc=2', '-whitelist=127.0.0.1', '-debug', '-addnode=127.0.0.1:64367', '--daemon', '-rpcuser=rt', '-rpcpassword=rt']] ) self.is_network_split = split self.rpc = self.nodes[0] self.rpc1 = self.nodes[1] self.sync_all() print("Done setting up network") class CryptoconditionsTestFramework(BitcoinTestFramework): def __init__(self): self.num_nodes = 2 def setup_chain(self): print("Initializing CC test directory "+self.options.tmpdir) initialize_chain_clean(self.options.tmpdir, self.num_nodes) def setup_network(self, split = False): print("Setting up network...") self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D" self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf" self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9" self.addr1 = "RXEXoa1nRmKhMbuZovpcYwQMsicwzccZBp" self.pubkey1 = "024026d4ad4ecfc1f705a9b42ca64af6d2ad947509c085534a30b8861d756c6ff0" self.privkey1 = "UtdydP56pGTFmawHzHr1wDrc4oUwCNW1ttX8Pc3KrvH3MA8P49Wi" self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[ # always give -ac_name as first extra_arg and port as third '-ac_name=REGTEST', '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', '-port=64367', '-rpcport=64368', '-regtest', '-addressindex=1', '-spentindex=1', '-ac_supply=5555555', '-ac_reward=10000000000000', '-pubkey=' + self.pubkey, '-ac_cc=2', '-whitelist=127.0.0.1', '-debug', '--daemon', '-rpcuser=rt', '-rpcpassword=rt' ], ['-ac_name=REGTEST', '-conf='+self.options.tmpdir+'/node1/REGTEST.conf', '-port=64365', '-rpcport=64366', '-regtest', '-addressindex=1', '-spentindex=1', '-ac_supply=5555555', '-ac_reward=10000000000000', '-pubkey=' + self.pubkey1, '-ac_cc=2', '-whitelist=127.0.0.1', '-debug', '-addnode=127.0.0.1:64367', '--daemon', '-rpcuser=rt', '-rpcpassword=rt']] ) self.is_network_split = split self.rpc = self.nodes[0] self.rpc1 = self.nodes[1] self.sync_all() print("Done setting up network") def send_and_mine(self, xtn, rpc_connection): txid = rpc_connection.sendrawtransaction(xtn) assert txid, 'got txid' # we need the tx above to be confirmed in the next block rpc_connection.generate(1) return txid