def run_test(self): assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True) assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2) self.nodes[0].setnetworkactive(False) assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False) timeout = 3 while self.nodes[0].getnetworkinfo()['connections'] != 0: # Wait a bit for all sockets to close assert timeout > 0, 'not all connections closed in time' timeout -= 0.1 time.sleep(0.1) self.nodes[0].setnetworkactive(True) connect_nodes_bi(self.nodes, 0, 1) assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True) assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2) # test getaddednodeinfo assert_equal(self.nodes[0].getaddednodeinfo(), []) # add a node (node2) to node0 ip_port = "127.0.0.1:{}".format(p2p_port(2)) self.nodes[0].addnode(ip_port, 'add') # check that the node has indeed been added added_nodes = self.nodes[0].getaddednodeinfo(ip_port) assert_equal(len(added_nodes), 1) assert_equal(added_nodes[0]['addednode'], ip_port) # check that a non-existant node returns an error assert_raises_jsonrpc(-24, "Node has not been added", self.nodes[0].getaddednodeinfo, '1.1.1.1')
def run_test (self): tmpdir = self.options.tmpdir # Make sure can't switch off usehd after wallet creation self.stop_node(1) assert_start_raises_init_error(1, self.options.tmpdir, ['-usehd=0'], 'already existing HD wallet') self.nodes[1] = start_node(1, self.options.tmpdir, self.node_args[1]) connect_nodes_bi(self.nodes, 0, 1) # Make sure we use hd, keep masterkeyid masterkeyid = self.nodes[1].getwalletinfo()['hdmasterkeyid'] assert_equal(len(masterkeyid), 40) # Import a non-HD private key in the HD wallet non_hd_add = self.nodes[0].getnewaddress() self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add)) # This should be enough to keep the master key and the non-HD key self.nodes[1].backupwallet(tmpdir + "/hd.bak") #self.nodes[1].dumpwallet(tmpdir + "/hd.dump") # Derive some HD addresses and remember the last # Also send funds to each add self.nodes[0].generate(101) hd_add = None num_hd_adds = 300 for i in range(num_hd_adds): hd_add = self.nodes[1].getnewaddress() hd_info = self.nodes[1].validateaddress(hd_add) assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i+1)+"'") assert_equal(hd_info["hdmasterkeyid"], masterkeyid) self.nodes[0].sendtoaddress(hd_add, 1) self.nodes[0].generate(1) self.nodes[0].sendtoaddress(non_hd_add, 1) self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1) self.log.info("Restore backup ...") self.stop_node(1) os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat") shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat") self.nodes[1] = start_node(1, self.options.tmpdir, self.node_args[1]) #connect_nodes_bi(self.nodes, 0, 1) # Assert that derivation is deterministic hd_add_2 = None for _ in range(num_hd_adds): hd_add_2 = self.nodes[1].getnewaddress() hd_info_2 = self.nodes[1].validateaddress(hd_add_2) assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(_+1)+"'") assert_equal(hd_info_2["hdmasterkeyid"], masterkeyid) assert_equal(hd_add, hd_add_2) # Needs rescan self.stop_node(1) self.nodes[1] = start_node(1, self.options.tmpdir, self.node_args[1] + ['-rescan']) #connect_nodes_bi(self.nodes, 0, 1) assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
def restart_second_node(self, extra_args=[]): self.nodes[1].stop() bitcoind_processes[1].wait() self.nodes[1] = start_node(1, self.options.tmpdir, extra_args=['-regtestprotectcoinbase','-debug=zrpc'] + extra_args) self.nodes[1].setmocktime(starttime + 9000) connect_nodes_bi(self.nodes, 0, 1) self.sync_all()
def setup_network(self, split=False): self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[NUPARAMS_ARGS] * 3) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) self.is_network_split=False self.sync_all()
def run_test(self): self.log.info("test -blocknotify") block_count = 10 blocks = self.nodes[1].generatetoaddress(block_count, self.nodes[1].getnewaddress() if self.is_wallet_compiled() else ADDRESS_BCRT1_UNSPENDABLE) # wait at most 10 seconds for expected number of files before reading the content wait_until(lambda: len(os.listdir(self.blocknotify_dir)) == block_count, timeout=10) # directory content should equal the generated blocks hashes assert_equal(sorted(blocks), sorted(os.listdir(self.blocknotify_dir))) if self.is_wallet_compiled(): self.log.info("test -walletnotify") # wait at most 10 seconds for expected number of files before reading the content wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) # directory content should equal the generated transaction hashes txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir))) self.stop_node(1) for tx_file in os.listdir(self.walletnotify_dir): os.remove(os.path.join(self.walletnotify_dir, tx_file)) self.log.info("test -walletnotify after rescan") # restart node to rescan to force wallet notifications self.start_node(1) connect_nodes_bi(self.nodes, 0, 1) wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) # directory content should equal the generated transaction hashes txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir)))
def setup_network(self): self.setup_nodes() # Fully mesh-connect nodes for faster mempool sync for i, j in itertools.product(range(self.num_nodes), repeat=2): if i > j: connect_nodes_bi(self.nodes, i, j) self.sync_all()
def setup_network(self, split=False): self.nodes = start_nodes(5, self.options.tmpdir ) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) connect_nodes_bi(self.nodes,0,3) connect_nodes_bi(self.nodes,0,4) self.is_network_split=False self.sync_all()
def run_test(self): ########################### # setban/listbanned tests # ########################### assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point self.nodes[1].setban("127.0.0.1", "add") assert wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10) assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point assert_equal(len(self.nodes[1].listbanned()), 1) self.nodes[1].clearbanned() assert_equal(len(self.nodes[1].listbanned()), 0) self.nodes[1].setban("127.0.0.0/24", "add") assert_equal(len(self.nodes[1].listbanned()), 1) # This will throw an exception because 127.0.0.1 is within range 127.0.0.0/24 assert_raises_jsonrpc(-23, "IP/Subnet already banned", self.nodes[1].setban, "127.0.0.1", "add") # This will throw an exception because 127.0.0.1/42 is not a real subnet assert_raises_jsonrpc(-30, "Error: Invalid IP/Subnet", self.nodes[1].setban, "127.0.0.1/42", "add") assert_equal(len(self.nodes[1].listbanned()), 1) # still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 # This will throw an exception because 127.0.0.1 was not added above assert_raises_jsonrpc(-30, "Error: Unban failed", self.nodes[1].setban, "127.0.0.1", "remove") assert_equal(len(self.nodes[1].listbanned()), 1) self.nodes[1].setban("127.0.0.0/24", "remove") assert_equal(len(self.nodes[1].listbanned()), 0) self.nodes[1].clearbanned() assert_equal(len(self.nodes[1].listbanned()), 0) # test persisted banlist self.nodes[1].setban("127.0.0.0/32", "add") self.nodes[1].setban("127.0.0.0/24", "add") self.nodes[1].setban("192.168.0.1", "add", 1) # ban for 1 seconds self.nodes[1].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds listBeforeShutdown = self.nodes[1].listbanned() assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) assert wait_until(lambda: len(self.nodes[1].listbanned()) == 3, timeout=10) stop_node(self.nodes[1], 1) self.nodes[1] = start_node(1, self.options.tmpdir) listAfterShutdown = self.nodes[1].listbanned() assert_equal("127.0.0.0/24", listAfterShutdown[0]['address']) assert_equal("127.0.0.0/32", listAfterShutdown[1]['address']) assert_equal("/19" in listAfterShutdown[2]['address'], True) # Clear ban lists self.nodes[1].clearbanned() connect_nodes_bi(self.nodes, 0, 1) ########################### # RPC disconnectnode test # ########################### address1 = self.nodes[0].getpeerinfo()[0]['addr'] self.nodes[0].disconnectnode(address=address1) assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1] connect_nodes_bi(self.nodes, 0, 1) # reconnect the node assert [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
def setup_network(self): ''' Can't rely on syncing all the nodes when staking=1 :param: :return: ''' self.setup_nodes() for i in range(self.num_nodes - 1): for j in range(i+1, self.num_nodes): connect_nodes_bi(self.nodes, i, j)
def setup_network(self, split=False): self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[[ '-nuparams=5ba81b19:100', # Overwinter '-nuparams=76b809bb:201', # Sapling ]] * 3) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) self.is_network_split=False self.sync_all()
def run_test(self): self.log.info("test -blocknotify") block_count = 10 blocks = self.nodes[1].generate(block_count) # wait at most 10 seconds for expected file size before reading the content wait_until(lambda: os.path.isfile(self.block_filename) and os.stat(self.block_filename).st_size >= (block_count * 65), timeout=10) # file content should equal the generated blocks hashes with open(self.block_filename, 'r', encoding="utf-8") as f: assert_equal(sorted(blocks), sorted(l.strip() for l in f.read().splitlines())) self.log.info("test -walletnotify") # wait at most 10 seconds for expected file size before reading the content wait_until(lambda: os.path.isfile(self.tx_filename) and os.stat(self.tx_filename).st_size >= (block_count * 65), timeout=10) # file content should equal the generated transaction hashes txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) with open(self.tx_filename, 'r', encoding="ascii") as f: assert_equal(sorted(txids_rpc), sorted(l.strip() for l in f.read().splitlines())) os.remove(self.tx_filename) self.log.info("test -walletnotify after rescan") # restart node to rescan to force wallet notifications self.restart_node(1) connect_nodes_bi(self.nodes, 0, 1) wait_until(lambda: os.path.isfile(self.tx_filename) and os.stat(self.tx_filename).st_size >= (block_count * 65), timeout=10) # file content should equal the generated transaction hashes txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) with open(self.tx_filename, 'r', encoding="ascii") as f: assert_equal(sorted(txids_rpc), sorted(l.strip() for l in f.read().splitlines())) # Mine another 41 up-version blocks. -alertnotify should trigger on the 51st. self.log.info("test -alertnotify") self.nodes[1].generate(41) self.sync_all() # Give bitcoind 10 seconds to write the alert notification wait_until(lambda: os.path.isfile(self.alert_filename) and os.path.getsize(self.alert_filename), timeout=10) with open(self.alert_filename, 'r', encoding='utf8') as f: alert_text = f.read() # Mine more up-version blocks, should not get more alerts: self.nodes[1].generate(2) self.sync_all() with open(self.alert_filename, 'r', encoding='utf8') as f: alert_text2 = f.read() self.log.info("-alertnotify should not continue notifying for more unknown version blocks") assert_equal(alert_text, alert_text2)
def mine_chain(self): self.log.info('Create some old blocks') for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600): self.nodes[0].setmocktime(t) self.nodes[0].generate(1) mining_info = self.nodes[0].getmininginfo() assert_equal(mining_info['blocks'], 200) assert_equal(mining_info['currentblocktx'], 0) assert_equal(mining_info['currentblockweight'], 4000) self.restart_node(0) connect_nodes_bi(self.nodes, 0, 1)
def _test_getnetworkinginfo(self): assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True) assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2) self.nodes[0].setnetworkactive(False) assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False) # Wait a bit for all sockets to close wait_until(lambda: self.nodes[0].getnetworkinfo()['connections'] == 0, timeout=3) self.nodes[0].setnetworkactive(True) connect_nodes_bi(self.nodes, 0, 1) assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True) assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)
def run_test(self): assert(self.nodes[0].getblockcount() == 200) assert(self.nodes[2].getblockcount() == 200) self.split_network() print "Test the maximum-allowed reorg:" print "Mine 99 blocks on Node 0" self.nodes[0].generate(99) assert(self.nodes[0].getblockcount() == 299) assert(self.nodes[2].getblockcount() == 200) print "Mine competing 100 blocks on Node 2" self.nodes[2].generate(100) assert(self.nodes[0].getblockcount() == 299) assert(self.nodes[2].getblockcount() == 300) print "Connect nodes to force a reorg" connect_nodes_bi(self.nodes, 0, 2) self.is_network_split = False sync_blocks(self.nodes) print "Check Node 0 is still running and on the correct chain" assert(self.nodes[0].getblockcount() == 300) self.split_network() print "Test the minimum-rejected reorg:" print "Mine 100 blocks on Node 0" self.nodes[0].generate(100) assert(self.nodes[0].getblockcount() == 400) assert(self.nodes[2].getblockcount() == 300) print "Mine competing 101 blocks on Node 2" self.nodes[2].generate(101) assert(self.nodes[0].getblockcount() == 400) assert(self.nodes[2].getblockcount() == 401) print "Sync nodes to force a reorg" connect_nodes_bi(self.nodes, 0, 2) self.is_network_split = False # sync_blocks uses RPC calls to wait for nodes to be synced, so don't # call it here, because it will have a non-specific connection error # when Node 0 stops. Instead, we explicitly check for the process itself # to stop. print "Check Node 0 is no longer running" assert(check_stopped(0)) # Dummy stop to enable the test to tear down self.nodes[0].stop = lambda: True
def run_test(self): self.log.info("test -blocknotify") block_count = 10 blocks = self.nodes[1].generatetoaddress(block_count, self.nodes[1].getnewaddress() if self.is_wallet_compiled() else ADDRESS_BCRT1_UNSPENDABLE) # wait at most 10 seconds for expected number of files before reading the content wait_until(lambda: len(os.listdir(self.blocknotify_dir)) == block_count, timeout=10) # directory content should equal the generated blocks hashes assert_equal(sorted(blocks), sorted(os.listdir(self.blocknotify_dir))) if self.is_wallet_compiled(): self.log.info("test -walletnotify") # wait at most 10 seconds for expected number of files before reading the content wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) # directory content should equal the generated transaction hashes txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir))) self.stop_node(1) for tx_file in os.listdir(self.walletnotify_dir): os.remove(os.path.join(self.walletnotify_dir, tx_file)) self.log.info("test -walletnotify after rescan") # restart node to rescan to force wallet notifications self.start_node(1) connect_nodes_bi(self.nodes, 0, 1) wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) # directory content should equal the generated transaction hashes txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir))) # Mine another 41 up-version blocks. -alertnotify should trigger on the 51st. self.log.info("test -alertnotify") self.nodes[1].generatetoaddress(41, ADDRESS_BCRT1_UNSPENDABLE) self.sync_all() # Give bitcoind 10 seconds to write the alert notification wait_until(lambda: len(os.listdir(self.alertnotify_dir)), timeout=10) for notify_file in os.listdir(self.alertnotify_dir): os.remove(os.path.join(self.alertnotify_dir, notify_file)) # Mine more up-version blocks, should not get more alerts: self.nodes[1].generatetoaddress(2, ADDRESS_BCRT1_UNSPENDABLE) self.sync_all() self.log.info("-alertnotify should not continue notifying for more unknown version blocks") assert_equal(len(os.listdir(self.alertnotify_dir)), 0)
def setup_network(self, split=False): self.setup_nodes() connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) connect_nodes_bi(self.nodes, 0, 3)
def setup_network(self): self.setup_nodes() connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) connect_nodes_bi(self.nodes, 0, 3)
def setup_network(self, split=False): self.nodes = start_nodes(4, self.options.tmpdir, extra_args=[['-regtestprotectcoinbase', '-debug=zrpcunsafe']] * 4 ) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) connect_nodes_bi(self.nodes,0,3) self.is_network_split=False self.sync_all()
def setup_network(self, split=False): self.nodes = start_nodes(4, self.options.tmpdir, extra_args=[["-nuparams=5ba81b19:200", "-debug=zrpcunsafe", "-txindex"]] * 4 ) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) connect_nodes_bi(self.nodes,0,3) self.is_network_split=False self.sync_all()
def _test_getnetworkinginfo(self): assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True) assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2) self.nodes[0].setnetworkactive(False) assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False) timeout = 3 while self.nodes[0].getnetworkinfo()['connections'] != 0: # Wait a bit for all sockets to close assert timeout > 0, 'not all connections closed in time' timeout -= 0.1 time.sleep(0.1) self.nodes[0].setnetworkactive(True) connect_nodes_bi(self.nodes, 0, 1) assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True) assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)
def run_test(self): print "Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:" print "Mine 4 blocks on Node 0" self.nodes[0].generate(4) assert(self.nodes[0].getblockcount() == 4) besthash = self.nodes[0].getbestblockhash() print "Mine competing 6 blocks on Node 1" self.nodes[1].generate(6) assert(self.nodes[1].getblockcount() == 6) print "Connect nodes to force a reorg" connect_nodes_bi(self.nodes,0,1) sync_blocks(self.nodes[0:2]) assert(self.nodes[0].getblockcount() == 6) badhash = self.nodes[1].getblockhash(2) print "Invalidate block 2 on node 0 and verify we reorg to node 0's original chain" self.nodes[0].invalidateblock(badhash) newheight = self.nodes[0].getblockcount() newhash = self.nodes[0].getbestblockhash() if (newheight != 4 or newhash != besthash): raise AssertionError("Wrong tip for node0, hash %s, height %d"%(newhash,newheight)) print "\nMake sure we won't reorg to a lower work chain:" connect_nodes_bi(self.nodes,1,2) print "Sync node 2 to node 1 so both have 6 blocks" sync_blocks(self.nodes[1:3]) assert(self.nodes[2].getblockcount() == 6) print "Invalidate block 5 on node 1 so its tip is now at 4" self.nodes[1].invalidateblock(self.nodes[1].getblockhash(5)) assert(self.nodes[1].getblockcount() == 4) print "Invalidate block 3 on node 2, so its tip is now 2" self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3)) assert(self.nodes[2].getblockcount() == 2) print "..and then mine a block" self.nodes[2].generate(1) print "Verify all nodes are at the right height" time.sleep(5) for i in xrange(3): print i,self.nodes[i].getblockcount() assert(self.nodes[2].getblockcount() == 3) assert(self.nodes[0].getblockcount() == 4) node1height = self.nodes[1].getblockcount() if node1height < 4: raise AssertionError("Node 1 reorged to a lower height: %d"%node1height)
def set_test_params(self): self.log.info("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:") self.log.info("Mine 4 blocks on Node 0") self.nodes[0].generate(4) assert(self.nodes[0].getblockcount() == 4) besthash = self.nodes[0].getbestblockhash() self.log.info("Mine competing 6 blocks on Node 1") self.nodes[1].generate(6) assert(self.nodes[1].getblockcount() == 6) self.log.info("Connect nodes to force a reorg") connect_nodes_bi(self.nodes,0,1) sync_blocks(self.nodes[0:2]) assert(self.nodes[0].getblockcount() == 6) badhash = self.nodes[1].getblockhash(2) self.log.info("Invalidate block 2 on node 0 and verify we reorg to node 0's original chain") self.nodes[0].invalidateblock(badhash) newheight = self.nodes[0].getblockcount() newhash = self.nodes[0].getbestblockhash() if (newheight != 4 or newhash != besthash): raise AssertionError("Wrong tip for node0, hash %s, height %d"%(newhash,newheight)) self.log.info("Make sure we won't reorg to a lower work chain:") connect_nodes_bi(self.nodes,1,2) self.log.info("Sync node 2 to node 1 so both have 6 blocks") sync_blocks(self.nodes[1:3]) assert(self.nodes[2].getblockcount() == 6) self.log.info("Invalidate block 5 on node 1 so its tip is now at 4") self.nodes[1].invalidateblock(self.nodes[1].getblockhash(5)) assert(self.nodes[1].getblockcount() == 4) self.log.info("Invalidate block 3 on node 2, so its tip is now 2") self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3)) assert(self.nodes[2].getblockcount() == 2) self.log.info("..and then mine a block") self.nodes[2].generate(1) self.log.info("Verify all nodes are at the right height") time.sleep(5) assert_equal(self.nodes[2].getblockcount(), 3) assert_equal(self.nodes[0].getblockcount(), 4) node1height = self.nodes[1].getblockcount() if node1height < 4: raise AssertionError("Node 1 reorged to a lower height: %d"%node1height)
def run_test(self): self.tmpdir = self.options.tmpdir self.nodes[0].generate(101) self.log.info("Make backup of wallet") self.stop_node(1) shutil.copyfile(self.tmpdir + "/node1/regtest/wallet.dat", self.tmpdir + "/wallet.bak") self.start_node(1, self.extra_args[1]) connect_nodes_bi(self.nodes, 0, 1) self.log.info("Generate keys for wallet") for _ in range(90): addr_oldpool = self.nodes[1].getnewaddress() for _ in range(20): addr_extpool = self.nodes[1].getnewaddress() self.log.info("Send funds to wallet") self.nodes[0].sendtoaddress(addr_oldpool, 10) self.nodes[0].generate(1) self.nodes[0].sendtoaddress(addr_extpool, 5) self.nodes[0].generate(1) sync_blocks(self.nodes) self.log.info("Restart node with wallet backup") self.stop_node(1) shutil.copyfile(self.tmpdir + "/wallet.bak", self.tmpdir + "/node1/regtest/wallet.dat") self.log.info("Verify keypool is restored and balance is correct") self.start_node(1, self.extra_args[1]) connect_nodes_bi(self.nodes, 0, 1) self.sync_all() assert_equal(self.nodes[1].getbalance(), 15) assert_equal(self.nodes[1].listtransactions()[0]['category'], "receive") # Check that we have marked all keys up to the used keypool key as used assert_equal(self.nodes[1].validateaddress(self.nodes[1].getnewaddress())['hdkeypath'], "m/0'/0'/110'")
def setup_network(self, split=False): self.nodes = start_nodes(4, self.options.tmpdir, extra_args=[[ '-nuparams=5ba81b19:100', # Overwinter '-nuparams=76b809bb:200', # Sapling '-txindex' # Avoid JSONRPC error: No information available about transaction ]] * 4 ) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) connect_nodes_bi(self.nodes,0,3) self.is_network_split=False self.sync_all()
def run_test(self): ########################### # setban/listbanned tests # ########################### assert_equal(len(self.nodes[2].getpeerinfo()), 4) #we should have 4 nodes at this point self.nodes[2].setban("127.0.0.1", "add") time.sleep(3) #wait till the nodes are disconected assert_equal(len(self.nodes[2].getpeerinfo()), 0) #all nodes must be disconnected at this point assert_equal(len(self.nodes[2].listbanned()), 1) self.nodes[2].clearbanned() assert_equal(len(self.nodes[2].listbanned()), 0) self.nodes[2].setban("127.0.0.0/24", "add") assert_equal(len(self.nodes[2].listbanned()), 1) try: self.nodes[2].setban("127.0.0.1", "add") #throws exception because 127.0.0.1 is within range 127.0.0.0/24 except: pass assert_equal(len(self.nodes[2].listbanned()), 1) #still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 try: self.nodes[2].setban("127.0.0.1", "remove") except: pass assert_equal(len(self.nodes[2].listbanned()), 1) self.nodes[2].setban("127.0.0.0/24", "remove") assert_equal(len(self.nodes[2].listbanned()), 0) self.nodes[2].clearbanned() assert_equal(len(self.nodes[2].listbanned()), 0) ########################### # RPC disconnectnode test # ########################### url = urlparse.urlparse(self.nodes[1].url) self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1))) time.sleep(2) #disconnecting a node needs a little bit of time for node in self.nodes[0].getpeerinfo(): assert(node['addr'] != url.hostname+":"+str(p2p_port(1))) connect_nodes_bi(self.nodes,0,1) #reconnect the node found = False for node in self.nodes[0].getpeerinfo(): if node['addr'] == url.hostname+":"+str(p2p_port(1)): found = True assert(found)
def run_test(self): # Encrypt wallet for test_locked_wallet_fails test self.nodes[1].encryptwallet(WALLET_PASSPHRASE) self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) connect_nodes_bi(self.nodes, 0, 1) self.sync_all() peer_node, rbf_node = self.nodes rbf_node_address = rbf_node.getnewaddress() # fund rbf node with 10 coins of 0.001 btc (100,000 satoshis) self.log.info("Mining blocks...") peer_node.generate(110) self.sync_all() for i in range(25): peer_node.sendtoaddress(rbf_node_address, 0.001) self.sync_all() peer_node.generate(1) self.sync_all() assert_equal(rbf_node.getbalance(), Decimal("0.025")) self.log.info("Running tests") dest_address = peer_node.getnewaddress() test_simple_bumpfee_succeeds(self, rbf_node, peer_node, dest_address) test_segwit_bumpfee_succeeds(rbf_node, dest_address) test_nonrbf_bumpfee_fails(peer_node, dest_address) test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address) test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address) test_small_output_fails(rbf_node, dest_address) test_dust_to_fee(rbf_node, dest_address) test_settxfee(rbf_node, dest_address) test_rebumping(rbf_node, dest_address) test_rebumping_not_replaceable(rbf_node, dest_address) test_unconfirmed_not_spendable(rbf_node, rbf_node_address) test_bumpfee_metadata(rbf_node, dest_address) test_locked_wallet_fails(rbf_node, dest_address) test_change_script_match(rbf_node, dest_address) # These tests wipe out a number of utxos that are expected in other tests test_small_output_with_feerate_succeeds(rbf_node, dest_address) test_no_more_inputs_fails(rbf_node, dest_address) self.log.info("Success")
def run_test(self): raise SkipTest("Litecoin doesn't support RBF.") # Encrypt wallet for test_locked_wallet_fails test self.nodes[1].node_encrypt_wallet(WALLET_PASSPHRASE) self.start_node(1) self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) connect_nodes_bi(self.nodes, 0, 1) self.sync_all() peer_node, rbf_node = self.nodes rbf_node_address = rbf_node.getnewaddress() # fund rbf node with 10 coins of 0.001 btc (100,000 satoshis) self.log.info("Mining blocks...") peer_node.generate(110) self.sync_all() for i in range(25): peer_node.sendtoaddress(rbf_node_address, 0.001) self.sync_all() peer_node.generate(1) self.sync_all() assert_equal(rbf_node.getbalance(), Decimal("0.025")) self.log.info("Running tests") dest_address = peer_node.getnewaddress() test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address) test_segwit_bumpfee_succeeds(rbf_node, dest_address) test_nonrbf_bumpfee_fails(peer_node, dest_address) test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address) test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address) test_small_output_fails(rbf_node, dest_address) test_dust_to_fee(rbf_node, dest_address) test_settxfee(rbf_node, dest_address) test_rebumping(rbf_node, dest_address) test_rebumping_not_replaceable(rbf_node, dest_address) test_unconfirmed_not_spendable(rbf_node, rbf_node_address) test_bumpfee_metadata(rbf_node, dest_address) test_locked_wallet_fails(rbf_node, dest_address) self.log.info("Success")
def run_test(self): wallet_path = os.path.join(self.nodes[1].datadir, "regtest", "wallets", "wallet.dat") wallet_backup_path = os.path.join(self.nodes[1].datadir, "wallet.bak") self.nodes[0].generate(101) self.log.info("Make backup of wallet") self.stop_node(1) shutil.copyfile(wallet_path, wallet_backup_path) self.start_node(1, self.extra_args[1]) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 0, 2) connect_nodes_bi(self.nodes, 0, 3) for i, output_type in enumerate(["legacy", "p2sh-segwit", "bech32"]): self.log.info("Generate keys for wallet with address type: {}".format(output_type)) idx = i+1 for _ in range(90): addr_oldpool = self.nodes[idx].getnewaddress(address_type=output_type) for _ in range(20): addr_extpool = self.nodes[idx].getnewaddress(address_type=output_type) # Make sure we're creating the outputs we expect address_details = self.nodes[idx].validateaddress(addr_extpool) if i == 0: assert(not address_details["isscript"] and not address_details["iswitness"]) elif i == 1: assert(address_details["isscript"] and not address_details["iswitness"]) else: assert(not address_details["isscript"] and address_details["iswitness"]) self.log.info("Send funds to wallet") self.nodes[0].sendtoaddress(addr_oldpool, 10) self.nodes[0].generate(1) self.nodes[0].sendtoaddress(addr_extpool, 5) self.nodes[0].generate(1) sync_blocks(self.nodes) self.log.info("Restart node with wallet backup") self.stop_node(idx) shutil.copyfile(wallet_backup_path, wallet_path) self.start_node(idx, self.extra_args[idx]) connect_nodes_bi(self.nodes, 0, idx) self.sync_all() self.log.info("Verify keypool is restored and balance is correct") assert_equal(self.nodes[idx].getbalance(), 15) assert_equal(self.nodes[idx].listtransactions()[0]['category'], "receive") # Check that we have marked all keys up to the used keypool key as used assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress())['hdkeypath'], "m/0'/0'/110'")
def setup_network(self, split=False): self.setup_nodes() connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) self.is_network_split = False self.sync_all()
def setup_network(self): self.setup_nodes() # Only need nodes 0-2 running at start of test self.stop_node(3) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) self.sync_all(self.nodes[0:3])
def run_test(self): min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']*100 # This test is not meant to test fee estimation and we'd like # to be sure all txs are sent at a consistent desired feerate for node in self.nodes: node.settxfee(min_relay_tx_fee) # if the fee's positive delta is higher than this value tests will fail, # neg. delta always fail the tests. # The size of the signature of every input may be at most 2 bytes larger # than a minimum sized signature. # = 2 bytes * minRelayTxFeePerByte feeTolerance = 2 * min_relay_tx_fee/1000 self.nodes[2].generate(1) self.sync_all() self.nodes[0].generate(121) self.sync_all() # ensure that setting changePosition in fundraw with an exact match is handled properly rawmatch = self.nodes[2].createrawtransaction([], {self.nodes[2].getnewaddress():50}) rawmatch = self.nodes[2].fundrawtransaction(rawmatch, {"changePosition":1, "subtractFeeFromOutputs":[0]}) assert_equal(rawmatch["changepos"], -1) watchonly_address = self.nodes[0].getnewaddress() watchonly_pubkey = self.nodes[0].getaddressinfo(watchonly_address)["pubkey"] watchonly_amount = Decimal(200) self.nodes[3].importpubkey(watchonly_pubkey, "", True) watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address, watchonly_amount) # Lock UTXO so nodes[0] doesn't accidentally spend it watchonly_vout = find_vout_for_address(self.nodes[0], watchonly_txid, watchonly_address) self.nodes[0].lockunspent(False, [{"txid": watchonly_txid, "vout": watchonly_vout}]) self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(), watchonly_amount / 10) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0) self.nodes[0].generate(1) self.sync_all() ############### # simple test # ############### inputs = [ ] outputs = { self.nodes[0].getnewaddress() : 1.0 } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) assert(len(dec_tx['vin']) > 0) #test that we have enough inputs ############################## # simple test with two coins # ############################## inputs = [ ] outputs = { self.nodes[0].getnewaddress() : 2.2 } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) assert(len(dec_tx['vin']) > 0) #test if we have enough inputs ############################## # simple test with two coins # ############################## inputs = [ ] outputs = { self.nodes[0].getnewaddress() : 2.6 } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) assert(len(dec_tx['vin']) > 0) assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') ################################ # simple test with two outputs # ################################ inputs = [ ] outputs = { self.nodes[0].getnewaddress() : 2.6, self.nodes[1].getnewaddress() : 2.5 } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) totalOut = 0 for out in dec_tx['vout']: totalOut += out['value'] assert(len(dec_tx['vin']) > 0) assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') ######################################################################### # test a fundrawtransaction with a VIN greater than the required amount # ######################################################################### utx = get_unspent(self.nodes[2].listunspent(), 5) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] outputs = { self.nodes[0].getnewaddress() : 1.0 } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) totalOut = 0 for out in dec_tx['vout']: totalOut += out['value'] assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee ##################################################################### # test a fundrawtransaction with which will not get a change output # ##################################################################### utx = get_unspent(self.nodes[2].listunspent(), 5) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] outputs = { self.nodes[0].getnewaddress() : Decimal(5.0) - fee - feeTolerance } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) totalOut = 0 for out in dec_tx['vout']: totalOut += out['value'] assert_equal(rawtxfund['changepos'], -1) assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee #################################################### # test a fundrawtransaction with an invalid option # #################################################### utx = get_unspent(self.nodes[2].listunspent(), 5) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ] outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) assert_raises_rpc_error(-3, "Unexpected key foo", self.nodes[2].fundrawtransaction, rawtx, {'foo':'bar'}) # reserveChangeKey was deprecated and is now removed assert_raises_rpc_error(-3, "Unexpected key reserveChangeKey", lambda: self.nodes[2].fundrawtransaction(hexstring=rawtx, options={'reserveChangeKey': True})) ############################################################ # test a fundrawtransaction with an invalid change address # ############################################################ utx = get_unspent(self.nodes[2].listunspent(), 5) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ] outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) assert_raises_rpc_error(-5, "changeAddress must be a valid DeepOnion address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'}) ############################################################ # test a fundrawtransaction with a provided change address # ############################################################ utx = get_unspent(self.nodes[2].listunspent(), 5) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ] outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) change = self.nodes[2].getnewaddress() assert_raises_rpc_error(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':change, 'changePosition':2}) rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0}) dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) out = dec_tx['vout'][0] assert_equal(change, out['scriptPubKey']['addresses'][0]) ######################################################### # test a fundrawtransaction with a provided change type # ######################################################### utx = get_unspent(self.nodes[2].listunspent(), 5) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ] outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[2].fundrawtransaction, rawtx, {'change_type': None}) assert_raises_rpc_error(-5, "Unknown change type ''", self.nodes[2].fundrawtransaction, rawtx, {'change_type': ''}) rawtx = self.nodes[2].fundrawtransaction(rawtx, {'change_type': 'bech32'}) dec_tx = self.nodes[2].decoderawtransaction(rawtx['hex']) assert_equal('witness_v0_keyhash', dec_tx['vout'][rawtx['changepos']]['scriptPubKey']['type']) ######################################################################### # test a fundrawtransaction with a VIN smaller than the required amount # ######################################################################### utx = get_unspent(self.nodes[2].listunspent(), 1) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] outputs = { self.nodes[0].getnewaddress() : 1.0 } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) # 4-byte version + 1-byte vin count + 36-byte prevout then script_len rawtx = rawtx[:82] + "0100" + rawtx[84:] dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex']) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) totalOut = 0 matchingOuts = 0 for i, out in enumerate(dec_tx['vout']): totalOut += out['value'] if out['scriptPubKey']['addresses'][0] in outputs: matchingOuts+=1 else: assert_equal(i, rawtxfund['changepos']) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex']) assert_equal(matchingOuts, 1) assert_equal(len(dec_tx['vout']), 2) ########################################### # test a fundrawtransaction with two VINs # ########################################### utx = get_unspent(self.nodes[2].listunspent(), 1) utx2 = get_unspent(self.nodes[2].listunspent(), 5) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ] outputs = { self.nodes[0].getnewaddress() : 6.0 } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) totalOut = 0 matchingOuts = 0 for out in dec_tx['vout']: totalOut += out['value'] if out['scriptPubKey']['addresses'][0] in outputs: matchingOuts+=1 assert_equal(matchingOuts, 1) assert_equal(len(dec_tx['vout']), 2) matchingIns = 0 for vinOut in dec_tx['vin']: for vinIn in inputs: if vinIn['txid'] == vinOut['txid']: matchingIns+=1 assert_equal(matchingIns, 2) #we now must see two vins identical to vins given as params ######################################################### # test a fundrawtransaction with two VINs and two vOUTs # ######################################################### utx = get_unspent(self.nodes[2].listunspent(), 1) utx2 = get_unspent(self.nodes[2].listunspent(), 5) inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ] outputs = { self.nodes[0].getnewaddress() : 6.0, self.nodes[0].getnewaddress() : 1.0 } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) totalOut = 0 matchingOuts = 0 for out in dec_tx['vout']: totalOut += out['value'] if out['scriptPubKey']['addresses'][0] in outputs: matchingOuts+=1 assert_equal(matchingOuts, 2) assert_equal(len(dec_tx['vout']), 3) ############################################## # test a fundrawtransaction with invalid vin # ############################################## inputs = [ {'txid' : "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1", 'vout' : 0} ] #invalid vin! outputs = { self.nodes[0].getnewaddress() : 1.0} rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx) ############################################################ #compare fee of a standard pubkeyhash transaction inputs = [] outputs = {self.nodes[1].getnewaddress():1.1} rawtx = self.nodes[0].createrawtransaction(inputs, outputs) fundedTx = self.nodes[0].fundrawtransaction(rawtx) #create same transaction over sendtoaddress txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] #compare fee feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert(feeDelta >= 0 and feeDelta <= feeTolerance) ############################################################ ############################################################ #compare fee of a standard pubkeyhash transaction with multiple outputs inputs = [] outputs = {self.nodes[1].getnewaddress():1.1,self.nodes[1].getnewaddress():1.2,self.nodes[1].getnewaddress():0.1,self.nodes[1].getnewaddress():1.3,self.nodes[1].getnewaddress():0.2,self.nodes[1].getnewaddress():0.3} rawtx = self.nodes[0].createrawtransaction(inputs, outputs) fundedTx = self.nodes[0].fundrawtransaction(rawtx) #create same transaction over sendtoaddress txId = self.nodes[0].sendmany("", outputs) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] #compare fee feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert(feeDelta >= 0 and feeDelta <= feeTolerance) ############################################################ ############################################################ #compare fee of a 2of2 multisig p2sh transaction # create 2of2 addr addr1 = self.nodes[1].getnewaddress() addr2 = self.nodes[1].getnewaddress() addr1Obj = self.nodes[1].getaddressinfo(addr1) addr2Obj = self.nodes[1].getaddressinfo(addr2) mSigObj = self.nodes[1].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address'] inputs = [] outputs = {mSigObj:1.1} rawtx = self.nodes[0].createrawtransaction(inputs, outputs) fundedTx = self.nodes[0].fundrawtransaction(rawtx) #create same transaction over sendtoaddress txId = self.nodes[0].sendtoaddress(mSigObj, 1.1) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] #compare fee feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert(feeDelta >= 0 and feeDelta <= feeTolerance) ############################################################ ############################################################ #compare fee of a standard pubkeyhash transaction # create 4of5 addr addr1 = self.nodes[1].getnewaddress() addr2 = self.nodes[1].getnewaddress() addr3 = self.nodes[1].getnewaddress() addr4 = self.nodes[1].getnewaddress() addr5 = self.nodes[1].getnewaddress() addr1Obj = self.nodes[1].getaddressinfo(addr1) addr2Obj = self.nodes[1].getaddressinfo(addr2) addr3Obj = self.nodes[1].getaddressinfo(addr3) addr4Obj = self.nodes[1].getaddressinfo(addr4) addr5Obj = self.nodes[1].getaddressinfo(addr5) mSigObj = self.nodes[1].addmultisigaddress(4, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey'], addr4Obj['pubkey'], addr5Obj['pubkey']])['address'] inputs = [] outputs = {mSigObj:1.1} rawtx = self.nodes[0].createrawtransaction(inputs, outputs) fundedTx = self.nodes[0].fundrawtransaction(rawtx) #create same transaction over sendtoaddress txId = self.nodes[0].sendtoaddress(mSigObj, 1.1) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] #compare fee feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert(feeDelta >= 0 and feeDelta <= feeTolerance) ############################################################ ############################################################ # spend a 2of2 multisig transaction over fundraw # create 2of2 addr addr1 = self.nodes[2].getnewaddress() addr2 = self.nodes[2].getnewaddress() addr1Obj = self.nodes[2].getaddressinfo(addr1) addr2Obj = self.nodes[2].getaddressinfo(addr2) mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address'] # send 1.2 BTC to msig addr txId = self.nodes[0].sendtoaddress(mSigObj, 1.2) self.sync_all() self.nodes[1].generate(1) self.sync_all() oldBalance = self.nodes[1].getbalance() inputs = [] outputs = {self.nodes[1].getnewaddress():1.1} rawtx = self.nodes[2].createrawtransaction(inputs, outputs) fundedTx = self.nodes[2].fundrawtransaction(rawtx) signedTx = self.nodes[2].signrawtransactionwithwallet(fundedTx['hex']) txId = self.nodes[2].sendrawtransaction(signedTx['hex']) self.sync_all() self.nodes[1].generate(1) self.sync_all() # make sure funds are received at node1 assert_equal(oldBalance+Decimal('1.10000000'), self.nodes[1].getbalance()) ############################################################ # locked wallet test self.nodes[1].encryptwallet("test") self.stop_nodes() self.start_nodes() # This test is not meant to test fee estimation and we'd like # to be sure all txs are sent at a consistent desired feerate for node in self.nodes: node.settxfee(min_relay_tx_fee) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) connect_nodes_bi(self.nodes,0,3) # Again lock the watchonly UTXO or nodes[0] may spend it, because # lockunspent is memory-only and thus lost on restart self.nodes[0].lockunspent(False, [{"txid": watchonly_txid, "vout": watchonly_vout}]) self.sync_all() # drain the keypool self.nodes[1].getnewaddress() self.nodes[1].getrawchangeaddress() inputs = [] outputs = {self.nodes[0].getnewaddress():1.1} rawtx = self.nodes[1].createrawtransaction(inputs, outputs) # fund a transaction that requires a new key for the change output # creating the key must be impossible because the wallet is locked assert_raises_rpc_error(-4, "Keypool ran out, please call keypoolrefill first", self.nodes[1].fundrawtransaction, rawtx) #refill the keypool self.nodes[1].walletpassphrase("test", 100) self.nodes[1].keypoolrefill(8) #need to refill the keypool to get an internal change address self.nodes[1].walletlock() assert_raises_rpc_error(-13, "walletpassphrase", self.nodes[1].sendtoaddress, self.nodes[0].getnewaddress(), 1.2) oldBalance = self.nodes[0].getbalance() inputs = [] outputs = {self.nodes[0].getnewaddress():1.1} rawtx = self.nodes[1].createrawtransaction(inputs, outputs) fundedTx = self.nodes[1].fundrawtransaction(rawtx) #now we need to unlock self.nodes[1].walletpassphrase("test", 600) signedTx = self.nodes[1].signrawtransactionwithwallet(fundedTx['hex']) txId = self.nodes[1].sendrawtransaction(signedTx['hex']) self.nodes[1].generate(1) self.sync_all() # make sure funds are received at node1 assert_equal(oldBalance+Decimal('51.10000000'), self.nodes[0].getbalance()) ############################################### # multiple (~19) inputs tx test | Compare fee # ############################################### #empty node1, send some small coins from node0 to node1 self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True) self.sync_all() self.nodes[0].generate(1) self.sync_all() for i in range(0,20): self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) self.nodes[0].generate(1) self.sync_all() #fund a tx with ~20 small inputs inputs = [] outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04} rawtx = self.nodes[1].createrawtransaction(inputs, outputs) fundedTx = self.nodes[1].fundrawtransaction(rawtx) #create same transaction over sendtoaddress txId = self.nodes[1].sendmany("", outputs) signedFee = self.nodes[1].getrawmempool(True)[txId]['fee'] #compare fee feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert(feeDelta >= 0 and feeDelta <= feeTolerance*19) #~19 inputs ############################################# # multiple (~19) inputs tx test | sign/send # ############################################# #again, empty node1, send some small coins from node0 to node1 self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True) self.sync_all() self.nodes[0].generate(1) self.sync_all() for i in range(0,20): self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) self.nodes[0].generate(1) self.sync_all() #fund a tx with ~20 small inputs oldBalance = self.nodes[0].getbalance() inputs = [] outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04} rawtx = self.nodes[1].createrawtransaction(inputs, outputs) fundedTx = self.nodes[1].fundrawtransaction(rawtx) fundedAndSignedTx = self.nodes[1].signrawtransactionwithwallet(fundedTx['hex']) txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex']) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(oldBalance+Decimal('50.19000000'), self.nodes[0].getbalance()) #0.19+block reward ##################################################### # test fundrawtransaction with OP_RETURN and no vin # ##################################################### rawtx = "0100000000010000000000000000066a047465737400000000" dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(len(dec_tx['vin']), 0) assert_equal(len(dec_tx['vout']), 1) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) assert_greater_than(len(dec_tx['vin']), 0) # at least one vin assert_equal(len(dec_tx['vout']), 2) # one change output added ################################################## # test a fundrawtransaction using only watchonly # ################################################## inputs = [] outputs = {self.nodes[2].getnewaddress() : watchonly_amount / 2} rawtx = self.nodes[3].createrawtransaction(inputs, outputs) result = self.nodes[3].fundrawtransaction(rawtx, {'includeWatching': True }) res_dec = self.nodes[0].decoderawtransaction(result["hex"]) assert_equal(len(res_dec["vin"]), 1) assert_equal(res_dec["vin"][0]["txid"], watchonly_txid) assert("fee" in result.keys()) assert_greater_than(result["changepos"], -1) ############################################################### # test fundrawtransaction using the entirety of watched funds # ############################################################### inputs = [] outputs = {self.nodes[2].getnewaddress() : watchonly_amount} rawtx = self.nodes[3].createrawtransaction(inputs, outputs) # Backward compatibility test (2nd param is includeWatching) result = self.nodes[3].fundrawtransaction(rawtx, True) res_dec = self.nodes[0].decoderawtransaction(result["hex"]) assert_equal(len(res_dec["vin"]), 2) assert(res_dec["vin"][0]["txid"] == watchonly_txid or res_dec["vin"][1]["txid"] == watchonly_txid) assert_greater_than(result["fee"], 0) assert_greater_than(result["changepos"], -1) assert_equal(result["fee"] + res_dec["vout"][result["changepos"]]["value"], watchonly_amount / 10) signedtx = self.nodes[3].signrawtransactionwithwallet(result["hex"]) assert(not signedtx["complete"]) signedtx = self.nodes[0].signrawtransactionwithwallet(signedtx["hex"]) assert(signedtx["complete"]) self.nodes[0].sendrawtransaction(signedtx["hex"]) self.nodes[0].generate(1) self.sync_all() ####################### # Test feeRate option # ####################### # Make sure there is exactly one input so coin selection can't skew the result assert_equal(len(self.nodes[3].listunspent(1)), 1) inputs = [] outputs = {self.nodes[3].getnewaddress() : 1} rawtx = self.nodes[3].createrawtransaction(inputs, outputs) result = self.nodes[3].fundrawtransaction(rawtx) # uses min_relay_tx_fee (set by settxfee) result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee}) result3 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 10*min_relay_tx_fee}) assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[3].fundrawtransaction, rawtx, {"feeRate": 1}) result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex']) assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate) assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate) ################################ # Test no address reuse occurs # ################################ result3 = self.nodes[3].fundrawtransaction(rawtx) res_dec = self.nodes[0].decoderawtransaction(result3["hex"]) changeaddress = "" for out in res_dec['vout']: if out['value'] > 1.0: changeaddress += out['scriptPubKey']['addresses'][0] assert(changeaddress != "") nextaddr = self.nodes[3].getnewaddress() # Now the change address key should be removed from the keypool assert(changeaddress != nextaddr) ###################################### # Test subtractFeeFromOutputs option # ###################################### # Make sure there is exactly one input so coin selection can't skew the result assert_equal(len(self.nodes[3].listunspent(1)), 1) inputs = [] outputs = {self.nodes[2].getnewaddress(): 1} rawtx = self.nodes[3].createrawtransaction(inputs, outputs) result = [self.nodes[3].fundrawtransaction(rawtx), # uses min_relay_tx_fee (set by settxfee) self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": []}), # empty subtraction list self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0]}), # uses min_relay_tx_fee (set by settxfee) self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee}), self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee, "subtractFeeFromOutputs": [0]})] dec_tx = [self.nodes[3].decoderawtransaction(tx_['hex']) for tx_ in result] output = [d['vout'][1 - r['changepos']]['value'] for d, r in zip(dec_tx, result)] change = [d['vout'][r['changepos']]['value'] for d, r in zip(dec_tx, result)] assert_equal(result[0]['fee'], result[1]['fee'], result[2]['fee']) assert_equal(result[3]['fee'], result[4]['fee']) assert_equal(change[0], change[1]) assert_equal(output[0], output[1]) assert_equal(output[0], output[2] + result[2]['fee']) assert_equal(change[0] + result[0]['fee'], change[2]) assert_equal(output[3], output[4] + result[4]['fee']) assert_equal(change[3] + result[3]['fee'], change[4]) inputs = [] outputs = {self.nodes[2].getnewaddress(): value for value in (1.0, 1.1, 1.2, 1.3)} rawtx = self.nodes[3].createrawtransaction(inputs, outputs) result = [self.nodes[3].fundrawtransaction(rawtx), # split the fee between outputs 0, 2, and 3, but not output 1 self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0, 2, 3]})] dec_tx = [self.nodes[3].decoderawtransaction(result[0]['hex']), self.nodes[3].decoderawtransaction(result[1]['hex'])] # Nested list of non-change output amounts for each transaction output = [[out['value'] for i, out in enumerate(d['vout']) if i != r['changepos']] for d, r in zip(dec_tx, result)] # List of differences in output amounts between normal and subtractFee transactions share = [o0 - o1 for o0, o1 in zip(output[0], output[1])] # output 1 is the same in both transactions assert_equal(share[1], 0) # the other 3 outputs are smaller as a result of subtractFeeFromOutputs assert_greater_than(share[0], 0) assert_greater_than(share[2], 0) assert_greater_than(share[3], 0) # outputs 2 and 3 take the same share of the fee assert_equal(share[2], share[3]) # output 0 takes at least as much share of the fee, and no more than 2 satoshis more, than outputs 2 and 3 assert_greater_than_or_equal(share[0], share[2]) assert_greater_than_or_equal(share[2] + Decimal(2e-8), share[0]) # the fee is the same in both transactions assert_equal(result[0]['fee'], result[1]['fee']) # the total subtracted from the outputs is equal to the fee assert_equal(share[0] + share[2] + share[3], result[0]['fee'])
def run_test(self): def wait_for_tip(node, tip): def check_tip(): return node.getbestblockhash() == tip wait_until(check_tip) node = self.nodes[0] parking_node = self.nodes[1] self.log.info("Test chain parking...") node.generate(10) tip = node.getbestblockhash() node.generate(1) block_to_park = node.getbestblockhash() node.generate(10) parked_tip = node.getbestblockhash() # get parking_node caught up. # (probably not needed, but just in case parking can have race # condition like invalidateblock below) wait_for_tip(parking_node, parked_tip) # Let's park the chain. assert parked_tip != tip assert block_to_park != tip assert block_to_park != parked_tip node.parkblock(block_to_park) assert_equal(node.getbestblockhash(), tip) # When the chain is unparked, the node reorg into its original chain. node.unparkblock(parked_tip) assert_equal(node.getbestblockhash(), parked_tip) # Parking and then unparking a block should not change its validity, # and invaliding and reconsidering a block should not change its # parked state. See the following test cases: self.log.info("Test invalidate, park, unpark, reconsider...") node.generate(1) tip = node.getbestblockhash() node.generate(1) bad_tip = node.getbestblockhash() # Generate an extra block to check that children are invalidated as # expected and do not produce dangling chaintips node.generate(1) good_tip = node.getbestblockhash() # avoid race condition from parking_node requesting block when invalid wait_for_tip(parking_node, good_tip) node.invalidateblock(bad_tip) self.only_valid_tip(tip, other_tip_status="invalid") node.parkblock(bad_tip) self.only_valid_tip(tip, other_tip_status="invalid") node.unparkblock(bad_tip) self.only_valid_tip(tip, other_tip_status="invalid") node.reconsiderblock(bad_tip) self.only_valid_tip(good_tip) self.log.info("Test park, invalidate, reconsider, unpark") node.generate(1) tip = node.getbestblockhash() node.generate(1) bad_tip = node.getbestblockhash() node.generate(1) good_tip = node.getbestblockhash() # avoid race condition from parking_node requesting block when invalid wait_for_tip(parking_node, good_tip) node.parkblock(bad_tip) self.only_valid_tip(tip, other_tip_status="parked") node.invalidateblock(bad_tip) # NOTE: Intuitively, other_tip_status would be "invalid", but because # only valid (unparked) chains are walked, child blocks' statuses are # not updated, so the "parked" state remains. self.only_valid_tip(tip, other_tip_status="parked") node.reconsiderblock(bad_tip) self.only_valid_tip(tip, other_tip_status="parked") node.unparkblock(bad_tip) self.only_valid_tip(good_tip) self.log.info("Test invalidate, park, reconsider, unpark...") node.generate(1) tip = node.getbestblockhash() node.generate(1) bad_tip = node.getbestblockhash() node.generate(1) good_tip = node.getbestblockhash() # avoid race condition from parking_node requesting block when invalid wait_for_tip(parking_node, good_tip) node.invalidateblock(bad_tip) self.only_valid_tip(tip, other_tip_status="invalid") node.parkblock(bad_tip) self.only_valid_tip(tip, other_tip_status="invalid") node.reconsiderblock(bad_tip) self.only_valid_tip(tip, other_tip_status="parked") node.unparkblock(bad_tip) self.only_valid_tip(good_tip) self.log.info("Test park, invalidate, unpark, reconsider") node.generate(1) tip = node.getbestblockhash() node.generate(1) bad_tip = node.getbestblockhash() node.generate(1) good_tip = node.getbestblockhash() # avoid race condition from parking_node requesting block when invalid wait_for_tip(parking_node, good_tip) node.parkblock(bad_tip) self.only_valid_tip(tip, other_tip_status="parked") node.invalidateblock(bad_tip) # NOTE: Intuitively, other_tip_status would be "invalid", but because # only valid (unparked) chains are walked, child blocks' statuses are # not updated, so the "parked" state remains. self.only_valid_tip(tip, other_tip_status="parked") node.unparkblock(bad_tip) self.only_valid_tip(tip, other_tip_status="invalid") node.reconsiderblock(bad_tip) self.only_valid_tip(good_tip) # To get ready for next testset, make sure both nodes are in sync. wait_for_tip(parking_node, good_tip) assert_equal(node.getbestblockhash(), parking_node.getbestblockhash()) # Wait for node 1 to park the chain. def wait_for_parked_block(block): def check_block(): for tip in parking_node.getchaintips(): if tip["hash"] == block: assert tip["status"] != "active" return tip["status"] == "parked" return False wait_until(check_block) def check_reorg_protection(depth, extra_blocks): self.log.info( "Test deep reorg parking, {} block deep".format(depth)) # Invalidate the tip on node 0, so it doesn't follow node 1. node.invalidateblock(node.getbestblockhash()) # Mine block to create a fork of proper depth parking_node.generatetoaddress( nblocks=depth - 1, address=parking_node.getnewaddress(label='coinbase')) node.generatetoaddress( nblocks=depth, address=node.getnewaddress(label='coinbase')) # extra block should now find themselves parked for i in range(extra_blocks): node.generate(1) wait_for_parked_block(node.getbestblockhash()) # If we mine one more block, the node reorgs. node.generate(1) wait_until(lambda: parking_node.getbestblockhash() == node. getbestblockhash()) check_reorg_protection(1, 0) check_reorg_protection(2, 0) check_reorg_protection(3, 1) check_reorg_protection(4, 4) check_reorg_protection(5, 5) check_reorg_protection(6, 6) check_reorg_protection(100, 100) # try deep reorg with a log check. with parking_node.assert_debug_log(["Park block"]): check_reorg_protection(3, 1) self.log.info( "Accepting many blocks at once (possibly out of order) should not park if there is no reorg." ) # rewind one block to make a reorg that is shallow. node.invalidateblock(parking_node.getbestblockhash()) # generate a ton of blocks at once. try: with parking_node.assert_debug_log(["Park block"]): node.generatetoaddress( nblocks=20, address=node.getnewaddress(label='coinbase')) wait_until(lambda: parking_node.getbestblockhash() == node. getbestblockhash()) except AssertionError as exc: # good, we want an absence of "Park block" messages assert "does not partially match log" in exc.args[0] else: raise AssertionError("Parked block when there was no deep reorg") self.log.info("Test that unparking works when -parkdeepreorg=0") # Set up parking node height = fork + 4, node height = fork + 5 node.invalidateblock(node.getbestblockhash()) parking_node.generate(3) node.generatetoaddress(nblocks=5, address=node.getnewaddress(label='coinbase')) wait_for_parked_block(node.getbestblockhash()) # Restart the parking node without parkdeepreorg. self.restart_node(1, ["-parkdeepreorg=0"]) parking_node = self.nodes[1] connect_nodes_bi(node, parking_node) # The other chain should still be marked 'parked'. wait_for_parked_block(node.getbestblockhash()) # Three more blocks is not enough to unpark. Even though its PoW is # larger, we are still following the delayed-unparking rules. node.generate(3) wait_for_parked_block(node.getbestblockhash()) # Final block pushes over the edge, and should unpark. node.generate(1) wait_until( lambda: parking_node.getbestblockhash() == node.getbestblockhash(), timeout=5)
def setup_network(self): self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-nuparams=5ba81b19:10']] * 3) connect_nodes_bi(self.nodes, 0, 1)
def test_mix_contract_transaction_fork(self, gen_blocks=False): ''' 在2条分叉链中,混合执行各种交易,然后: 1.不产生块,合并网络 2.产生块,合并网络 :return: ''' self.sync_all() self.node1.generate(2) assert_equal(self.node1.getrawmempool(), []) # make sure mempool empty assert_equal(self.node0.getrawmempool(), []) # make sure mempool empty ct = Contract(self.node0, self.options.tmpdir, debug=False) ct2 = Contract(self.node0, self.options.tmpdir, debug=False) ct2.call_payable(amount=1000) print(ct.publish_txid) self.sync_all() self.node0.generate(2) self.sync_all() blocks_num = self.node0.getblockcount() # split mgc network self.split_network() self.node0.generate(2) # fork self.node2.generate(8) # fork balances = [n.getbalance() for n in self.nodes] # in group 1 # normal transaction sendtxs_a = [ self.node0.sendtoaddress(self.node3.getnewaddress(), 1000) for i in range(5) ] # publish contract transaction ccontracts_a = [ Contract(self.node0, self.options.tmpdir, debug=False) for i in range(5) ] # call contract transaction call_contract_txs_a = [ ct.call_payable(amount=1000).txid for ct in ccontracts_a ] call_contract_txs_a1 = [ ct.call_callOtherContractTest(ccontracts_a[0].contract_id, 'callOtherContractTest', ccontracts_a[-1].contract_id, "contractDataTest").txid for ct in ccontracts_a ] # long mempool chain transaction for i in range(8): result = ccontracts_a[1].call_reentrancyTest(throw_exception=False) ccontracts_a[2].call_maxContractCallTest(2).txid self.sync_all([self.nodes[:2], self.nodes[2:]]) # in group 2 sendtxs_b = [ self.node2.sendtoaddress(self.node1.getnewaddress(), 1000) for i in range(5) ] # publish contract transaction ccontracts_b = [ Contract(self.node2, self.options.tmpdir, debug=False) for i in range(5) ] # call contract transaction call_contract_txs_b = [ ct.call_payable(amount=1000).txid for ct in ccontracts_b ] call_contract_txs_b1 = [ ct.call_callOtherContractTest(ccontracts_b[0].contract_id, 'callOtherContractTest', ccontracts_b[-1].contract_id, "contractDataTest").txid for ct in ccontracts_b ] # long mempool chain transaction for i in range(8): result = ccontracts_b[1].call_reentrancyTest(throw_exception=False) ccontracts_b[2].call_maxContractCallTest(2).txid self.sync_all([self.nodes[:2], self.nodes[2:]]) # join network if gen_blocks: blocks_a = self.node0.generate(2) blocks_b = self.node2.generate(6) more_work_blocks = self.make_more_work_than(2, 0) for i in range(4): print("before join:", i, self.nodes[i].getblockcount(), int(self.nodes[i].getchaintipwork(), 16)) print("mempool:", self.nodes[i].getrawmempool()) print("join network") connect_nodes_bi(self.nodes, 1, 2) try: print("sync_mempools.......") # sync_mempools(self.nodes, timeout=30) print("sync_mempools done") except Exception as e: print("sync mempool failed,ignore!") sync_blocks(self.nodes) if gen_blocks: for i in range(4): print("mempool:", self.nodes[i].getrawmempool()) for i in range(4): print(i, self.nodes[i].getblockcount(), int(self.nodes[i].getchaintipwork(), 16)) tips = self.nodes[0].getchaintips() print("tips:", tips) assert_equal(len(tips), self.tips_num + 1) self.tips_num += 1 # 合并后,节点再次调用合约,该交易应该回被不同组的节点抛弃,因为合约不存在 result = ccontracts_a[2].call_reentrancyTest() if not result.reason(): tx1 = result.txid result = ccontracts_b[2].call_reentrancyTest() if not result.reason(): tx2 = result.txid # tx1 = ccontracts_a[2].call_reentrancyTest().txid # tx2 = ccontracts_b[2].call_reentrancyTest().txid try: sync_mempools(self.nodes, timeout=30) except Exception as e: print("sync_mempools(self.nodes,timeout = 30) not done") # wait_until(lambda: tx1 not in self.node2.getrawmempool(), timeout=10) # wait_until(lambda: tx1 in self.node1.getrawmempool(), timeout=10) # wait_until(lambda: tx2 not in self.node1.getrawmempool(), timeout=10) # wait_until(lambda: tx2 in self.node3.getrawmempool(), timeout=10) for i, n in enumerate(self.nodes): n.generate(2) print("node{} generate done".format(i)) sync_blocks(self.nodes)
def test_double_publish(self): ''' 同一个合约交易,在主链与分叉上发布 合并后,确认数为2(bb-bb4),而不是3(a1-a2-a3) txid同时存在于listsinceblock的transactions和removed 只消耗一份utxo,合约余额也只有一份 ab0 / \ aa1 [ca1] bb1 | | aa2 bb2 | | aa3 bb3 [ca1] | bb4 :return: ''' self.sync_all() self.node0.generate(2) self.sync_all() assert_equal(self.node0.getrawmempool(), []) hex_content = get_contract_hex(self.contract_file) coster = self.node0.getnewaddress() sendtx = self.node0.sendtoaddress(coster, 1000) self.node0.generate(1) self.sync_all() sender_pub = self.node0.validateaddress(coster)['pubkey'] sender_pri = self.node0.dumpprivkey(coster) amount = 100 changeaddress = self.node0.getnewaddress() balance = self.node0.getbalance() signed_tx = self.publish_contract(self.node0, hex_content, coster, sender_pub, sender_pri, amount, changeaddress, send_flag=False) blocks_num = self.node0.getblockcount() self.split_network() txid1 = self.node0.sendrawtransaction(signed_tx['hex']) # generate bb1-bb2 on right side self.node2.generate(2) txid2 = self.node2.sendrawtransaction(signed_tx['hex']) print(txid1, txid2) assert_equal(txid1, txid2) lastblockhash = self.node0.generate(3)[-1] block_hash = self.node2.generate(2)[-1] blocks = self.make_more_work_than(2, 0) gen_blocks = len(blocks) # join network for i in range(4): print("before join:", i, self.nodes[i].getblockcount(), int(self.nodes[i].getchaintipwork(), 16)) print("mempool:", self.nodes[i].getrawmempool()) print("join network") connect_nodes_bi(self.nodes, 1, 2) sync_blocks(self.nodes) for i in range(4): print("mempool:", self.nodes[i].getrawmempool()) # 确认存在分叉存在 tips = self.nodes[1].getchaintips() print(tips) assert_equal(len(tips), self.tips_num + 1) self.tips_num += 1 assert_equal(self.node1.getblockcount(), blocks_num + 4 + gen_blocks) assert_equal(self.node1.getbestblockhash(), blocks[-1] if gen_blocks > 0 else block_hash) # assert assert_equal( self.node0.getbalance() - MINER_REWARD + 100 - self.get_txfee(txid1['txid']) + self.get_txfee(sendtx), balance) assert_equal(self.node2.getbalanceof(txid1['contractaddress']), 100) # listsinceblock(lastblockhash) should now include txid1 in transactions # as well as in removed lsbres = self.node0.listsinceblock(lastblockhash) assert any(tx['txid'] == txid1['txid'] for tx in lsbres['transactions']) assert any(tx['txid'] == txid1['txid'] for tx in lsbres['removed']) # find transaction and ensure confirmations is valid for tx in lsbres['transactions']: if tx['txid'] == txid1['txid']: assert_equal(tx['confirmations'], 2 + gen_blocks) # the same check for the removed array; confirmations should STILL be 2 for tx in lsbres['removed']: if tx['txid'] == txid1['txid']: assert_equal(tx['confirmations'], 2 + gen_blocks)
def setup_network(self, split=False): self.add_nodes(self.num_nodes, extra_args=self.extra_args) self.start_nodes() connect_nodes_bi(self.nodes, 0, 1)
def setup_network(self): super().setup_network() connect_nodes_bi(self.nodes, 0, 2)
def run_test(self): # NLAST_POW_BLOCK = 250 - so mine 125 blocks each node (25 consecutive blocks for 5 times) NMATURITY = 100 self.log.info("Mining 250 blocks (125 with node 0 and 125 with node 1)...") for i in range(5): self.generateBatchBlocks(0, 25) sync_blocks(self.nodes) self.generateBatchBlocks(1, 25) sync_blocks(self.nodes) sync_mempools(self.nodes) # Check balances balance0 = 250.0 * (125 - 50) balance1 = 250.0 * (125 - 50) # Last two 25-blocks bursts (for each node) are not mature: NMATURITY = 2 * (2 * 25) immature_balance0 = 250.0 * 50 immature_balance1 = 250.0 * 50 w_info = self.nodes[0].getwalletinfo() assert_equal(w_info["balance"], balance0) assert_equal(w_info["immature_balance"], immature_balance0) self.log.info("Balance for node 0 checks out: %f [%f]" % (balance0, immature_balance0)) w_info = self.nodes[1].getwalletinfo() assert_equal(w_info["balance"], balance1) assert_equal(w_info["immature_balance"], immature_balance1) self.log.info("Balance for node 1 checks out: %f [%f]" % (balance1, immature_balance1)) initial_balance = balance0 initial_immature_balance = immature_balance0 initial_unspent = self.nodes[0].listunspent() # PoS start reached (block 250) - disconnect nodes self.nodes[0].disconnectnode(urllib.parse.urlparse(self.nodes[1].url).hostname + ":" + str(p2p_port(1))) self.nodes[1].disconnectnode(urllib.parse.urlparse(self.nodes[0].url).hostname + ":" + str(p2p_port(0))) self.log.info("Nodes disconnected") # Stake one block with node-0 and save the stake input self.log.info("Staking 1 block with node 0...") self.nodes[0].generate(1) last_block = self.nodes[0].getblock(self.nodes[0].getbestblockhash()) assert(len(last_block["tx"]) > 1) # a PoS block has at least two txes coinstake_txid = last_block["tx"][1] coinstake_tx = self.nodes[0].getrawtransaction(coinstake_txid, True) assert(coinstake_tx["vout"][0]["scriptPubKey"]["hex"] == "") # first output of coinstake is empty stakeinput = coinstake_tx["vin"][0] # The stake input was unspent 1 block ago, now it's not res, utxo = self.findUtxoInList(stakeinput["txid"], stakeinput["vout"], initial_unspent) assert (res and utxo["spendable"]) res, utxo = self.findUtxoInList(stakeinput["txid"], stakeinput["vout"], self.nodes[0].listunspent()) assert (not res or not utxo["spendable"]) self.log.info("Coinstake input %s...%s-%d is no longer spendable." % ( stakeinput["txid"][:9], stakeinput["txid"][-4:], stakeinput["vout"])) # Stake 10 more blocks with node-0 and check balances self.log.info("Staking 10 more blocks with node 0...") self.generateBatchBlocks(0, 10) balance0 = initial_balance + 0 # mined blocks matured (250*11) - staked blocks inputs (250*11) immature_balance0 += 250 * 11 # -mined blocks matured (250*11) + staked blocks (500*11) w_info = self.nodes[0].getwalletinfo() assert_equal(w_info["balance"], balance0) assert_equal(w_info["immature_balance"], immature_balance0) self.log.info("Balance for node 0 checks out: %f [%f]" % (balance0, immature_balance0)) # verify that the stakeinput can't be spent rawtx_unsigned = self.nodes[0].createrawtransaction( [{"txid": str(stakeinput["txid"]), "vout": int(stakeinput["vout"])}], {"xxncEuJK27ygNh7imNfaX8JV6ZQUnoBqzN": 249.99}) rawtx = self.nodes[0].signrawtransaction(rawtx_unsigned) assert(rawtx["complete"]) assert_raises_rpc_error(-25, "Missing inputs",self.nodes[0].sendrawtransaction, rawtx["hex"]) # Stake 12 blocks with node-1 self.log.info("Staking 12 blocks with node 1...") self.generateBatchBlocks(1, 12) balance1 -= 250 * 12 # 0 - staked blocks inputs (250*12) immature_balance1 += 500 * 12 # + staked blocks (500 * 12) w_info = self.nodes[1].getwalletinfo() assert_equal(w_info["balance"], balance1) assert_equal(w_info["immature_balance"], immature_balance1) self.log.info("Balance for node 1 checks out: %f [%f]" % (balance1, immature_balance1)) new_best_hash = self.nodes[1].getbestblockhash() # re-connect and sync nodes and check that node-0 gets on the other chain self.log.info("Connecting and syncing nodes...") connect_nodes_bi(self.nodes, 0, 1) sync_blocks(self.nodes) assert_equal(self.nodes[0].getbestblockhash(), new_best_hash) # check balance of node-0 balance0 = initial_balance + 250 * 12 # + mined blocks matured (250*12) immature_balance0 = initial_immature_balance - 250 * 12 # - mined blocks matured (250*12) w_info = self.nodes[0].getwalletinfo() assert_equal(w_info["balance"], balance0) # <--- !!! THIS FAILS before PR #1043 assert_equal(w_info["immature_balance"], immature_balance0) self.log.info("Balance for node 0 checks out: %f [%f]" % (balance0, immature_balance0)) # check that NOW the original stakeinput is present and spendable res, utxo = self.findUtxoInList(stakeinput["txid"], stakeinput["vout"], self.nodes[0].listunspent()) assert (res and utxo["spendable"]) # <--- !!! THIS FAILS before PR #1043 self.log.info("Coinstake input %s...%s-%d is spendable again." % ( stakeinput["txid"][:9], stakeinput["txid"][-4:], stakeinput["vout"])) self.nodes[0].sendrawtransaction(rawtx["hex"]) self.nodes[1].generate(1) sync_blocks(self.nodes) res, utxo = self.findUtxoInList(stakeinput["txid"], stakeinput["vout"], self.nodes[0].listunspent()) assert (not res or not utxo["spendable"])
def run_test (self): tmpdir = self.options.tmpdir # Make sure can't switch off usehd after wallet creation self.stop_node(1) self.assert_start_raises_init_error(1, ['-usehd=0'], 'already existing HD wallet') self.start_node(1) connect_nodes_bi(self.nodes, 0, 1) # Make sure we use hd, keep masterkeyid masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] assert_equal(masterkeyid, self.nodes[1].getwalletinfo()['hdmasterkeyid']) assert_equal(len(masterkeyid), 40) # create an internal key change_addr = self.nodes[1].getrawchangeaddress() change_addrV= self.nodes[1].validateaddress(change_addr) assert_equal(change_addrV["hdkeypath"], "m/0'/1'/0'") #first internal child key # Import a non-HD private key in the HD wallet non_hd_add = self.nodes[0].getnewaddress() self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add)) # This should be enough to keep the master key and the non-HD key self.nodes[1].backupwallet(tmpdir + "/hd.bak") #self.nodes[1].dumpwallet(tmpdir + "/hd.dump") # Derive some HD addresses and remember the last # Also send funds to each add self.nodes[0].generate(101) hd_add = None num_hd_adds = 300 for i in range(num_hd_adds): hd_add = self.nodes[1].getnewaddress() hd_info = self.nodes[1].validateaddress(hd_add) assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i)+"'") assert_equal(hd_info["hdseedid"], masterkeyid) self.nodes[0].sendtoaddress(hd_add, 1) self.nodes[0].generate(1) self.nodes[0].sendtoaddress(non_hd_add, 1) self.nodes[0].generate(1) # create an internal key (again) change_addr = self.nodes[1].getrawchangeaddress() change_addrV= self.nodes[1].validateaddress(change_addr) assert_equal(change_addrV["hdkeypath"], "m/0'/1'/1'") #second internal child key self.sync_all() assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1) self.log.info("Restore backup ...") self.stop_node(1) # we need to delete the complete regtest directory # otherwise node1 would auto-recover all funds in flag the keypool keys as used shutil.rmtree(os.path.join(tmpdir, "node1/regtest/blocks")) shutil.rmtree(os.path.join(tmpdir, "node1/regtest/chainstate")) shutil.copyfile(os.path.join(tmpdir, "hd.bak"), os.path.join(tmpdir, "node1/regtest/wallet.dat")) self.start_node(1) # Assert that derivation is deterministic hd_add_2 = None for _ in range(num_hd_adds): hd_add_2 = self.nodes[1].getnewaddress() hd_info_2 = self.nodes[1].validateaddress(hd_add_2) assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(_)+"'") assert_equal(hd_info_2["hdseedid"], masterkeyid) assert_equal(hd_add, hd_add_2) connect_nodes_bi(self.nodes, 0, 1) self.sync_all() # Needs rescan self.stop_node(1) self.start_node(1, extra_args=self.extra_args[1] + ['-rescan']) assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1) # Try a RPC based rescan self.stop_node(1) shutil.rmtree(os.path.join(tmpdir, "node1/regtest/blocks")) shutil.rmtree(os.path.join(tmpdir, "node1/regtest/chainstate")) shutil.copyfile(os.path.join(tmpdir, "hd.bak"), os.path.join(tmpdir, "node1/regtest/wallet.dat")) self.start_node(1, extra_args=self.extra_args[1]) connect_nodes_bi(self.nodes, 0, 1) self.sync_all() out = self.nodes[1].rescanblockchain(0, 1) assert_equal(out['start_height'], 0) assert_equal(out['stop_height'], 1) out = self.nodes[1].rescanblockchain() assert_equal(out['start_height'], 0) assert_equal(out['stop_height'], self.nodes[1].getblockcount()) assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1) # send a tx and make sure its using the internal chain for the changeoutput txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) outs = self.nodes[1].decoderawtransaction(self.nodes[1].gettransaction(txid)['hex'])['vout'] keypath = "" for out in outs: if out['value'] != 1: keypath = self.nodes[1].validateaddress(out['scriptPubKey']['addresses'][0])['hdkeypath'] assert_equal(keypath[0:7], "m/0'/1'")
def run_test(self): pp = pprint.PrettyPrinter(indent=4) self.num_nodes = 4 self.start_nodes() connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 2, 3) connect_nodes_bi(self.nodes, 3, 0) print "Announce nodes" self.mns = [ Mn(self.nodes[i], "node" + str(i)) for i in range(self.num_nodes) ] for i in range(self.num_nodes): self.announce_mn(i) self.sync_all() self.nodes[0].generate(1) self.sync_all() for i in range(self.num_nodes): assert_equal(self.dump_mn(i)['status'], "announced") print "Nodes announced, restarting nodes (node #3 disconnected)" self.stop_nodes() self.num_nodes = 3 self.start_nodes([["-masternode_operator=" + self.mns[i].operator] for i in range(self.num_nodes)]) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 2, 0) # Generate blocks for activation height self.nodes[0].generate(9) sync_blocks([self.nodes[0], self.nodes[1]]) sync_blocks([self.nodes[0], self.nodes[2]]) time.sleep(4) # Autoactivation should happen here self.nodes[0].generate(1) sync_blocks([self.nodes[0], self.nodes[1]]) sync_blocks([self.nodes[0], self.nodes[1]]) time.sleep(4) for i in range(self.num_nodes): assert_equal(self.dump_mn(i)['status'], "activated") print "Nodes activated. Waiting for node #3 became outdated (30 sec)" time.sleep(30) # Here, nodes should deside to kick off node #3 self.nodes[0].generate(1) time.sleep(4) print "Here should be autovoting" self.nodes[0].generate(1) time.sleep(4) # pp.pprint(self.nodes[0].mn_list([], True)) print "Waiting for autofinalize" i = 0 while i < 10 and self.nodes[0].mn_list([self.mns[3].id ])[0]['status'] == "announced": self.nodes[0].generate(1) time.sleep(1) i = i + 1 print i assert_equal(self.nodes[0].mn_list([self.mns[3].id])[0]['status'], "announced, dismissed") # pp.pprint(self.nodes[0].mn_list([], True)) print "Done"
def setup_network(self): self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.node_args) self.is_network_split = False connect_nodes_bi(self.nodes, 0, 1)
def setup_network(self, split=False): # Setup nodes and connect them self.nodes = self.setup_nodes() connect_nodes_bi(self.nodes, 0, 1) self.sync_all()
def run_test(self): # Check that there's no UTXO on none of the nodes assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("Mining blocks...") self.nodes[0].generate(1) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 50) assert_equal(walletinfo['balance'], 0) self.sync_all([self.nodes[0:3]]) self.nodes[1].generate(101) self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 50) assert_equal(self.nodes[1].getbalance(), 50) assert_equal(self.nodes[2].getbalance(), 0) # Check that only first and second nodes have UTXOs utxos = self.nodes[0].listunspent() assert_equal(len(utxos), 1) assert_equal(len(self.nodes[1].listunspent()), 1) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("test gettxout") confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"] # First, outputs that are unspent both in the chain and in the # mempool should appear with or without include_mempool txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=False) assert_equal(txout['value'], 50) txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=True) assert_equal(txout['value'], 50) # Send 21 BTC from 0 to 2 using sendtoaddress call. self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) self.log.info("test gettxout (second part)") # utxo spent in mempool should be visible if you exclude mempool # but invisible if you include mempool txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False) assert_equal(txout['value'], 50) txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True) assert txout is None # new utxo from mempool should be invisible if you exclude mempool # but visible if you include mempool txout = self.nodes[0].gettxout(mempool_txid, 0, False) assert txout is None txout1 = self.nodes[0].gettxout(mempool_txid, 0, True) txout2 = self.nodes[0].gettxout(mempool_txid, 1, True) # note the mempool tx will have randomly assigned indices # but 10 will go to node2 and the rest will go to node0 balance = self.nodes[0].getbalance() assert_equal(set([txout1['value'], txout2['value']]), set([10, balance])) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 0) # Have node0 mine a block, thus it will collect its own fee. self.nodes[0].generate(1) self.sync_all([self.nodes[0:3]]) # Exercise locking of unspent outputs unspent_0 = self.nodes[2].listunspent()[0] unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} assert_raises_rpc_error(-8, "Invalid parameter, expected locked output", self.nodes[2].lockunspent, True, [unspent_0]) self.nodes[2].lockunspent(False, [unspent_0]) assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0]) assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) assert_equal([unspent_0], self.nodes[2].listlockunspent()) self.nodes[2].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[2].listlockunspent()), 0) assert_raises_rpc_error(-8, "txid must be of length 64 (not 34, for '0000000000000000000000000000000000')", self.nodes[2].lockunspent, False, [{"txid": "0000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[2].lockunspent, False, [{"txid": "ZZZ0000000000000000000000000000000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "Invalid parameter, unknown transaction", self.nodes[2].lockunspent, False, [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "Invalid parameter, vout index out of bounds", self.nodes[2].lockunspent, False, [{"txid": unspent_0["txid"], "vout": 999}]) # An output should be unlocked when spent unspent_0 = self.nodes[1].listunspent()[0] self.nodes[1].lockunspent(False, [unspent_0]) tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 }) tx = self.nodes[1].fundrawtransaction(tx)['hex'] tx = self.nodes[1].signrawtransactionwithwallet(tx)["hex"] self.nodes[1].sendrawtransaction(tx) assert_equal(len(self.nodes[1].listlockunspent()), 0) # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) self.sync_all([self.nodes[0:3]]) # node0 should end up with 100 btc in block rewards plus fees, but # minus the 21 plus fees sent to node2 assert_equal(self.nodes[0].getbalance(), 100 - 21) assert_equal(self.nodes[2].getbalance(), 21) # Node0 should have two unspent outputs. # Create a couple of transactions to send them to node2, submit them through # node1, and make sure both node0 and node2 pick them up properly: node0utxos = self.nodes[0].listunspent(1) assert_equal(len(node0utxos), 2) # create both transactions txns_to_send = [] for utxo in node0utxos: inputs = [] outputs = {} inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) outputs[self.nodes[2].getnewaddress()] = utxo["amount"] - 3 raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) txns_to_send.append(self.nodes[0].signrawtransactionwithwallet(raw_tx)) # Have node 1 (miner) send the transactions self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], True) self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True) # Have node1 mine a block to confirm transactions: self.nodes[1].generate(1) self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 94) # Verify that a spent output cannot be locked anymore spent_0 = {"txid": node0utxos[0]["txid"], "vout": node0utxos[0]["vout"]} assert_raises_rpc_error(-8, "Invalid parameter, expected unspent output", self.nodes[0].lockunspent, False, [spent_0]) # Send 10 BTC normal address = self.nodes[0].getnewaddress("test") fee_per_byte = Decimal('0.001') / 1000 self.nodes[2].settxfee(fee_per_byte * 1000) txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(self.nodes[0].getbalance(), Decimal('10')) # Send 10 BTC with subtract fee from amount txid = self.nodes[2].sendtoaddress(address, 10, "", "", True) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) # Sendmany 10 BTC txid = self.nodes[2].sendmany('', {address: 10}, 0, "", []) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_0_bal += Decimal('10') node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(self.nodes[0].getbalance(), node_0_bal) # Sendmany 10 BTC with subtract fee from amount txid = self.nodes[2].sendmany('', {address: 10}, 0, "", [address]) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) # Test ResendWalletTransactions: # Create a couple of transactions, then start up a fourth # node (nodes[3]) and ask nodes[0] to rebroadcast. # EXPECT: nodes[3] should have those transactions in its mempool. txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) sync_mempools(self.nodes[0:2]) self.start_node(3) connect_nodes_bi(self.nodes, 0, 3) sync_blocks(self.nodes) relayed = self.nodes[0].resendwallettransactions() assert_equal(set(relayed), {txid1, txid2}) sync_mempools(self.nodes) assert txid1 in self.nodes[3].getrawmempool() # check if we can list zero value tx as available coins # 1. create raw_tx # 2. hex-changed one output to 0.0 # 3. sign and send # 4. check if recipient (node0) can list the zero value tx usp = self.nodes[1].listunspent(query_options={'minimumAmount': '49.998'})[0] inputs = [{"txid": usp['txid'], "vout": usp['vout']}] outputs = {self.nodes[1].getnewaddress(): 49.998, self.nodes[0].getnewaddress(): 11.11} raw_tx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") # replace 11.11 with 0.0 (int32) signed_raw_tx = self.nodes[1].signrawtransactionwithwallet(raw_tx) decoded_raw_tx = self.nodes[1].decoderawtransaction(signed_raw_tx['hex']) zero_value_txid = decoded_raw_tx['txid'] self.nodes[1].sendrawtransaction(signed_raw_tx['hex']) self.sync_all() self.nodes[1].generate(1) # mine a block self.sync_all() unspent_txs = self.nodes[0].listunspent() # zero value tx must be in listunspents output found = False for uTx in unspent_txs: if uTx['txid'] == zero_value_txid: found = True assert_equal(uTx['amount'], Decimal('0')) assert found # do some -walletbroadcast tests self.stop_nodes() self.start_node(0, ["-walletbroadcast=0"]) self.start_node(1, ["-walletbroadcast=0"]) self.start_node(2, ["-walletbroadcast=0"]) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) self.sync_all([self.nodes[0:3]]) txid_not_broadcast = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast) self.nodes[1].generate(1) # mine a block, tx should not be in there self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[2].getbalance(), node_2_bal) # should not be changed because tx was not broadcasted # now broadcast from another node, mine a block, sync, and check the balance self.nodes[1].sendrawtransaction(tx_obj_not_broadcast['hex']) self.nodes[1].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal += 2 tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast) assert_equal(self.nodes[2].getbalance(), node_2_bal) # create another tx self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) # restart the nodes with -walletbroadcast=1 self.stop_nodes() self.start_node(0) self.start_node(1) self.start_node(2) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) sync_blocks(self.nodes[0:3]) self.nodes[0].generate(1) sync_blocks(self.nodes[0:3]) node_2_bal += 2 # tx should be added to balance because after restarting the nodes tx should be broadcast assert_equal(self.nodes[2].getbalance(), node_2_bal) # send a tx with value in a string (PR#6380 +) txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-2')) txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-0.0001')) # check if JSON parser can handle scientific notation in strings txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1e-4") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-0.0001')) # General checks for errors from incorrect inputs # This will raise an exception because the amount type is wrong assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4") # This will raise an exception since generate does not accept a string assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2") # This will raise an exception for the invalid private key format assert_raises_rpc_error(-5, "Invalid private key encoding", self.nodes[0].importprivkey, "invalid") # This will raise an exception for importing an address with the PS2H flag temp_address = self.nodes[1].getnewaddress() assert_raises_rpc_error(-5, "Cannot use the p2sh flag with an address - use a script instead", self.nodes[0].importaddress, temp_address, "label", False, True) # This will raise an exception for attempting to dump the private key of an address you do not own assert_raises_rpc_error(-3, "Address does not refer to a key", self.nodes[0].dumpprivkey, temp_address) # This will raise an exception for attempting to get the private key of an invalid Bitcoin address assert_raises_rpc_error(-5, "Invalid Goldcoin address", self.nodes[0].dumpprivkey, "invalid") # This will raise an exception for attempting to set a label for an invalid Bitcoin address assert_raises_rpc_error(-5, "Invalid Goldcoin address", self.nodes[0].setlabel, "invalid address", "label") # This will raise an exception for importing an invalid address assert_raises_rpc_error(-5, "Invalid Goldcoin address or script", self.nodes[0].importaddress, "invalid") # This will raise an exception for attempting to import a pubkey that isn't in hex assert_raises_rpc_error(-5, "Pubkey must be a hex string", self.nodes[0].importpubkey, "not hex") # This will raise an exception for importing an invalid pubkey assert_raises_rpc_error(-5, "Pubkey is not a valid public key", self.nodes[0].importpubkey, "5361746f736869204e616b616d6f746f") # Import address and private key to check correct behavior of spendable unspents # 1. Send some coins to generate new UTXO address_to_import = self.nodes[2].getnewaddress() txid = self.nodes[0].sendtoaddress(address_to_import, 1) self.nodes[0].generate(1) self.sync_all([self.nodes[0:3]]) # 2. Import address from node2 to node1 self.nodes[1].importaddress(address_to_import) # 3. Validate that the imported address is watch-only on node1 assert self.nodes[1].getaddressinfo(address_to_import)["iswatchonly"] # 4. Check that the unspents after import are not spendable assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": False}) # 5. Import private key of the previously imported address on node1 priv_key = self.nodes[2].dumpprivkey(address_to_import) self.nodes[1].importprivkey(priv_key) # 6. Check that the unspents are now spendable on node1 assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": True}) # Mine a block from node0 to an address from node1 coinbase_addr = self.nodes[1].getnewaddress() block_hash = self.nodes[0].generatetoaddress(1, coinbase_addr)[0] coinbase_txid = self.nodes[0].getblock(block_hash)['tx'][0] self.sync_all([self.nodes[0:3]]) # Check that the txid and balance is found by node1 self.nodes[1].gettransaction(coinbase_txid) # check if wallet or blockchain maintenance changes the balance self.sync_all([self.nodes[0:3]]) blocks = self.nodes[0].generate(2) self.sync_all([self.nodes[0:3]]) balance_nodes = [self.nodes[i].getbalance() for i in range(3)] block_count = self.nodes[0].getblockcount() # Check modes: # - True: unicode escaped as \u.... # - False: unicode directly as UTF-8 for mode in [True, False]: self.nodes[0].rpc.ensure_ascii = mode # unicode check: Basic Multilingual Plane, Supplementary Plane respectively for label in [u'ббаБаА', u'№ Ё']: addr = self.nodes[0].getnewaddress() self.nodes[0].setlabel(addr, label) assert_equal(self.nodes[0].getaddressinfo(addr)['label'], label) assert label in self.nodes[0].listlabels() self.nodes[0].rpc.ensure_ascii = True # restore to default # maintenance tests maintenance = [ '-rescan', '-reindex', '-zapwallettxes=1', '-zapwallettxes=2', # disabled until issue is fixed: https://github.com/bitcoin/bitcoin/issues/7463 # '-salvagewallet', ] chainlimit = 6 for m in maintenance: self.log.info("check " + m) self.stop_nodes() # set lower ancestor limit for later self.start_node(0, [m, "-limitancestorcount=" + str(chainlimit)]) self.start_node(1, [m, "-limitancestorcount=" + str(chainlimit)]) self.start_node(2, [m, "-limitancestorcount=" + str(chainlimit)]) if m == '-reindex': # reindex will leave rpc warm up "early"; Wait for it to finish wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)]) assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) # Exercise listsinceblock with the last two blocks coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) assert_equal(coinbase_tx_1["lastblock"], blocks[1]) assert_equal(len(coinbase_tx_1["transactions"]), 1) assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0) # ==Check that wallet prefers to use coins that don't exceed mempool limits ===== # Get all non-zero utxos together chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()] singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True) self.nodes[0].generate(1) node0_balance = self.nodes[0].getbalance() # Split into two chains rawtx = self.nodes[0].createrawtransaction([{"txid": singletxid, "vout": 0}], {chain_addrs[0]: node0_balance / 2 - Decimal('0.01'), chain_addrs[1]: node0_balance / 2 - Decimal('0.01')}) signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx) singletxid = self.nodes[0].sendrawtransaction(signedtx["hex"]) self.nodes[0].generate(1) # Make a long chain of unconfirmed payments without hitting mempool limit # Each tx we make leaves only one output of change on a chain 1 longer # Since the amount to send is always much less than the outputs, we only ever need one output # So we should be able to generate exactly chainlimit txs for each original output sending_addr = self.nodes[1].getnewaddress() txid_list = [] for i in range(chainlimit * 2): txid_list.append(self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))) assert_equal(self.nodes[0].getmempoolinfo()['size'], chainlimit * 2) assert_equal(len(txid_list), chainlimit * 2) # Without walletrejectlongchains, we will still generate a txid # The tx will be stored in the wallet but not accepted to the mempool extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001')) assert extra_txid not in self.nodes[0].getrawmempool() assert extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()] self.nodes[0].abandontransaction(extra_txid) total_txs = len(self.nodes[0].listtransactions("*", 99999)) # Try with walletrejectlongchains # Double chain limit but require combining inputs, so we pass SelectCoinsMinConf self.stop_node(0) self.start_node(0, extra_args=["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)]) # wait for loadmempool timeout = 10 while (timeout > 0 and len(self.nodes[0].getrawmempool()) < chainlimit * 2): time.sleep(0.5) timeout -= 0.5 assert_equal(len(self.nodes[0].getrawmempool()), chainlimit * 2) node0_balance = self.nodes[0].getbalance() # With walletrejectlongchains we will not create the tx and store it in our wallet. assert_raises_rpc_error(-4, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01')) # Verify nothing new in wallet assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999))) # Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py assert_raises_rpc_error(-5, "Invalid address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac") assert not address_info["ismine"] assert not address_info["iswatchonly"] assert not address_info["isscript"] assert not address_info["ischange"] # Test getaddressinfo 'ischange' field on change address. self.nodes[0].generate(1) destination = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(destination, 0.123) tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex']) output_addresses = [vout['scriptPubKey']['addresses'][0] for vout in tx["vout"]] assert len(output_addresses) > 1 for address in output_addresses: ischange = self.nodes[0].getaddressinfo(address)['ischange'] assert_equal(ischange, address != destination) if ischange: change = address self.nodes[0].setlabel(change, 'foobar') assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False)
def run_test(self): self.log.info("test -blocknotify") block_count = 10 blocks = self.nodes[1].generate(block_count) # wait at most 10 seconds for expected file size before reading the content wait_until(lambda: os.path.isfile(self.block_filename) and os.stat( self.block_filename).st_size >= (block_count * 65), timeout=10) # file content should equal the generated blocks hashes with open(self.block_filename, 'r') as f: assert_equal(sorted(blocks), sorted(f.read().splitlines())) self.log.info("test -walletnotify") # wait at most 10 seconds for expected file size before reading the content wait_until(lambda: os.path.isfile(self.tx_filename) and os.stat( self.tx_filename).st_size >= (block_count * 65), timeout=10) # file content should equal the generated transaction hashes txids_rpc = list( map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) with open(self.tx_filename, 'r') as f: assert_equal(sorted(txids_rpc), sorted(f.read().splitlines())) os.remove(self.tx_filename) self.log.info("test -walletnotify after rescan") # restart node to rescan to force wallet notifications self.restart_node(1) connect_nodes_bi(self.nodes, 0, 1) wait_until(lambda: os.path.isfile(self.tx_filename) and os.stat( self.tx_filename).st_size >= (block_count * 65), timeout=10) # file content should equal the generated transaction hashes txids_rpc = list( map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) with open(self.tx_filename, 'r') as f: assert_equal(sorted(txids_rpc), sorted(f.read().splitlines())) # Mine another 41 up-version blocks. -alertnotify should trigger on the 51st. self.log.info("test -alertnotify") self.nodes[1].generate(51) self.sync_all() # Give kabberryd 10 seconds to write the alert notification wait_until(lambda: os.path.isfile(self.alert_filename) and os.path. getsize(self.alert_filename), timeout=10) with open(self.alert_filename, 'r', encoding='utf8') as f: alert_text = f.read() # Mine more up-version blocks, should not get more alerts: self.nodes[1].generate(2) self.sync_all() with open(self.alert_filename, 'r', encoding='utf8') as f: alert_text2 = f.read() self.log.info( "-alertnotify should not continue notifying for more unknown version blocks" ) assert_equal(alert_text, alert_text2)
def run_test(self): assert_equal(len(self.nodes[0].listtokens()), 1) # only one token == DFI print("Generating initial chain...") self.nodes[0].generate(100) owner = self.nodes[0].getnewaddress("", "legacy") self.nodes[0].generate(1) self.sync_blocks() # START #======================== print("Generating accounts...") self.generate_accounts() assert_equal(len(self.accounts), self.COUNT_ACCOUNT) print("Generate " + str(self.COUNT_ACCOUNT) + " accounts") print("Generating pools...") self.create_pools(owner) assert_equal(len(self.nodes[0].listtokens({}, False)), (3 * self.COUNT_POOLS) + 1) assert_equal(len(self.nodes[0].listpoolpairs({}, False)), self.COUNT_POOLS) print("Generate " + str(self.COUNT_POOLS) + " pools and " + str(self.COUNT_POOLS * 2) + " tokens") print("Minting tokens...") mint_amount = self.mint_tokens(owner) assert_equal(len(self.nodes[0].getaccount(owner, {}, True)), self.COUNT_POOLS * 2) print("Minted " + mint_amount + " of every coin") print("Sending tokens...") self.send_tokens(owner) for account in self.accounts: assert_equal(self.nodes[0].getaccount(account, {}, True)[self.get_id_token(self.tokens[0])], self.AMOUNT_TOKEN) print("Tokens sent out") print("Adding liquidity...") self.add_pools_liquidity(owner) for pool in self.pools: idPool = list(self.nodes[0].getpoolpair(pool, True).keys())[0] idTokenA = self.nodes[0].getpoolpair(pool, True)[idPool]['idTokenA'] idTokenB = self.nodes[0].getpoolpair(pool, True)[idPool]['idTokenB'] reserveA = self.nodes[0].getpoolpair(pool, True)[idPool]['reserveA'] reserveB = self.nodes[0].getpoolpair(pool, True)[idPool]['reserveB'] assert_equal(self.liquidity[idTokenA], reserveA) assert_equal(self.liquidity[idTokenB], reserveB) reserveAB = self.nodes[0].getpoolpair(pool, True)[idPool]['reserveA/reserveB'] reserveBA = self.nodes[0].getpoolpair(pool, True)[idPool]['reserveB/reserveA'] resAB = int((self.liquidity[idTokenA] * self.DECIMAL) / (self.liquidity[idTokenB] * self.DECIMAL) * self.DECIMAL) resBA = int((self.liquidity[idTokenB] * self.DECIMAL) / (self.liquidity[idTokenA] * self.DECIMAL) * self.DECIMAL) assert_equal(reserveAB * self.DECIMAL, resAB) assert_equal(reserveBA * self.DECIMAL, resBA) print("Liquidity added") print("Setting governance variables...") obj = {} for i in range(self.COUNT_POOLS): obj[str(i + 1)] = 1 / self.COUNT_POOLS self.nodes[0].setgov({ "LP_SPLITS": obj }) self.nodes[0].setgov({ "LP_DAILY_DFI_REWARD": self.LP_DAILY_DFI_REWARD }) self.nodes[0].generate(1) self.sync_blocks() g1 = self.nodes[0].getgov("LP_SPLITS") for i in range(self.COUNT_POOLS): assert_equal(g1['LP_SPLITS'][str(i + 1)], 1 / self.COUNT_POOLS) g2 = self.nodes[0].getgov("LP_DAILY_DFI_REWARD") assert(g2 == {'LP_DAILY_DFI_REWARD': Decimal(self.LP_DAILY_DFI_REWARD)} ) print("Set governance variables") # Stop node #2 for future revert self.stop_node(2) print("Swapping tokens...") start_time = time.time() nodes = self.nodes[0:2] self.poolswap(nodes) end_time = time.time() - start_time print("Tokens exchanged") print("Elapsed time: {} s".format(end_time)) # REVERTING: #======================== print ("Reverting...") self.start_node(2) self.nodes[2].generate(5) connect_nodes_bi(self.nodes, 1, 2) self.sync_blocks() # Wipe mempool self.nodes[0].clearmempool() self.nodes[1].clearmempool() self.nodes[2].clearmempool() assert(self.nodes[0].getblockcount() == 120) # eunos self.LP_DAILY_DFI_REWARD = self.nodes[0].getgov("LP_DAILY_DFI_REWARD")['LP_DAILY_DFI_REWARD'] assert_equal(self.LP_DAILY_DFI_REWARD, Decimal('14843.90592000')) # 144 blocks a day times 103.08268000 print("Swapping tokens after eunos height...") self.poolswap(self.nodes)
def setup_network(self): self.node_args[1].append('-backupdir=' + self.options.tmpdir) self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.node_args) self.is_network_split = False connect_nodes_bi(self.nodes, 0, 1)
def setup_network(self, split=False): self.nodes = start_nodes(2, self.options.tmpdir) connect_nodes_bi(self.nodes, 0, 1) self.is_network_split = False self.sync_all()
def run_test(self): self.log.info("Ensure submitblock can in principle reorg to a competing chain") self.nodes[0].generate(1) assert_equal(self.nodes[0].getblockcount(), 1) hashZ = self.nodes[1].generate(2)[-1] assert_equal(self.nodes[1].getblockcount(), 2) node_sync_via_rpc(self.nodes[0:3]) assert_equal(self.nodes[0].getbestblockhash(), hashZ) self.log.info("Mine blocks A-B-C on Node 0") hashC = self.nodes[0].generate(3)[-1] assert_equal(self.nodes[0].getblockcount(), 5) self.log.info("Mine competing blocks E-F-G on Node 1") hashG = self.nodes[1].generate(3)[-1] assert_equal(self.nodes[1].getblockcount(), 5) assert(hashC != hashG) self.log.info("Connect nodes and check no reorg occurs") # Submit competing blocks via RPC so any reorg should occur before we proceed (no way to wait on inaction for p2p sync) node_sync_via_rpc(self.nodes[0:2]) connect_nodes_bi(self.nodes,0,1) assert_equal(self.nodes[0].getbestblockhash(), hashC) assert_equal(self.nodes[1].getbestblockhash(), hashG) self.log.info("Make Node0 prefer block G") self.nodes[0].preciousblock(hashG) assert_equal(self.nodes[0].getbestblockhash(), hashG) self.log.info("Make Node0 prefer block C again") self.nodes[0].preciousblock(hashC) assert_equal(self.nodes[0].getbestblockhash(), hashC) self.log.info("Make Node1 prefer block C") self.nodes[1].preciousblock(hashC) sync_chain(self.nodes[0:2]) # wait because node 1 may not have downloaded hashC assert_equal(self.nodes[1].getbestblockhash(), hashC) self.log.info("Make Node1 prefer block G again") self.nodes[1].preciousblock(hashG) assert_equal(self.nodes[1].getbestblockhash(), hashG) self.log.info("Make Node0 prefer block G again") self.nodes[0].preciousblock(hashG) assert_equal(self.nodes[0].getbestblockhash(), hashG) self.log.info("Make Node1 prefer block C again") self.nodes[1].preciousblock(hashC) assert_equal(self.nodes[1].getbestblockhash(), hashC) self.log.info("Mine another block (E-F-G-)H on Node 0 and reorg Node 1") self.nodes[0].generate(1) assert_equal(self.nodes[0].getblockcount(), 6) sync_blocks(self.nodes[0:2]) hashH = self.nodes[0].getbestblockhash() assert_equal(self.nodes[1].getbestblockhash(), hashH) self.log.info("Node1 should not be able to prefer block C anymore") self.nodes[1].preciousblock(hashC) assert_equal(self.nodes[1].getbestblockhash(), hashH) self.log.info("Mine competing blocks I-J-K-L on Node 2") self.nodes[2].generate(4) assert_equal(self.nodes[2].getblockcount(), 6) hashL = self.nodes[2].getbestblockhash() self.log.info("Connect nodes and check no reorg occurs") node_sync_via_rpc(self.nodes[1:3]) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) assert_equal(self.nodes[0].getbestblockhash(), hashH) assert_equal(self.nodes[1].getbestblockhash(), hashH) assert_equal(self.nodes[2].getbestblockhash(), hashL) self.log.info("Make Node1 prefer block L") self.nodes[1].preciousblock(hashL) assert_equal(self.nodes[1].getbestblockhash(), hashL) self.log.info("Make Node2 prefer block H") self.nodes[2].preciousblock(hashH) assert_equal(self.nodes[2].getbestblockhash(), hashH)
def test_callcontract_fork(self, with_send=False, crash_point=1): ''' 调用同一合约,不含send操作与含send操作 ab0[contract_ab] / \ aa1 [cca1] bb1 [ccb1] | | aa2 bb2 | | aa3 bb3 | bb4 | ... :param with_send: :return: ''' self.sync_all() self.node0.generate(2) assert_equal(self.node0.getrawmempool(), []) # make sure mempool empty assert_equal(self.node1.getrawmempool(), []) # make sure mempool empty ct = Contract(self.node1, self.options.tmpdir, debug=False) ct2 = Contract(self.node1, self.options.tmpdir, debug=False) ct2.call_payable(amount=1000) print(ct.publish_txid) self.sync_all() self.node0.generate(2) self.sync_all() blocks_num = self.node1.getblockcount() # split mgc network self.split_network() self.node1.generate(2) # fork self.node3.generate(8) # fork # in group 1 balance = self.node1.getbalance() # tx_ai,tx_a11,tx_a12这3个交易,在合并网络后,应该都会被重新打回内存池中,毕竟是短链 tx_a1 = ct.call_payable(amount=2000)['txid'] tx_a11 = ct.call_contractDataTest(amount=0)['txid'] tx_a12 = ct.call_contractDataTest(amount=0)['txid'] if with_send: tmp_ct = Contract(self.node1, debug=False) print(tmp_ct.publish_txid) tx_a13 = ct.call_callOtherContractTest(ct2.contract_id, 'callOtherContractTest', tmp_ct.contract_id, "contractDataTest", amount=0) print("ct balance:", ct.get_balance()) print(tx_a13) print(tx_a1, tx_a11, tx_a12) self.sync_all([self.nodes[:2], self.nodes[2:]]) last_block_hash = self.node1.generate(2)[-1] assert self.node1.getrawmempool() == [] self.sync_all([self.nodes[:2], self.nodes[2:]]) # in group 2 tx_b1 = ct.call_payable(amount=2000, exec_node=self.node3, sender=self.node3.getnewaddress())['txid'] print(tx_b1) self.sync_all([self.nodes[:2], self.nodes[2:]]) self.node3.generate(2) self.sync_all([self.nodes[:2], self.nodes[2:]]) assert tx_b1 not in self.node3.getrawmempool() tx_b11 = ct.call_contractDataTest(amount=0, exec_node=self.node3)['txid'] print("ct balance:", ct.get_balance(exec_node=self.node3)) if with_send: # 这里有两个crash point,下面代码分别对应不同的CP if crash_point == 1: tx_b12 = ct.call_callOtherContractTest(ct2.contract_id, 'callOtherContractTest', ct.contract_id, "contractDataTest", exec_node=self.node3, amount=0) print("ct balance:", ct.get_balance(exec_node=self.node3)) else: tx_b12 = ct.call_callOtherContractTest(ct2.contract_id, 'callOtherContractTest', ct.contract_id, "contractDataTest", amount=0) ct.call_reentrancyTest() print("ct balance:", ct.get_balance(exec_node=self.node1)) print("ct balance:", ct.get_balance(exec_node=self.node3)) print("tx_b12:", tx_b12.txid) print(tx_b11) block_b16 = self.node3.generate(6)[-1] assert_equal(self.node3.getrawmempool(), []) if with_send and crash_point == 1: assert_equal(self.node1.getrawmempool(), []) elif with_send and crash_point == 2: pass # assert_equal(self.node1.getrawmempool(), [tx_b12.txid]) self.sync_all([self.nodes[:2], self.nodes[2:]]) # join network more_work_blocks = self.make_more_work_than(3, 1) for i in range(4): print("before join:", i, self.nodes[i].getblockcount(), int(self.nodes[i].getchaintipwork(), 16)) print("mempool:", self.nodes[i].getrawmempool()) print("ct balance:", ct.get_balance(exec_node=self.node3)) print("ct balance:", ct.get_balance(exec_node=self.node1)) print("join network") connect_nodes_bi(self.nodes, 1, 2) sync_blocks(self.nodes) print("ct balance:", ct.get_balance(exec_node=self.node1)) print("ct balance:", ct.get_balance(exec_node=self.node3)) for i in range(4): print("mempool:", self.nodes[i].getrawmempool()) if with_send: print( "assert_equal(len(self.node1.getrawmempool()), 5),should {} == 5" .format(len(self.node1.getrawmempool()))) # assert_equal(len(self.node1.getrawmempool()), 5) # 短链的块内交易必须是打回内存池的,否则可能有bug了 else: print( " assert_equal(len(self.node1.getrawmempool()), 3),should {} == 5" .format(len(self.node1.getrawmempool()))) # assert_equal(len(self.node1.getrawmempool()), 3) # 短链的块内交易必须是打回内存池的,否则可能有bug了 assert (balance - MINER_REWARD * 2 - 2000) - self.node1.getbalance() < 100 print("node2 ct get_balance:", ct.get_balance(exec_node=self.node2)) bal = 2000 if with_send and crash_point == 1: bal = 2000 - 20 #应该是2000-10的 assert_equal(self.node1.getbalanceof(ct.contract_id), bal) # 减去合约的send调用 assert_equal(self.node0.getbalanceof(ct.contract_id), bal) # 减去合约的send调用 # assert_equal(ct.call_get('counter', broadcasting=False,amount = 0)['return'][0], 4) # 因为本节点mempool有合约交易,所以应该为4 assert_equal( ct.call_get('counter', broadcasting=False, exec_node=self.node2, amount=0)['return'][0], 2) # 该节点内存池中没有交易哦,所以应该为2 for i in range(4): print("node{} ct2 get_balance:{}".format( i, ct2.get_balance(exec_node=self.nodes[i]))) # assert_equal(self.node0.getbalanceof(ct2.contract_id), 1000 if with_send else 1000) # 减去合约的send调用 # assert_equal(self.node1.getbalanceof(ct2.contract_id), 1000 if with_send else 1000) # 减去合约的send调用 # # assert_equal(self.node2.getbalanceof(ct2.contract_id), 1000 - 10 if with_send else 1000) # 减去合约的send调用 # assert_equal(self.node2.getbalanceof(ct2.contract_id), 1000 - 0 if with_send else 1000) # 减去合约的send调用 for i in range(4): print(i, self.nodes[i].getblockcount(), int(self.nodes[i].getchaintipwork(), 16)) tips = self.nodes[0].getchaintips() print(tips) assert_equal(len(tips), self.tips_num + 1) self.tips_num += 1 assert_equal(self.node2.getblockcount(), blocks_num + 16 + len(more_work_blocks)) assert_equal( self.node2.getbestblockhash(), block_b16 if not more_work_blocks else more_work_blocks[-1]) print(self.node1.gettransaction(tx_a1)) print(self.node1.gettransaction(tx_a11)) # clear node0's and node1's mempool and check balance self.node1.generate(4) sync_blocks(self.nodes) assert_equal(self.node0.getrawmempool(), []) assert_equal(self.node1.getrawmempool(), []) # assert_equal(self.node1.getbalanceof(ct.contract_id), 4000 - 20 if with_send else 4000) bal = 4000 if with_send and crash_point == 1: bal = 4000 - 40 #应该是4000- 20 的 elif with_send and crash_point == 2: bal = 4000 - 20 # assert_equal(self.node1.getbalanceof(ct.contract_id), bal) assert (balance - MINER_REWARD * 2 - 2000) - self.node1.getbalance() < 100 # In bestchain,ensure contract data is correct # for i in range(4): # assert_equal( # ct.call_get('counter', exec_node=self.nodes[i], sender=self.nodes[i].getnewaddress(),amount = 0)['return'][0], 4) # 未完成的用例,下面的有问题,先屏蔽 # ''' # listsinceblock(lastblockhash) should now include txid_a1, as seen from nodes[0] # 这里只有node1节点才成功,换成其他节点时失败的,这不应该 lsbres = self.nodes[1].listsinceblock(last_block_hash) assert any( tx['txid'] == tx_a1 for tx in lsbres['transactions']) # 这里只有node1节点才成功,换成其他节点时失败的,这不应该 # but it should not include 'removed' if include_removed=false lsbres2 = self.nodes[1].listsinceblock(blockhash=last_block_hash, include_removed=False) assert 'removed' not in lsbres2
def run_test(self): self.nodes[0].importaddress(ADDRESS_WATCHONLY) # Check that nodes don't own any UTXOs assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) self.log.info("Check that only node 0 is watching an address") assert 'watchonly' in self.nodes[0].getbalances() assert 'watchonly' not in self.nodes[1].getbalances() self.log.info("Mining blocks ...") self.nodes[0].generate(1) self.sync_all() self.nodes[1].generate(1) self.nodes[1].generatetoaddress(101, ADDRESS_WATCHONLY) self.sync_all() assert_equal(self.nodes[0].getbalances()['mine']['trusted'], 50) assert_equal(self.nodes[0].getwalletinfo()['balance'], 50) assert_equal(self.nodes[1].getbalances()['mine']['trusted'], 50) assert_equal(self.nodes[0].getbalances()['watchonly']['immature'], 5000) assert 'watchonly' not in self.nodes[1].getbalances() assert_equal(self.nodes[0].getbalance(), 50) assert_equal(self.nodes[1].getbalance(), 50) self.log.info("Test getbalance with different arguments") assert_equal(self.nodes[0].getbalance("*"), 50) assert_equal(self.nodes[0].getbalance("*", 1), 50) assert_equal(self.nodes[0].getbalance("*", 1, True), 100) assert_equal(self.nodes[0].getbalance(minconf=1), 50) assert_equal( self.nodes[0].getbalance(minconf=0, include_watchonly=True), 100) assert_equal( self.nodes[1].getbalance(minconf=0, include_watchonly=True), 50) # Send 40 CRT from 0 to 1 and 60 CRT from 1 to 0. txs = create_transactions(self.nodes[0], self.nodes[1].getnewaddress(), 40, [Decimal('0.01')]) self.nodes[0].sendrawtransaction(txs[0]['hex']) self.nodes[1].sendrawtransaction( txs[0]['hex'] ) # sending on both nodes is faster than waiting for propagation self.sync_all() txs = create_transactions( self.nodes[1], self.nodes[0].getnewaddress(), 60, [Decimal('0.01'), Decimal('0.02')]) self.nodes[1].sendrawtransaction(txs[0]['hex']) self.nodes[0].sendrawtransaction( txs[0]['hex'] ) # sending on both nodes is faster than waiting for propagation self.sync_all() # First argument of getbalance must be set to "*" assert_raises_rpc_error( -32, "dummy first argument must be excluded or set to \"*\"", self.nodes[1].getbalance, "") self.log.info( "Test getbalance and getunconfirmedbalance with unconfirmed inputs" ) def test_balances(*, fee_node_1=0): # getbalance without any arguments includes unconfirmed transactions, but not untrusted transactions assert_equal(self.nodes[0].getbalance(), Decimal('9.99')) # change from node 0's send assert_equal(self.nodes[1].getbalance(), Decimal('30') - fee_node_1) # change from node 1's send # Same with minconf=0 assert_equal(self.nodes[0].getbalance(minconf=0), Decimal('9.99')) assert_equal(self.nodes[1].getbalance(minconf=0), Decimal('30') - fee_node_1) # getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago # TODO: fix getbalance tracking of coin spentness depth assert_equal(self.nodes[0].getbalance(minconf=1), Decimal('0')) assert_equal(self.nodes[1].getbalance(minconf=1), Decimal('0')) # getunconfirmedbalance assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('60')) # output of node 1's spend assert_equal( self.nodes[0].getbalances()['mine']['untrusted_pending'], Decimal('60')) assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], Decimal('60')) assert_equal( self.nodes[1].getunconfirmedbalance(), Decimal('0') ) # Doesn't include output of node 0's send since it was spent assert_equal( self.nodes[1].getbalances()['mine']['untrusted_pending'], Decimal('0')) assert_equal(self.nodes[1].getwalletinfo()["unconfirmed_balance"], Decimal('0')) test_balances(fee_node_1=Decimal('0.01')) # Node 1 bumps the transaction fee and resends self.nodes[1].sendrawtransaction(txs[1]['hex']) self.nodes[0].sendrawtransaction( txs[1]['hex'] ) # sending on both nodes is faster than waiting for propagation self.sync_all() self.log.info( "Test getbalance and getunconfirmedbalance with conflicted unconfirmed inputs" ) test_balances(fee_node_1=Decimal('0.02')) self.nodes[1].generatetoaddress(1, ADDRESS_WATCHONLY) self.sync_all() # balances are correct after the transactions are confirmed assert_equal( self.nodes[0].getbalance(), Decimal('69.99')) # node 1's send plus change from node 0's send assert_equal(self.nodes[1].getbalance(), Decimal('29.98')) # change from node 0's send # Send total balance away from node 1 txs = create_transactions(self.nodes[1], self.nodes[0].getnewaddress(), Decimal('29.97'), [Decimal('0.01')]) self.nodes[1].sendrawtransaction(txs[0]['hex']) self.nodes[1].generatetoaddress(2, ADDRESS_WATCHONLY) self.sync_all() # getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago # TODO: fix getbalance tracking of coin spentness depth # getbalance with minconf=3 should still show the old balance assert_equal(self.nodes[1].getbalance(minconf=3), Decimal('0')) # getbalance with minconf=2 will show the new balance. assert_equal(self.nodes[1].getbalance(minconf=2), Decimal('0')) # check mempool transactions count for wallet unconfirmed balance after # dynamically loading the wallet. before = self.nodes[1].getunconfirmedbalance() dst = self.nodes[1].getnewaddress() self.nodes[1].unloadwallet('') self.nodes[0].sendtoaddress(dst, 0.1) self.sync_all() self.nodes[1].loadwallet('') after = self.nodes[1].getunconfirmedbalance() assert_equal(before + Decimal('0.1'), after) # Create 3 more wallet txs, where the last is not accepted to the # mempool because it is the third descendant of the tx above for _ in range(3): # Set amount high enough such that all coins are spent by each tx txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 99) self.log.info('Check that wallet txs not in the mempool are untrusted') assert txid not in self.nodes[0].getrawmempool() assert_equal(self.nodes[0].gettransaction(txid)['trusted'], False) assert_equal(self.nodes[0].getbalance(minconf=0), 0) self.log.info("Test replacement and reorg of non-mempool tx") tx_orig = self.nodes[0].gettransaction(txid)['hex'] # Increase fee by 1 coin tx_replace = tx_orig.replace( struct.pack("<q", 99 * 10**8).hex(), struct.pack("<q", 98 * 10**8).hex(), ) tx_replace = self.nodes[0].signrawtransactionwithwallet( tx_replace)['hex'] # Total balance is given by the sum of outputs of the tx total_amount = sum([ o['value'] for o in self.nodes[0].decoderawtransaction(tx_replace)['vout'] ]) self.sync_all() self.nodes[1].sendrawtransaction(hexstring=tx_replace, maxfeerate=0) # Now confirm tx_replace block_reorg = self.nodes[1].generatetoaddress(1, ADDRESS_WATCHONLY)[0] self.sync_all() assert_equal(self.nodes[0].getbalance(minconf=0), total_amount) self.log.info('Put txs back into mempool of node 1 (not node 0)') self.nodes[0].invalidateblock(block_reorg) self.nodes[1].invalidateblock(block_reorg) assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted self.nodes[0].generatetoaddress(1, ADDRESS_WATCHONLY) assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted # Now confirm tx_orig self.restart_node(1, ['-persistmempool=0']) connect_nodes_bi(self.nodes, 0, 1) sync_blocks(self.nodes) self.nodes[1].sendrawtransaction(tx_orig) self.nodes[1].generatetoaddress(1, ADDRESS_WATCHONLY) self.sync_all() assert_equal(self.nodes[0].getbalance(minconf=0), total_amount + 1) # The reorg recovered our fee of 1 coin
def run_test(self): node = self.nodes[0].add_p2p_connection(P2PIgnoreInv()) network_thread_start() node.wait_for_verack() expected_services = NODE_BLOOM | NODE_WITNESS | NODE_NETWORK_LIMITED self.log.info("Check that node has signalled expected services.") assert_equal(node.nServices, expected_services) self.log.info("Check that the localservices is as expected.") assert_equal(int(self.nodes[0].getnetworkinfo()['localservices'], 16), expected_services) self.log.info( "Mine enough blocks to reach the NODE_NETWORK_LIMITED range.") connect_nodes_bi(self.nodes, 0, 1) blocks = self.nodes[1].generate(292) sync_blocks([self.nodes[0], self.nodes[1]]) self.log.info("Make sure we can max retrieve block at tip-288.") node.send_getdata_for_block(blocks[1]) # last block in valid range node.wait_for_block(int(blocks[1], 16), timeout=3) self.log.info( "Requesting block at height 2 (tip-289) must fail (ignored).") node.send_getdata_for_block( blocks[0]) # first block outside of the 288+2 limit node.wait_for_disconnect(5) self.log.info("Check local address relay, do a fresh connection.") self.nodes[0].disconnect_p2ps() network_thread_join() node1 = self.nodes[0].add_p2p_connection(P2PIgnoreInv()) network_thread_start() node1.wait_for_verack() node1.send_message(msg_verack()) node1.wait_for_addr() #must relay address with NODE_NETWORK_LIMITED assert_equal(node1.firstAddrnServices, 1036) self.nodes[0].disconnect_p2ps() node1.wait_for_disconnect() # connect unsynced node 2 with pruned NODE_NETWORK_LIMITED peer # because node 2 is in IBD and node 0 is a NODE_NETWORK_LIMITED peer, sync must not be possible connect_nodes_bi(self.nodes, 0, 2) try: sync_blocks([self.nodes[0], self.nodes[2]], timeout=5) except: pass # node2 must remain at heigh 0 assert_equal( self.nodes[2].getblockheader( self.nodes[2].getbestblockhash())['height'], 0) # now connect also to node 1 (non pruned) connect_nodes_bi(self.nodes, 1, 2) # sync must be possible sync_blocks(self.nodes) # disconnect all peers self.disconnect_all() # mine 10 blocks on node 0 (pruned node) self.nodes[0].generate(10) # connect node1 (non pruned) with node0 (pruned) and check if the can sync connect_nodes_bi(self.nodes, 0, 1) # sync must be possible, node 1 is no longer in IBD and should therefore connect to node 0 (NODE_NETWORK_LIMITED) sync_blocks([self.nodes[0], self.nodes[1]])
def setup_network(self, split=False): super().setup_network() connect_nodes_bi(self.nodes, 0, 2)
def run_test(self): assert_equal(len(self.nodes[0].listtokens()), 1) # only one token == DFI self.nodes[0].generate(100) self.sync_all() # Stop node #3 for future revert self.stop_node(3) # CREATION: #======================== collateral0 = self.nodes[0].getnewaddress("", "legacy") self.nodes[0].generate(1) # 1 Creating DAT token self.nodes[0].createtoken({ "symbol": "PT", "name": "Platinum", "isDAT": True, "collateralAddress": collateral0 }) self.nodes[0].generate(1) self.sync_blocks([self.nodes[0], self.nodes[2]]) # At this point, token was created tokens = self.nodes[0].listtokens() assert_equal(len(tokens), 2) assert_equal(tokens['1']["symbol"], "PT") # check sync: tokens = self.nodes[2].listtokens() assert_equal(len(tokens), 2) assert_equal(tokens['1']["symbol"], "PT") # 3 Trying to make regular token self.nodes[0].generate(1) createTokenTx = self.nodes[0].createtoken({ "symbol": "GOLD", "name": "shiny gold", "isDAT": False, "collateralAddress": collateral0 }) self.nodes[0].generate(1) # Checks tokens = self.nodes[0].listtokens() assert_equal(len(tokens), 3) assert_equal(tokens['128']["symbol"], "GOLD") assert_equal(tokens['128']["creationTx"], createTokenTx) # 7 Creating PoolPair from Foundation -> OK self.nodes[0].createpoolpair({ "tokenA": "PT", "tokenB": "GOLD#128", "comission": 0.001, "status": True, "ownerAddress": collateral0, "pairSymbol": "PTGOLD" }, []) self.nodes[0].generate(1) # Trying to create the same again and fail try: self.nodes[0].createpoolpair({ "tokenA": "PT", "tokenB": "GOLD#128", "comission": 0.001, "status": True, "ownerAddress": collateral0, "pairSymbol": "PTGD" }, []) except JSONRPCException as e: errorString = e.error['message'] assert("Error, there is already a poolpairwith same tokens, but different poolId" in errorString) # Creating another one trPP = self.nodes[0].createpoolpair({ "tokenA": "DFI", "tokenB": "GOLD#128", "comission": 0.001, "status": True, "ownerAddress": collateral0, "pairSymbol": "DFGLD" }, []) # 7+ Checking if it's an automatically created token (collateral unlocked, user's token has collateral locked) tx = self.nodes[0].getrawtransaction(trPP) decodeTx = self.nodes[0].decoderawtransaction(tx) assert_equal(len(decodeTx['vout']), 2) #print(decodeTx['vout'][1]['scriptPubKey']['hex']) spendTx = self.nodes[0].createrawtransaction([{'txid':decodeTx['txid'], 'vout':1}],[{collateral0:9.999}]) signedTx = self.nodes[0].signrawtransactionwithwallet(spendTx) assert_equal(signedTx['complete'], True) self.nodes[0].generate(1) # 8 Creating PoolPair not from Foundation -> Error try: self.nodes[2].createpoolpair({ "tokenA": "DFI", "tokenB": "GOLD#128", "comission": 0.001, "status": True, "ownerAddress": collateral0, "pairSymbol": "DFIGOLD" }, []) except JSONRPCException as e: errorString = e.error['message'] assert("Need foundation member authorization" in errorString) # 9 Checking pool existence p0 = self.nodes[0].getpoolpair("PTGOLD") assert_equal(p0['2']['symbol'], "PTGOLD") #10 Checking nonexistent pool try: self.nodes[0].getpoolpair("DFIGOLD") except JSONRPCException as e: errorString = e.error['message'] assert("Pool not found" in errorString) try: self.nodes[2].getpoolpair("PTGOLD") except JSONRPCException as e: errorString = e.error['message'] assert("Pool not found" in errorString) #11 Checking listpoolpairs poolpairsn0 = self.nodes[0].listpoolpairs() assert_equal(len(poolpairsn0), 2) self.sync_blocks([self.nodes[0], self.nodes[2]]) poolpairsn2 = self.nodes[2].listpoolpairs() #print (poolpairsn2) assert_equal(len(poolpairsn2), 2) # 12 Checking pool existence after sync p1 = self.nodes[2].getpoolpair("PTGOLD") #print(p1) assert_equal(p1['2']['symbol'], "PTGOLD") assert(p1['2']['idTokenA'] == '1') assert(p1['2']['idTokenB'] == '128') # 13 Change pool status assert_equal(self.nodes[0].getpoolpair("PTGOLD")['2']['status'], True) self.nodes[0].updatepoolpair({ "pool": "PTGOLD", "status": False, "commission": 0.01 }, []) self.nodes[0].generate(1) assert_equal(self.nodes[0].getpoolpair("PTGOLD")['2']['status'], False) assert_equal(str(self.nodes[0].getpoolpair("PTGOLD")['2']['commission']), "0.01000000") self.sync_blocks([self.nodes[0], self.nodes[2]]) assert_equal(self.nodes[2].getpoolpair("PTGOLD")['2']['status'], False) assert_equal(str(self.nodes[2].getpoolpair("PTGOLD")['2']['commission']), "0.01000000") self.nodes[0].updatepoolpair({"pool": "PTGOLD", "commission": 0.1}, []) self.nodes[0].generate(1) assert_equal(self.nodes[0].getpoolpair("PTGOLD")['2']['status'], False) assert_equal(str(self.nodes[0].getpoolpair("PTGOLD")['2']['commission']), "0.10000000") try: self.nodes[0].updatepoolpair({"pool": "PTGOLD", "commission": 2}) except JSONRPCException as e: errorString = e.error['message'] assert("commission > 100%" in errorString) self.nodes[0].updatepoolpair({"pool": "PTGOLD", "status": True}, []) self.nodes[0].generate(1) assert_equal(self.nodes[0].getpoolpair("PTGOLD")['2']['status'], True) assert_equal(str(self.nodes[0].getpoolpair("PTGOLD")['2']['commission']), "0.10000000") ownerAddress = self.nodes[0].getpoolpair("PTGOLD")['2']['ownerAddress'] collateral1 = self.nodes[1].getnewaddress("", "legacy") self.nodes[0].updatepoolpair({"pool": "PTGOLD", "ownerAddress": collateral1}, []) self.nodes[0].generate(1) assert_equal(self.nodes[0].getpoolpair("PTGOLD")['2']['status'], True) assert_equal(str(self.nodes[0].getpoolpair("PTGOLD")['2']['commission']), "0.10000000") assert(self.nodes[0].getpoolpair("PTGOLD")['2']['ownerAddress'] != ownerAddress) self.nodes[0].updatepoolpair({"pool": "PTGOLD", "ownerAddress": collateral0}, []) self.nodes[0].generate(1) assert_equal(self.nodes[0].getpoolpair("PTGOLD")['2']['ownerAddress'], ownerAddress) # REVERTING: #======================== print ("Reverting...") # Reverting creation! self.start_node(3) self.nodes[3].generate(30) connect_nodes_bi(self.nodes, 0, 3) self.sync_blocks() assert_equal(len(self.nodes[0].listpoolpairs()), 0)
def run_test(self): self.log.info("Test setban and listbanned RPCs") self.log.info("setban: successfully ban single IP address") assert_equal( len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point self.nodes[1].setban("127.0.0.1", "add") wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10) assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point assert_equal(len(self.nodes[1].listbanned()), 1) self.log.info("clearbanned: successfully clear ban list") self.nodes[1].clearbanned() assert_equal(len(self.nodes[1].listbanned()), 0) self.nodes[1].setban("127.0.0.0/24", "add") self.log.info("setban: fail to ban an already banned subnet") assert_equal(len(self.nodes[1].listbanned()), 1) assert_raises_rpc_error(-23, "IP/Subnet already banned", self.nodes[1].setban, "127.0.0.1", "add") self.log.info("setban: fail to ban an invalid subnet") assert_raises_rpc_error(-30, "Error: Invalid IP/Subnet", self.nodes[1].setban, "127.0.0.1/42", "add") assert_equal( len(self.nodes[1].listbanned()), 1 ) # still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 self.log.info("setban remove: fail to unban a non-banned subnet") assert_raises_rpc_error(-30, "Error: Unban failed", self.nodes[1].setban, "127.0.0.1", "remove") assert_equal(len(self.nodes[1].listbanned()), 1) self.log.info("setban remove: successfully unban subnet") self.nodes[1].setban("127.0.0.0/24", "remove") assert_equal(len(self.nodes[1].listbanned()), 0) self.nodes[1].clearbanned() assert_equal(len(self.nodes[1].listbanned()), 0) self.log.info("setban: test persistence across node restart") self.nodes[1].setban("127.0.0.0/32", "add") self.nodes[1].setban("127.0.0.0/24", "add") # Set the mocktime so we can control when bans expire old_time = int(time.time()) self.nodes[1].setmocktime(old_time) self.nodes[1].setban("192.168.0.1", "add", 1) # ban for 1 seconds self.nodes[1].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds listBeforeShutdown = self.nodes[1].listbanned() assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) # Move time forward by 3 seconds so the third ban has expired self.nodes[1].setmocktime(old_time + 3) assert_equal(len(self.nodes[1].listbanned()), 3) self.stop_node(1) self.start_node(1) listAfterShutdown = self.nodes[1].listbanned() assert_equal("127.0.0.0/24", listAfterShutdown[0]['address']) assert_equal("127.0.0.0/32", listAfterShutdown[1]['address']) assert_equal("/19" in listAfterShutdown[2]['address'], True) # Clear ban lists self.nodes[1].clearbanned() connect_nodes_bi(self.nodes, 0, 1) self.log.info("Test disconnectnode RPCs") self.log.info( "disconnectnode: fail to disconnect when calling with address and nodeid" ) address1 = self.nodes[0].getpeerinfo()[0]['addr'] node1 = self.nodes[0].getpeerinfo()[0]['addr'] assert_raises_rpc_error( -32602, "Only one of address and nodeid should be provided.", self.nodes[0].disconnectnode, address=address1, nodeid=node1) self.log.info( "disconnectnode: fail to disconnect when calling with junk address" ) assert_raises_rpc_error(-29, "Node not found in connected nodes", self.nodes[0].disconnectnode, address="221B Baker Street") self.log.info( "disconnectnode: successfully disconnect node by address") address1 = self.nodes[0].getpeerinfo()[0]['addr'] self.nodes[0].disconnectnode(address=address1) wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) assert not [ node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1 ] self.log.info("disconnectnode: successfully reconnect node") connect_nodes_bi(self.nodes, 0, 1) # reconnect the node assert_equal(len(self.nodes[0].getpeerinfo()), 2) assert [ node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1 ] self.log.info( "disconnectnode: successfully disconnect node by node id") id1 = self.nodes[0].getpeerinfo()[0]['id'] self.nodes[0].disconnectnode(nodeid=id1) wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) assert not [ node for node in self.nodes[0].getpeerinfo() if node['id'] == id1 ]
def run_test(self): wallet_path = os.path.join(self.nodes[1].datadir, "regtest", "wallets", "wallet.dat") wallet_backup_path = os.path.join(self.nodes[1].datadir, "wallet.bak") self.nodes[0].generate(101) self.log.info("Make backup of wallet") self.stop_node(1) shutil.copyfile(wallet_path, wallet_backup_path) self.start_node(1, self.extra_args[1]) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 0, 2) connect_nodes_bi(self.nodes, 0, 3) for i, output_type in enumerate(["legacy", "p2sh-segwit", "bech32"]): self.log.info( "Generate keys for wallet with address type: {}".format( output_type)) idx = i + 1 for _ in range(90): addr_oldpool = self.nodes[idx].getnewaddress( address_type=output_type) for _ in range(20): addr_extpool = self.nodes[idx].getnewaddress( address_type=output_type) # Make sure we're creating the outputs we expect address_details = self.nodes[idx].validateaddress(addr_extpool) if i == 0: assert not address_details["isscript"] and not address_details[ "iswitness"] elif i == 1: assert address_details[ "isscript"] and not address_details["iswitness"] else: assert not address_details["isscript"] and address_details[ "iswitness"] self.log.info("Send funds to wallet") self.nodes[0].sendtoaddress(addr_oldpool, 10) self.nodes[0].generate(1) self.nodes[0].sendtoaddress(addr_extpool, 5) self.nodes[0].generate(1) self.sync_blocks() self.log.info("Restart node with wallet backup") self.stop_node(idx) shutil.copyfile(wallet_backup_path, wallet_path) self.start_node(idx, self.extra_args[idx]) connect_nodes_bi(self.nodes, 0, idx) self.sync_all() self.log.info("Verify keypool is restored and balance is correct") assert_equal(self.nodes[idx].getbalance(), 15) assert_equal(self.nodes[idx].listtransactions()[0]['category'], "receive") # Check that we have marked all keys up to the used keypool key as used assert_equal( self.nodes[idx].getaddressinfo( self.nodes[idx].getnewaddress())['hdkeypath'], "m/0'/0'/110'")
def run_test(self): # add zaddr to node 0 myzaddr0 = self.nodes[0].z_getnewaddress() # send node 0 taddr to zaddr to get out of coinbase mytaddr = self.nodes[0].getnewaddress() recipients = [] recipients.append({ "address": myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001') }) # utxo amount less fee myopid = self.nodes[0].z_sendmany(mytaddr, recipients) opids = [] opids.append(myopid) timeout = 120 status = None for x in xrange(1, timeout): results = self.nodes[0].z_getoperationresult(opids) if len(results) == 0: time.sleep(1) else: status = results[0]["status"] assert_equal("success", status) mytxid = results[0]["result"]["txid"] break self.sync_all() self.nodes[0].generate(1) self.sync_all() # add zaddr to node 2 myzaddr = self.nodes[2].z_getnewaddress() # import node 2 zaddr into node 1 myzkey = self.nodes[2].z_exportkey(myzaddr) self.nodes[1].z_importkey(myzkey) # encrypt node 1 wallet and wait to terminate self.nodes[1].encryptwallet("test") litecoinzd_processes[1].wait() # restart node 1 self.nodes[1] = start_node(1, self.options.tmpdir) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) self.sync_all() # send node 0 zaddr to note 2 zaddr recipients = [] recipients.append({"address": myzaddr, "amount": 7.0}) myopid = self.nodes[0].z_sendmany(myzaddr0, recipients) opids = [] opids.append(myopid) timeout = 120 status = None for x in xrange(1, timeout): results = self.nodes[0].z_getoperationresult(opids) if len(results) == 0: time.sleep(1) else: status = results[0]["status"] assert_equal("success", status) mytxid = results[0]["result"]["txid"] break self.sync_all() self.nodes[0].generate(1) self.sync_all() # check zaddr balance zsendmanynotevalue = Decimal('7.0') assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue) assert_equal(self.nodes[1].z_getbalance(myzaddr), zsendmanynotevalue) # add zaddr to node 3 myzaddr3 = self.nodes[3].z_getnewaddress() # send node 2 zaddr to note 3 zaddr recipients = [] recipients.append({"address": myzaddr3, "amount": 2.0}) myopid = self.nodes[2].z_sendmany(myzaddr, recipients) opids = [] opids.append(myopid) timeout = 120 status = None for x in xrange(1, timeout): results = self.nodes[2].z_getoperationresult(opids) if len(results) == 0: time.sleep(1) else: status = results[0]["status"] assert_equal("success", status) mytxid = results[0]["result"]["txid"] break self.sync_all() self.nodes[2].generate(1) self.sync_all() # check zaddr balance zsendmany2notevalue = Decimal('2.0') zsendmanyfee = Decimal('0.0001') zaddrremaining = zsendmanynotevalue - zsendmany2notevalue - zsendmanyfee assert_equal(self.nodes[3].z_getbalance(myzaddr3), zsendmany2notevalue) assert_equal(self.nodes[2].z_getbalance(myzaddr), zaddrremaining) # Parallel encrypted wallet can't cache nullifiers for received notes, # and therefore can't detect spends. So it sees a balance corresponding # to the sum of both notes it received (one as change). # TODO: Devise a way to avoid this issue (#1528) assert_equal(self.nodes[1].z_getbalance(myzaddr), zsendmanynotevalue + zaddrremaining) # send node 2 zaddr on node 1 to taddr # This requires that node 1 be unlocked, which triggers caching of # uncached nullifiers. self.nodes[1].walletpassphrase("test", 600) mytaddr1 = self.nodes[1].getnewaddress() recipients = [] recipients.append({"address": mytaddr1, "amount": 1.0}) myopid = self.nodes[1].z_sendmany(myzaddr, recipients) opids = [] opids.append(myopid) timeout = 120 status = None for x in xrange(1, timeout): results = self.nodes[1].z_getoperationresult(opids) if len(results) == 0: time.sleep(1) else: status = results[0]["status"] assert_equal("success", status) mytxid = results[0]["result"]["txid"] [mytxid] # hush pyflakes break self.sync_all() self.nodes[1].generate(1) self.sync_all() # check zaddr balance # Now that the encrypted wallet has been unlocked, the note nullifiers # have been cached and spent notes can be detected. Thus the two wallets # are in agreement once more. zsendmany3notevalue = Decimal('1.0') zaddrremaining2 = zaddrremaining - zsendmany3notevalue - zsendmanyfee assert_equal(self.nodes[1].z_getbalance(myzaddr), zaddrremaining2) assert_equal(self.nodes[2].z_getbalance(myzaddr), zaddrremaining2) # Test viewing keys node3mined = Decimal('250.0') assert_equal( { k: Decimal(v) for k, v in self.nodes[3].z_gettotalbalance().items() }, { 'transparent': node3mined, 'private': zsendmany2notevalue, 'total': node3mined + zsendmany2notevalue, }) # add node 1 address and node 2 viewing key to node 3 myzvkey = self.nodes[2].z_exportviewingkey(myzaddr) self.nodes[3].importaddress(mytaddr1) self.nodes[3].z_importviewingkey(myzvkey) # Check the address has been imported assert_equal(myzaddr in self.nodes[3].z_listaddresses(), False) assert_equal(myzaddr in self.nodes[3].z_listaddresses(True), True) # Node 3 should see the same received notes as node 2 assert_equal(self.nodes[2].z_listreceivedbyaddress(myzaddr), self.nodes[3].z_listreceivedbyaddress(myzaddr)) # Node 3's balances should be unchanged without explicitly requesting # to include watch-only balances assert_equal( { k: Decimal(v) for k, v in self.nodes[3].z_gettotalbalance().items() }, { 'transparent': node3mined, 'private': zsendmany2notevalue, 'total': node3mined + zsendmany2notevalue, }) # Wallet can't cache nullifiers for notes received by addresses it only has a # viewing key for, and therefore can't detect spends. So it sees a balance # corresponding to the sum of all notes the address received. # TODO: Fix this during the Sapling upgrade (via #2277) assert_equal( { k: Decimal(v) for k, v in self.nodes[3].z_gettotalbalance(1, True).items() }, { 'transparent': node3mined + Decimal('1.0'), 'private': zsendmany2notevalue + zsendmanynotevalue + zaddrremaining + zaddrremaining2, 'total': node3mined + Decimal('1.0') + zsendmany2notevalue + zsendmanynotevalue + zaddrremaining + zaddrremaining2, }) # Check individual balances reflect the above assert_equal(self.nodes[3].z_getbalance(mytaddr1), Decimal('1.0')) assert_equal(self.nodes[3].z_getbalance(myzaddr), zsendmanynotevalue + zaddrremaining + zaddrremaining2)
def run_test(self): testnode0 = TestNode() connections = [] connections.append( NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], testnode0, "regtest", OVERWINTER_PROTO_VERSION)) testnode0.add_connection(connections[0]) # Start up network handling in another thread NetworkThread().start() testnode0.wait_for_verack() # Verify mininodes are connected to zprimed nodes peerinfo = self.nodes[0].getpeerinfo() versions = [x["version"] for x in peerinfo] assert_equal(1, versions.count(OVERWINTER_PROTO_VERSION)) assert_equal(0, peerinfo[0]["banscore"]) # Mine some blocks so we can spend coinbase_blocks = self.nodes[0].generate(200) node_address = self.nodes[0].getnewaddress() # Sync nodes 0 and 1 sync_blocks(self.nodes[:2]) sync_mempools(self.nodes[:2]) # Verify block count assert_equal(self.nodes[0].getblockcount(), 200) assert_equal(self.nodes[1].getblockcount(), 200) assert_equal(self.nodes[2].getblockcount(), 0) # Mininodes send expiring soon transaction in "tx" message to zprimed node self.send_transaction(testnode0, coinbase_blocks[0], node_address, 203) # Assert that the tx is not in the mempool (expiring soon) assert_equal([], self.nodes[0].getrawmempool()) assert_equal([], self.nodes[1].getrawmempool()) assert_equal([], self.nodes[2].getrawmempool()) # Mininodes send transaction in "tx" message to zprimed node tx2 = self.send_transaction(testnode0, coinbase_blocks[1], node_address, 204) # tx2 is not expiring soon assert_equal([tx2.hash], self.nodes[0].getrawmempool()) assert_equal([tx2.hash], self.nodes[1].getrawmempool()) # node 2 is isolated assert_equal([], self.nodes[2].getrawmempool()) # Verify txid for tx2 self.verify_inv(testnode0, tx2) self.send_data_message(testnode0, tx2) self.verify_last_tx(testnode0, tx2) # Sync and mine an empty block with node 2, leaving tx in the mempool of node0 and node1 for blkhash in coinbase_blocks: blk = self.nodes[0].getblock(blkhash, 0) self.nodes[2].submitblock(blk) self.nodes[2].generate(1) # Verify block count assert_equal(self.nodes[0].getblockcount(), 200) assert_equal(self.nodes[1].getblockcount(), 200) assert_equal(self.nodes[2].getblockcount(), 201) # Reconnect node 2 to the network connect_nodes_bi(self.nodes, 0, 2) # Set up test node for node 2 testnode2 = TestNode() connections.append( NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], testnode2, "regtest", OVERWINTER_PROTO_VERSION)) testnode2.add_connection(connections[-1]) # Verify block count sync_blocks(self.nodes[:3]) assert_equal(self.nodes[0].getblockcount(), 201) assert_equal(self.nodes[1].getblockcount(), 201) assert_equal(self.nodes[2].getblockcount(), 201) # Verify contents of mempool assert_equal([tx2.hash], self.nodes[0].getrawmempool()) assert_equal([tx2.hash], self.nodes[1].getrawmempool()) assert_equal([], self.nodes[2].getrawmempool()) # Confirm tx2 cannot be submitted to a mempool because it is expiring soon. try: rawtx2 = hexlify(tx2.serialize()) self.nodes[2].sendrawtransaction(rawtx2) fail("Sending transaction should have failed") except JSONRPCException as e: assert_equal( "tx-expiring-soon: expiryheight is 204 but should be at least 205 to avoid transaction expiring soon", e.error['message']) self.send_data_message(testnode0, tx2) # Sync up with node after p2p messages delivered testnode0.sync_with_ping() # Verify node 0 does not reply to "getdata" by sending "tx" message, as tx2 is expiring soon with mininode_lock: assert_equal(testnode0.last_tx, None) # Verify mininode received a "notfound" message containing the txid of tx2 with mininode_lock: msg = testnode0.last_notfound assert_equal(len(msg.inv), 1) assert_equal(tx2.sha256, msg.inv[0].hash) # Create a transaction to verify that processing of "getdata" messages is functioning tx3 = self.send_transaction(testnode0, coinbase_blocks[2], node_address, 999) self.send_data_message(testnode0, tx3) self.verify_last_tx(testnode0, tx3) # Verify txid for tx3 is returned in "inv", but tx2 which is expiring soon is not returned self.verify_inv(testnode0, tx3) self.verify_inv(testnode2, tx3) # Verify contents of mempool assert_equal({tx2.hash, tx3.hash}, set(self.nodes[0].getrawmempool())) assert_equal({tx2.hash, tx3.hash}, set(self.nodes[1].getrawmempool())) assert_equal({tx3.hash}, set(self.nodes[2].getrawmempool())) # Verify banscore for nodes are still zero assert_equal( 0, sum(peer["banscore"] for peer in self.nodes[0].getpeerinfo())) assert_equal( 0, sum(peer["banscore"] for peer in self.nodes[2].getpeerinfo())) [c.disconnect_node() for c in connections]
def run_test(self): # Make sure can't switch off usehd after wallet creation self.stop_node(1) self.nodes[1].assert_start_raises_init_error([ '-usehd=0' ], "Error: Error loading : You can't disable HD on an already existing HD wallet" ) self.start_node(1) connect_nodes_bi(self.nodes, 0, 1) # Make sure we use hd, keep masterkeyid masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] assert_equal(masterkeyid, self.nodes[1].getwalletinfo()['hdmasterkeyid']) assert_equal(len(masterkeyid), 40) # create an internal key change_addr = self.nodes[1].getrawchangeaddress() change_addrV = self.nodes[1].getaddressinfo(change_addr) assert_equal(change_addrV["hdkeypath"], "m/88'/1'/0'") #first internal child key # Import a non-HD private key in the HD wallet non_hd_add = self.nodes[0].getnewaddress() self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add)) # This should be enough to keep the master key and the non-HD key self.nodes[1].backupwallet( os.path.join(self.nodes[1].datadir, "hd.bak")) #self.nodes[1].dumpwallet(os.path.join(self.nodes[1].datadir, "hd.dump")) # Derive some HD addresses and remember the last # Also send funds to each add self.nodes[0].generate(COINBASE_MATURITY + 1) hd_add = None NUM_HD_ADDS = 10 for i in range(NUM_HD_ADDS): hd_add = self.nodes[1].getnewaddress() hd_info = self.nodes[1].getaddressinfo(hd_add) assert_equal(hd_info["hdkeypath"], "m/88'/0'/" + str(i) + "'") assert_equal(hd_info["hdseedid"], masterkeyid) assert_equal(hd_info["hdmasterkeyid"], masterkeyid) self.nodes[0].sendtoaddress(hd_add, 1) self.nodes[0].generate(1) self.nodes[0].sendtoaddress(non_hd_add, 1) self.nodes[0].generate(1) # create an internal key (again) change_addr = self.nodes[1].getrawchangeaddress() change_addrV = self.nodes[1].getaddressinfo(change_addr) assert_equal(change_addrV["hdkeypath"], "m/88'/1'/1'") #second internal child key self.sync_all() assert_equal(self.nodes[1].getbalance(), NUM_HD_ADDS + 1) self.log.info("Restore backup ...") self.stop_node(1) # we need to delete the complete regtest directory # otherwise node1 would auto-recover all funds in flag the keypool keys as used shutil.rmtree(os.path.join(self.nodes[1].datadir, "regtest", "blocks")) shutil.rmtree( os.path.join(self.nodes[1].datadir, "regtest", "chainstate")) shutil.copyfile( os.path.join(self.nodes[1].datadir, "hd.bak"), os.path.join(self.nodes[1].datadir, "regtest", "wallets", "wallet.dat")) self.start_node(1) # Assert that derivation is deterministic hd_add_2 = None for i in range(NUM_HD_ADDS): hd_add_2 = self.nodes[1].getnewaddress() hd_info_2 = self.nodes[1].getaddressinfo(hd_add_2) assert_equal(hd_info_2["hdkeypath"], "m/88'/0'/" + str(i) + "'") assert_equal(hd_info_2["hdseedid"], masterkeyid) assert_equal(hd_info_2["hdmasterkeyid"], masterkeyid) assert_equal(hd_add, hd_add_2) connect_nodes_bi(self.nodes, 0, 1) self.sync_all() # Needs rescan self.stop_node(1) self.start_node(1, extra_args=self.extra_args[1] + ['-rescan']) assert_equal(self.nodes[1].getbalance(), NUM_HD_ADDS + 1) # Try a RPC based rescan self.stop_node(1) shutil.rmtree(os.path.join(self.nodes[1].datadir, "regtest", "blocks")) shutil.rmtree( os.path.join(self.nodes[1].datadir, "regtest", "chainstate")) shutil.copyfile( os.path.join(self.nodes[1].datadir, "hd.bak"), os.path.join(self.nodes[1].datadir, "regtest", "wallets", "wallet.dat")) self.start_node(1, extra_args=self.extra_args[1]) connect_nodes_bi(self.nodes, 0, 1) self.sync_all() # Wallet automatically scans blocks older than key on startup assert_equal(self.nodes[1].getbalance(), NUM_HD_ADDS + 1) out = self.nodes[1].rescanblockchain(0, 1) assert_equal(out['start_height'], 0) assert_equal(out['stop_height'], 1) out = self.nodes[1].rescanblockchain() assert_equal(out['start_height'], 0) assert_equal(out['stop_height'], self.nodes[1].getblockcount()) assert_equal(self.nodes[1].getbalance(), NUM_HD_ADDS + 1) # send a tx and make sure its using the internal chain for the changeoutput txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) outs = self.nodes[1].decoderawtransaction( self.nodes[1].gettransaction(txid)['hex'])['vout'] keypath = "" for out in outs: if out['value'] != 1: keypath = self.nodes[1].getaddressinfo( out['scriptPubKey']['addresses'][0])['hdkeypath'] assert_equal(keypath[0:8], "m/88'/1'") # Generate a new HD seed on node 1 and make sure it is set orig_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] self.nodes[1].sethdseed() new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] assert orig_masterkeyid != new_masterkeyid addr = self.nodes[1].getnewaddress() assert_equal( self.nodes[1].getaddressinfo(addr)['hdkeypath'], 'm/88\'/0\'/0\'' ) # Make sure the new address is the first from the keypool self.nodes[1].keypoolrefill(1) # Fill keypool with 1 key # Set a new HD seed on node 1 without flushing the keypool new_seed = self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress()) orig_masterkeyid = new_masterkeyid self.nodes[1].sethdseed(False, new_seed) new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] assert orig_masterkeyid != new_masterkeyid addr = self.nodes[1].getnewaddress() assert_equal(orig_masterkeyid, self.nodes[1].getaddressinfo(addr)['hdseedid']) assert_equal(self.nodes[1].getaddressinfo(addr)['hdkeypath'], 'm/88\'/0\'/1\'' ) # Make sure the new address continues previous keypool # Check that the next address is from the new seed self.nodes[1].keypoolrefill(1) next_addr = self.nodes[1].getnewaddress() assert_equal(new_masterkeyid, self.nodes[1].getaddressinfo(next_addr)['hdseedid']) assert_equal( self.nodes[1].getaddressinfo(next_addr)['hdkeypath'], 'm/88\'/0\'/0\'' ) # Make sure the new address is not from previous keypool assert next_addr != addr # Sethdseed parameter validity assert_raises_rpc_error(-1, 'sethdseed', self.nodes[0].sethdseed, False, new_seed, 0) assert_raises_rpc_error(-5, "Invalid private key", self.nodes[1].sethdseed, False, "not_wif") assert_raises_rpc_error(-1, "JSON value is not a boolean as expected", self.nodes[1].sethdseed, "Not_bool") assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[1].sethdseed, False, True) assert_raises_rpc_error(-5, "Already have this key", self.nodes[1].sethdseed, False, new_seed) assert_raises_rpc_error( -5, "Already have this key", self.nodes[1].sethdseed, False, self.nodes[1].dumpprivkey(self.nodes[1].getnewaddress()))
def run_test(self): print("Mining blocks...") feeTolerance = Decimal( "0.00000002" ) #if the fee's positive delta is higher than this value tests will fail, neg. delta always fail the tests self.nodes[2].generate(1) self.sync_all() self.nodes[0].generate(201) self.sync_all() watchonly_address = self.nodes[0].getnewaddress() watchonly_pubkey = self.nodes[0].validateaddress( watchonly_address)["pubkey"] watchonly_amount = 200 self.nodes[3].importpubkey(watchonly_pubkey, "", True) watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address, watchonly_amount) self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(), watchonly_amount / 10) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0) self.sync_all() self.nodes[0].generate(1) self.sync_all() ############### # simple test # ############### inputs = [] outputs = {self.nodes[0].getnewaddress(): 1.0} rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) assert_equal(len(dec_tx['vin']) > 0, True) #test if we have enought inputs ############################## # simple test with two coins # ############################## inputs = [] outputs = {self.nodes[0].getnewaddress(): 2.2} rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) assert_equal(len(dec_tx['vin']) > 0, True) #test if we have enough inputs ############################## # simple test with two coins # ############################## inputs = [] outputs = {self.nodes[0].getnewaddress(): 2.6} rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) assert_equal(len(dec_tx['vin']) > 0, True) assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') ################################ # simple test with two outputs # ################################ inputs = [] outputs = { self.nodes[0].getnewaddress(): 2.6, self.nodes[1].getnewaddress(): 2.5 } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) totalOut = 0 for out in dec_tx['vout']: totalOut += out['value'] assert_equal(len(dec_tx['vin']) > 0, True) assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') ######################################################################### # test a fundrawtransaction with a VIN greater than the required amount # ######################################################################### utx = False listunspent = self.nodes[2].listunspent() for aUtx in listunspent: if aUtx['amount'] == 5.0: utx = aUtx break assert_equal(utx != False, True) inputs = [{'txid': utx['txid'], 'vout': utx['vout']}] outputs = {self.nodes[0].getnewaddress(): Decimal('1.0')} rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) totalOut = 0 for out in dec_tx['vout']: totalOut += out['value'] assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee ##################################################################### # test a fundrawtransaction with which will not get a change output # ##################################################################### utx = False listunspent = self.nodes[2].listunspent() for aUtx in listunspent: if aUtx['amount'] == 5.0: utx = aUtx break assert_equal(utx != False, True) inputs = [{'txid': utx['txid'], 'vout': utx['vout']}] outputs = { self.nodes[0].getnewaddress(): Decimal('5.0') - fee - feeTolerance } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) totalOut = 0 for out in dec_tx['vout']: totalOut += out['value'] assert_equal(rawtxfund['changepos'], -1) assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee ######################################################################### # test a fundrawtransaction with a VIN smaller than the required amount # ######################################################################### utx = False listunspent = self.nodes[2].listunspent() for aUtx in listunspent: if aUtx['amount'] == 1.0: utx = aUtx break assert_equal(utx != False, True) inputs = [{'txid': utx['txid'], 'vout': utx['vout']}] outputs = {self.nodes[0].getnewaddress(): Decimal('1.0')} rawtx = self.nodes[2].createrawtransaction(inputs, outputs) # 4-byte version + 4-byte versionGroupId + 1-byte vin count + 36-byte prevout then script_len rawtx = rawtx[:90] + "0100" + rawtx[92:] dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex']) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) totalOut = 0 matchingOuts = 0 for i, out in enumerate(dec_tx['vout']): totalOut += out['value'] if out['scriptPubKey']['addresses'][0] in outputs: matchingOuts += 1 else: assert_equal(i, rawtxfund['changepos']) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex']) assert_equal(matchingOuts, 1) assert_equal(len(dec_tx['vout']), 2) ########################################### # test a fundrawtransaction with two VINs # ########################################### utx = False utx2 = False listunspent = self.nodes[2].listunspent() for aUtx in listunspent: if aUtx['amount'] == 1.0: utx = aUtx if aUtx['amount'] == 5.0: utx2 = aUtx assert_equal(utx != False, True) inputs = [{ 'txid': utx['txid'], 'vout': utx['vout'] }, { 'txid': utx2['txid'], 'vout': utx2['vout'] }] outputs = {self.nodes[0].getnewaddress(): 6.0} rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) totalOut = 0 matchingOuts = 0 for out in dec_tx['vout']: totalOut += out['value'] if out['scriptPubKey']['addresses'][0] in outputs: matchingOuts += 1 assert_equal(matchingOuts, 1) assert_equal(len(dec_tx['vout']), 2) matchingIns = 0 for vinOut in dec_tx['vin']: for vinIn in inputs: if vinIn['txid'] == vinOut['txid']: matchingIns += 1 assert_equal( matchingIns, 2) #we now must see two vins identical to vins given as params ######################################################### # test a fundrawtransaction with two VINs and two vOUTs # ######################################################### utx = False utx2 = False listunspent = self.nodes[2].listunspent() for aUtx in listunspent: if aUtx['amount'] == 1.0: utx = aUtx if aUtx['amount'] == 5.0: utx2 = aUtx assert_equal(utx != False, True) inputs = [{ 'txid': utx['txid'], 'vout': utx['vout'] }, { 'txid': utx2['txid'], 'vout': utx2['vout'] }] outputs = { self.nodes[0].getnewaddress(): 6.0, self.nodes[0].getnewaddress(): 1.0 } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) fee = rawtxfund['fee'] dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) totalOut = 0 matchingOuts = 0 for out in dec_tx['vout']: totalOut += out['value'] if out['scriptPubKey']['addresses'][0] in outputs: matchingOuts += 1 assert_equal(matchingOuts, 2) assert_equal(len(dec_tx['vout']), 3) ############################################## # test a fundrawtransaction with invalid vin # ############################################## listunspent = self.nodes[2].listunspent() inputs = [{ 'txid': "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1", 'vout': 0 }] #invalid vin! outputs = {self.nodes[0].getnewaddress(): 1.0} rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) errorString = "" try: rawtxfund = self.nodes[2].fundrawtransaction(rawtx) except JSONRPCException as e: errorString = e.error['message'] assert_equal("Insufficient" in errorString, True) ############################################################ #compare fee of a standard pubkeyhash transaction inputs = [] outputs = {self.nodes[1].getnewaddress(): 1.1} rawTx = self.nodes[0].createrawtransaction(inputs, outputs) fundedTx = self.nodes[0].fundrawtransaction(rawTx) #create same transaction over sendtoaddress txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] #compare fee feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert (feeDelta >= 0 and feeDelta <= feeTolerance) ############################################################ ############################################################ #compare fee of a standard pubkeyhash transaction with multiple outputs inputs = [] outputs = { self.nodes[1].getnewaddress(): 1.1, self.nodes[1].getnewaddress(): 1.2, self.nodes[1].getnewaddress(): 0.1, self.nodes[1].getnewaddress(): 1.3, self.nodes[1].getnewaddress(): 0.2, self.nodes[1].getnewaddress(): 0.3 } rawTx = self.nodes[0].createrawtransaction(inputs, outputs) fundedTx = self.nodes[0].fundrawtransaction(rawTx) #create same transaction over sendtoaddress txId = self.nodes[0].sendmany("", outputs) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] #compare fee feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert (feeDelta >= 0 and feeDelta <= feeTolerance) ############################################################ ############################################################ #compare fee of a 2of2 multisig p2sh transaction # create 2of2 addr addr1 = self.nodes[1].getnewaddress() addr2 = self.nodes[1].getnewaddress() addr1Obj = self.nodes[1].validateaddress(addr1) addr2Obj = self.nodes[1].validateaddress(addr2) mSigObj = self.nodes[1].addmultisigaddress( 2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) inputs = [] outputs = {mSigObj: 1.1} rawTx = self.nodes[0].createrawtransaction(inputs, outputs) fundedTx = self.nodes[0].fundrawtransaction(rawTx) #create same transaction over sendtoaddress txId = self.nodes[0].sendtoaddress(mSigObj, 1.1) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] #compare fee feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert (feeDelta >= 0 and feeDelta <= feeTolerance) ############################################################ ############################################################ #compare fee of a standard pubkeyhash transaction # create 4of5 addr addr1 = self.nodes[1].getnewaddress() addr2 = self.nodes[1].getnewaddress() addr3 = self.nodes[1].getnewaddress() addr4 = self.nodes[1].getnewaddress() addr5 = self.nodes[1].getnewaddress() addr1Obj = self.nodes[1].validateaddress(addr1) addr2Obj = self.nodes[1].validateaddress(addr2) addr3Obj = self.nodes[1].validateaddress(addr3) addr4Obj = self.nodes[1].validateaddress(addr4) addr5Obj = self.nodes[1].validateaddress(addr5) mSigObj = self.nodes[1].addmultisigaddress(4, [ addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey'], addr4Obj['pubkey'], addr5Obj['pubkey'] ]) inputs = [] outputs = {mSigObj: 1.1} rawTx = self.nodes[0].createrawtransaction(inputs, outputs) fundedTx = self.nodes[0].fundrawtransaction(rawTx) #create same transaction over sendtoaddress txId = self.nodes[0].sendtoaddress(mSigObj, 1.1) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] #compare fee feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert (feeDelta >= 0 and feeDelta <= feeTolerance) ############################################################ ############################################################ # spend a 2of2 multisig transaction over fundraw # create 2of2 addr addr1 = self.nodes[2].getnewaddress() addr2 = self.nodes[2].getnewaddress() addr1Obj = self.nodes[2].validateaddress(addr1) addr2Obj = self.nodes[2].validateaddress(addr2) mSigObj = self.nodes[2].addmultisigaddress( 2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) # send 1.2 BTC to msig addr txId = self.nodes[0].sendtoaddress(mSigObj, 1.2) self.sync_all() self.nodes[1].generate(1) self.sync_all() oldBalance = self.nodes[1].getbalance() inputs = [] outputs = {self.nodes[1].getnewaddress(): 1.1} rawTx = self.nodes[2].createrawtransaction(inputs, outputs) fundedTx = self.nodes[2].fundrawtransaction(rawTx) signedTx = self.nodes[2].signrawtransaction(fundedTx['hex']) txId = self.nodes[2].sendrawtransaction(signedTx['hex']) self.sync_all() self.nodes[1].generate(1) self.sync_all() # make sure funds are received at node1 assert_equal(oldBalance + Decimal('1.10000000'), self.nodes[1].getbalance()) ############################################################ # locked wallet test self.nodes[1].encryptwallet("test") self.nodes.pop(1) stop_nodes(self.nodes) wait_bitcoinds() self.nodes = start_nodes(4, self.options.tmpdir) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) connect_nodes_bi(self.nodes, 0, 3) self.is_network_split = False self.sync_all() error = False try: self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2) except: error = True assert (error) oldBalance = self.nodes[0].getbalance() inputs = [] outputs = {self.nodes[0].getnewaddress(): 1.1} rawTx = self.nodes[1].createrawtransaction(inputs, outputs) fundedTx = self.nodes[1].fundrawtransaction(rawTx) #now we need to unlock self.nodes[1].walletpassphrase("test", 100) signedTx = self.nodes[1].signrawtransaction(fundedTx['hex']) txId = self.nodes[1].sendrawtransaction(signedTx['hex']) self.sync_all() self.nodes[1].generate(1) self.sync_all() # make sure funds are received at node1 assert_equal(oldBalance + Decimal('98.10000000'), self.nodes[0].getbalance()) ############################################### # multiple (~19) inputs tx test | Compare fee # ############################################### #empty node1, send some small coins from node0 to node1 self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True) self.sync_all() self.nodes[0].generate(1) self.sync_all() for i in range(0, 20): self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) self.sync_all() self.nodes[0].generate(1) self.sync_all() #fund a tx with ~20 small inputs inputs = [] outputs = { self.nodes[0].getnewaddress(): 0.15, self.nodes[0].getnewaddress(): 0.04 } rawTx = self.nodes[1].createrawtransaction(inputs, outputs) fundedTx = self.nodes[1].fundrawtransaction(rawTx) #create same transaction over sendtoaddress txId = self.nodes[1].sendmany("", outputs) signedFee = self.nodes[1].getrawmempool(True)[txId]['fee'] #compare fee feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee) assert (feeDelta >= 0 and feeDelta <= feeTolerance * 19) #~19 inputs ############################################# # multiple (~19) inputs tx test | sign/send # ############################################# #again, empty node1, send some small coins from node0 to node1 self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True) self.sync_all() self.nodes[0].generate(1) self.sync_all() for i in range(0, 20): self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01) self.sync_all() self.nodes[0].generate(1) self.sync_all() #fund a tx with ~20 small inputs oldBalance = self.nodes[0].getbalance() inputs = [] outputs = { self.nodes[0].getnewaddress(): 0.15, self.nodes[0].getnewaddress(): 0.04 } rawTx = self.nodes[1].createrawtransaction(inputs, outputs) fundedTx = self.nodes[1].fundrawtransaction(rawTx) fundedAndSignedTx = self.nodes[1].signrawtransaction(fundedTx['hex']) txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex']) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(oldBalance + Decimal('97.19000000'), self.nodes[0].getbalance()) #0.19+block reward ##################################################### # test fundrawtransaction with OP_RETURN and no vin # ##################################################### rawtx = "0100000000010000000000000000066a047465737400000000" dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(len(dec_tx['vin']), 0) assert_equal(len(dec_tx['vout']), 1) rawtxfund = self.nodes[2].fundrawtransaction(rawtx) dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) assert_greater_than(len(dec_tx['vin']), 0) # at least one vin assert_equal(len(dec_tx['vout']), 2) # one change output added ################################################## # test a fundrawtransaction using only watchonly # ################################################## inputs = [] outputs = {self.nodes[2].getnewaddress(): watchonly_amount / 2} rawtx = self.nodes[3].createrawtransaction(inputs, outputs) result = self.nodes[3].fundrawtransaction(rawtx, True) res_dec = self.nodes[0].decoderawtransaction(result["hex"]) assert_equal(len(res_dec["vin"]), 1) assert_equal(res_dec["vin"][0]["txid"], watchonly_txid) assert_equal("fee" in result.keys(), True) assert_greater_than(result["changepos"], -1) ############################################################### # test fundrawtransaction using the entirety of watched funds # ############################################################### inputs = [] outputs = {self.nodes[2].getnewaddress(): watchonly_amount} rawtx = self.nodes[3].createrawtransaction(inputs, outputs) result = self.nodes[3].fundrawtransaction(rawtx, True) res_dec = self.nodes[0].decoderawtransaction(result["hex"]) assert_equal(len(res_dec["vin"]), 2) assert (res_dec["vin"][0]["txid"] == watchonly_txid or res_dec["vin"][1]["txid"] == watchonly_txid) assert_greater_than(result["fee"], 0) assert_greater_than(result["changepos"], -1) assert_equal( result["fee"] + res_dec["vout"][result["changepos"]]["value"], watchonly_amount / 10) signedtx = self.nodes[3].signrawtransaction(result["hex"]) assert (not signedtx["complete"]) signedtx = self.nodes[0].signrawtransaction(signedtx["hex"]) assert (signedtx["complete"]) self.nodes[0].sendrawtransaction(signedtx["hex"])
def run_test(self): mc_node1 = self.nodes[0] mc_node2 = self.nodes[1] sc_node1 = self.sc_nodes[0] # Synchronize mc_node1 and mc_node2 self.sync_all() # Generate 1 SC block without any MC block info scblock_id0 = generate_next_blocks(sc_node1, "first node", 1)[0] # Verify that SC block has no MC headers, ref data, ommers check_mcheaders_amount(0, scblock_id0, sc_node1) check_mcreferencedata_amount(0, scblock_id0, sc_node1) check_ommers_amount(0, scblock_id0, sc_node1) # Generate 1 MC block on the first MC node mcblock_hash1 = mc_node1.generate(1)[0] # Synchronize mc_node1 and mc_node2, then disconnect them. self.sync_all() disconnect_nodes_bi(self.nodes, 0, 1) # Generate 1 more MC block on the first MC node mcblock_hash2 = mc_node1.generate(1)[0] # Generate 1 SC block, that should put 2 MC blocks inside # SC block contains MC `mcblock_hash1` that is common for MC Nodes 1,2 and `mcblock_hash2` that is known only by MC Node 1. scblock_id1 = generate_next_blocks(sc_node1, "first node", 1)[0] check_scparent(scblock_id0, scblock_id1, sc_node1) # Verify that SC block contains MC block as a MainchainReference check_mcheaders_amount(2, scblock_id1, sc_node1) check_mcreferencedata_amount(2, scblock_id1, sc_node1) check_mcreference_presence(mcblock_hash1, scblock_id1, sc_node1) check_mcreference_presence(mcblock_hash2, scblock_id1, sc_node1) check_ommers_amount(0, scblock_id1, sc_node1) # Generate another 2 MC blocks on the second MC node fork_mcblock_hash1 = mc_node2.generate(1)[0] fork_mcblock_hash2 = mc_node2.generate(1)[0] # Connect and synchronize MC node 1 to MC node 2 connect_nodes_bi(self.nodes, 0, 1) self.sync_all() # MC Node 1 should replace mcblock_hash2 Tip with [fork_mcblock_hash1, fork_mcblock_hash2] assert_equal(fork_mcblock_hash2, mc_node1.getbestblockhash()) # Generate 1 SC block # SC block must contains `mcblock_hash1` again and add fork_mcblock_hash1,2 # Ommered block also contains common `mcblock_hash1`, but moreover an orphaned `mcblock_hash2` scblock_id2 = generate_next_blocks(sc_node1, "first node", 1)[0] check_scparent(scblock_id0, scblock_id2, sc_node1) # Verify that SC block contains newly created MC blocks as a MainchainHeaders and no MainchainRefData check_mcheaders_amount(3, scblock_id2, sc_node1) check_mcreferencedata_amount(0, scblock_id2, sc_node1) check_mcheader_presence(mcblock_hash1, scblock_id2, sc_node1) check_mcheader_presence(fork_mcblock_hash1, scblock_id2, sc_node1) check_mcheader_presence(fork_mcblock_hash2, scblock_id2, sc_node1) # Verify that SC block contains 1 Ommer with 1 MainchainHeader check_ommers_amount(1, scblock_id2, sc_node1) check_ommers_cumulative_score(1, scblock_id2, sc_node1) check_ommer(scblock_id1, [mcblock_hash1, mcblock_hash2], scblock_id2, sc_node1)