def run_test(self): self.nodes[0].generate(3) stop_node(self.nodes[0], 0) wait_bitcoinds() self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug", "-reindex", "-checkblockindex=1"]) assert_equal(self.nodes[0].getblockcount(), 3) print "Success"
def run_test(self): blockhashes = [] print("Mining blocks...") for _ in range(8): blockhashes.extend(self.nodes[0].generate(1)) time.sleep(1) self.sync_all() times = [self.nodes[1].getblock(b)['time'] for b in blockhashes] assert_equal(blockhashes, self.nodes[1].getblockhashes(times[0] + 100, 0)) # test various ranges; the api returns blocks have times LESS THAN # 'high' (first argument), not less than or equal, hence the +1 assert_equal(blockhashes[0:8], self.nodes[1].getblockhashes(times[8 - 1] + 1, times[0])) assert_equal(blockhashes[2:6], self.nodes[1].getblockhashes(times[6 - 1] + 1, times[2])) assert_equal(blockhashes[5:8], self.nodes[1].getblockhashes(times[8 - 1] + 1, times[5])) assert_equal(blockhashes[6:7], self.nodes[1].getblockhashes(times[7 - 1] + 1, times[6])) assert_equal(blockhashes[4:6], self.nodes[1].getblockhashes(times[6 - 1] + 1, times[4])) assert_equal(blockhashes[1:1], self.nodes[1].getblockhashes(times[1 - 1] + 1, times[1])) # Restart all nodes to ensure indices are saved to disk and recovered stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # generating multiple blocks within the same second should # result in timestamp index entries with unique times # (not realistic but there is logic to ensure this) blockhashes = self.nodes[0].generate(10) self.sync_all() firsttime = self.nodes[1].getblock(blockhashes[0])['time'] assert_equal( blockhashes, self.nodes[1].getblockhashes(firsttime + 10 + 1, firsttime)) # the api can also return 'logical' times, which is the key of the # timestamp index (the content being blockhash). Logical times are # block times when possible, but since keys must be unique, and the # previous 10 block were generated in much less than 10 seconds, # each logical time should be one greater than the previous. results = self.nodes[1].getblockhashes(firsttime + 10 + 1, firsttime, {'logicalTimes': True}) ltimes = [r['logicalts'] for r in results] assert_equal(ltimes, list(range(firsttime, firsttime + 10))) # there's also a flag to exclude orphaned blocks; results should # be the same in this test assert_equal( results, self.nodes[1].getblockhashes(firsttime + 10 + 1, firsttime, { 'logicalTimes': True, 'noOrphans': True }))
def run_test(self): self.nodes[0].generate(3) stop_node(self.nodes[0], 0) wait_bitcoinds() self.nodes[0] = start_node( 0, self.options.tmpdir, ["-debug", "-reindex", "-checkblockindex=1"]) assert_equal(self.nodes[0].getblockcount(), 3) print("Success")
def run_test(self): #do some -walletbroadcast tests stop_nodes(self.nodes) wait_bitcoinds() self.nodes = start_nodes( 3, self.options.tmpdir, [["-walletbroadcast=0"], ["-walletbroadcast=0"], ["-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() txIdNotBroadcasted = self.nodes[0].sendtoaddress( self.nodes[2].getnewaddress(), 2) txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) self.sync_all() self.nodes[1].generate(1) #mine a block, tx should not be in there self.sync_all() assert_equal( self.nodes[2].getbalance(), Decimal('2425.00000000') ) #default should not be changed because tx was not broadcasted assert_equal( self.nodes[2].getbalance("*"), Decimal('2425.00000000') ) #default 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(txObjNotBroadcasted['hex']) self.sync_all() self.nodes[1].generate(1) self.sync_all() txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) assert_equal(self.nodes[2].getbalance(), Decimal('2427.00000000')) #should not be assert_equal(self.nodes[2].getbalance("*"), Decimal('2427.00000000')) #should not be #create another tx txIdNotBroadcasted = self.nodes[0].sendtoaddress( self.nodes[2].getnewaddress(), 2) #restart the nodes with -walletbroadcast=1 stop_nodes(self.nodes) wait_bitcoinds() self.nodes = start_nodes(3, self.options.tmpdir) 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) self.nodes[0].generate(1) sync_blocks(self.nodes) # tx should be added to balance because after restarting the nodes tx should be broadcast assert_equal(self.nodes[2].getbalance(), Decimal('2429.00000000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('2429.00000000'))
def reindex(self, justchainstate=False): self.nodes[0].generate(3) blockcount = self.nodes[0].getblockcount() stop_node(self.nodes[0], 0) wait_bitcoinds() self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug", "-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]) while self.nodes[0].getblockcount() < blockcount: time.sleep(0.1) assert_equal(self.nodes[0].getblockcount(), blockcount) print("Success")
def main(): import optparse parser = optparse.OptionParser(usage="%prog [options]") parser.add_option( "--nocleanup", dest="nocleanup", default=False, action="store_true", help="Leave bitcoinds and test.* datadir on exit or error") parser.add_option( "--srcdir", dest="srcdir", default="../../src", help= "Source directory containing bitcoind/bitcoin-cli (default: %default%)" ) parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"), help="Root directory for datadirs") (options, args) = parser.parse_args() os.environ['PATH'] = options.srcdir + ":" + os.environ['PATH'] check_json_precision() success = False try: print("Initializing test directory " + options.tmpdir) if not os.path.isdir(options.tmpdir): os.makedirs(options.tmpdir) initialize_chain(options.tmpdir) run_test(options.tmpdir) success = True except AssertionError as e: print("Assertion failed: " + e.message) except Exception as e: print("Unexpected exception caught during testing: " + str(e)) traceback.print_tb(sys.exc_info()[2]) if not options.nocleanup: print("Cleaning up") wait_bitcoinds() shutil.rmtree(options.tmpdir) if success: print("Tests successful") sys.exit(0) else: print("Failed") sys.exit(1)
def main(): import optparse parser = optparse.OptionParser(usage="%prog [options]") parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true", help="Leave bitcoinds and test.* datadir on exit or error") # ZEN_MOD_START parser.add_option("--srcdir", dest="srcdir", default="../../src", help="Source directory containing zend/zen-cli (default: %default%)") # ZEN_MOD_END parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"), help="Root directory for datadirs") (options, args) = parser.parse_args() os.environ['PATH'] = options.srcdir+":"+os.environ['PATH'] check_json_precision() success = False nodes = [] try: print("Initializing test directory "+options.tmpdir) if not os.path.isdir(options.tmpdir): os.makedirs(options.tmpdir) initialize_chain(options.tmpdir) nodes = start_nodes(1, options.tmpdir, extra_args=[['-experimentalfeatures', '-developerencryptwallet']]) run_test(nodes, options.tmpdir) success = True except AssertionError as e: print("Assertion failed: "+e.message) except JSONRPCException as e: print("JSONRPC error: "+e.error['message']) traceback.print_tb(sys.exc_info()[2]) except Exception as e: print("Unexpected exception caught during testing: "+str(sys.exc_info()[0])) traceback.print_tb(sys.exc_info()[2]) if not options.nocleanup: print("Cleaning up") stop_nodes(nodes) wait_bitcoinds() shutil.rmtree(options.tmpdir) if success: print("Tests successful") sys.exit(0) else: print("Failed") sys.exit(1)
def main(): import optparse parser = optparse.OptionParser(usage="%prog [options]") parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true", help="Leave bitcoinds and test.* datadir on exit or error") parser.add_option("--srcdir", dest="srcdir", default="../../src", help="Source directory containing bitcoind/bitcoin-cli (default: %default%)") parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"), help="Root directory for datadirs") (options, args) = parser.parse_args() os.environ['PATH'] = options.srcdir+":"+os.environ['PATH'] check_json_precision() success = False nodes = [] try: print("Initializing test directory "+options.tmpdir) if not os.path.isdir(options.tmpdir): os.makedirs(options.tmpdir) initialize_chain(options.tmpdir) nodes = start_nodes(1, options.tmpdir, extra_args=[['-experimentalfeatures', '-developerencryptwallet']]) run_test(nodes, options.tmpdir) success = True except AssertionError as e: print("Assertion failed: "+e.message) except JSONRPCException as e: print("JSONRPC error: "+e.error['message']) traceback.print_tb(sys.exc_info()[2]) except Exception as e: print("Unexpected exception caught during testing: "+str(sys.exc_info()[0])) traceback.print_tb(sys.exc_info()[2]) if not options.nocleanup: print("Cleaning up") stop_nodes(nodes) wait_bitcoinds() shutil.rmtree(options.tmpdir) if success: print("Tests successful") sys.exit(0) else: print("Failed") sys.exit(1)
def run_allowip_test(self, allow_ips, rpchost, rpcport): ''' Start a node with rpcwallow IP, and request getinfo at a non-localhost IP. ''' base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips] self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [base_args]) try: # connect to node through non-loopback interface node = get_rpc_proxy(rpc_url(0, "%s:%d" % (rpchost, rpcport)), 0) node.getinfo() finally: node = None # make sure connection will be garbage collected and closed stop_nodes(self.nodes) wait_bitcoinds()
def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport): ''' Start a node with rpcwallow IP, and request getinfo at a non-localhost IP. ''' base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips] nodes = start_nodes(1, tmpdir, [base_args]) try: # connect to node through non-loopback interface url = "http://*****:*****@%s:%d" % (rpchost, rpcport,) node = get_rpc_proxy(url, 1) node.getinfo() finally: node = None # make sure connection will be garbage collected and closed stop_nodes(nodes) wait_bitcoinds()
def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport): ''' Start a node with rpcwallow IP, and request getinfo at a non-localhost IP. ''' base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips] nodes = start_nodes(1, tmpdir, [base_args]) try: # connect to node through non-loopback interface url = "http://*****:*****@%s:%d" % (rpchost, rpcport,) node = AuthServiceProxy(url) node.getinfo() finally: node = None # make sure connection will be garbage collected and closed stop_nodes(nodes) wait_bitcoinds()
def run_bind_test(tmpdir, allow_ips, connect_to, addresses, expected): ''' Start a node with requested rpcallowip and rpcbind parameters, then try to connect, and check if the set of bound addresses matches the expected set. ''' expected = [(addr_to_hex(addr), port) for (addr, port) in expected] base_args = ['-disablewallet', '-nolisten'] if allow_ips: base_args += ['-rpcallowip=' + x for x in allow_ips] binds = ['-rpcbind=' + addr for addr in addresses] nodes = start_nodes(1, tmpdir, [base_args + binds], connect_to) try: pid = bitcoind_processes[0].pid assert_equal(set(get_bind_addrs(pid)), set(expected)) finally: stop_nodes(nodes) wait_bitcoinds()
def run_bind_test(tmpdir, allow_ips, connect_to, addresses, expected): ''' Start a node with requested rpcallowip and rpcbind parameters, then try to connect, and check if the set of bound addresses matches the expected set. ''' expected = [(addr_to_hex(addr), port) for (addr, port) in expected] base_args = ['-disablewallet', '-nolisten'] if allow_ips: base_args += ['-rpcallowip=' + x for x in allow_ips] binds = ['-rpcbind='+addr for addr in addresses] nodes = start_nodes(1, tmpdir, [base_args + binds], connect_to) try: pid = bitcoind_processes[0].pid assert_equal(set(get_bind_addrs(pid)), set(expected)) finally: stop_nodes(nodes) wait_bitcoinds()
def run_test(self): # z_getnewaddress is deprecated, but enabled by default so it should succeed self.nodes[0].z_getnewaddress() # zcrawkeygen is deprecated, and not enabled by default so it should fail errorString = '' try: self.nodes[0].zcrawkeygen() except JSONRPCException as e: errorString = e.error['message'] assert "DEPRECATED" in errorString # restart with a specific selection of deprecated methods enabled stop_nodes(self.nodes) wait_bitcoinds() self.setup_network_internal(["getnewaddress", "zcrawkeygen"]) # z_getnewaddress is enabled by default, so it should succeed self.nodes[0].z_getnewaddress() # getnewaddress and zcrawkeygen are enabled so they should succeed. self.nodes[0].getnewaddress() self.nodes[0].zcrawkeygen() # restart with no deprecated methods enabled stop_nodes(self.nodes) wait_bitcoinds() self.setup_network_internal(["none"]) errorString = '' try: self.nodes[0].z_getnewaddress() except JSONRPCException as e: errorString = e.error['message'] assert "DEPRECATED" in errorString errorString = '' try: self.nodes[0].zcrawkeygen() except JSONRPCException as e: errorString = e.error['message'] assert "DEPRECATED" in errorString
def stop_nodes(self): stop_nodes(self.nodes) wait_bitcoinds()
def run_test(self): print("Mining blocks...") min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee'] # 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 = max(2 * min_relay_tx_fee / 1000, Decimal("0.00000001")) 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 = Decimal(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 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_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(self.num_nodes, 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('11.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('10.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): # Sanity-check the test harness self.nodes[0].generate(200) assert_equal(self.nodes[0].getblockcount(), 200) self.sync_all() # Verify Sapling address is persisted in wallet sapling_addr = self.nodes[0].z_getnewaddress('sapling') # Make sure the node has the addresss addresses = self.nodes[0].z_listaddresses() assert_true(sapling_addr in addresses, "Should contain address before restart") # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Make sure we still have the address after restarting addresses = self.nodes[0].z_listaddresses() assert_true(sapling_addr in addresses, "Should contain address after restart") # Node 0 shields funds to Sapling address taddr0 = get_coinbase_address(self.nodes[0]) recipients = [] recipients.append({"address": sapling_addr, "amount": Decimal('20')}) myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify shielded balance assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('20')) # Verify size of shielded pools pools = self.nodes[0].getblockchaininfo()['valuePools'] assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Verify size of shielded pools pools = self.nodes[0].getblockchaininfo()['valuePools'] assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling # Node 0 sends some shielded funds to Node 1 dest_addr = self.nodes[1].z_getnewaddress('sapling') recipients = [] recipients.append({"address": dest_addr, "amount": Decimal('15')}) myopid = self.nodes[0].z_sendmany(sapling_addr, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify balances assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15')) # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Verify balances assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15')) # Verify importing a spending key will update and persist the nullifiers and witnesses correctly sk0 = self.nodes[0].z_exportkey(sapling_addr) self.nodes[2].z_importkey(sk0, "yes") assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5')) # Verify importing a viewing key will update and persist the nullifiers and witnesses correctly extfvk0 = self.nodes[0].z_exportviewingkey(sapling_addr) self.nodes[3].z_importviewingkey(extfvk0, "yes") assert_equal(self.nodes[3].z_getbalance(sapling_addr), Decimal('5')) assert_equal(self.nodes[3].z_gettotalbalance()['private'], '0.00') assert_equal(self.nodes[3].z_gettotalbalance(1, True)['private'], '5.00') # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Verify nullifiers persisted correctly by checking balance # Prior to PR #3590, there will be an error as spent notes are considered unspent: # Assertion failed: expected: <25.00000000> but was: <5> assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5')) assert_equal(self.nodes[3].z_getbalance(sapling_addr), Decimal('5')) assert_equal(self.nodes[3].z_gettotalbalance()['private'], '0.00') assert_equal(self.nodes[3].z_gettotalbalance(1, True)['private'], '5.00') # Verity witnesses persisted correctly by sending shielded funds recipients = [] recipients.append({"address": dest_addr, "amount": Decimal('1')}) myopid = self.nodes[2].z_sendmany(sapling_addr, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[2], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify balances assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('4')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('16'))
def run_test(self): ''' (3) / (0)--(1) \ (2) Simulate multiple split for having more forks on different blocks ''' blocks = [] blocks.append(self.nodes[0].getblockhash(0)) print("\n\nGenesis block is:\n" + blocks[0]) s = "Node 1 generates a block" print("\n" + s) self.mark_logs(s) blocks.extend(self.nodes[1].generate(1)) # block height 1 print blocks[len(blocks) - 1] self.sync_all() # Node(0): [0]->[1] # | # | # Node(1): [0]->[1] # /\ # / \ # + Node(2): [0]->[1] # | # Node(3): [0]->[1] print("\n\nSplit nodes (1)----x x---(3)") # self.split_network_2() #------------------------------------------------- disconnect_nodes(self.nodes[1], 3) disconnect_nodes(self.nodes[3], 1) # connect_nodes_bi(self.nodes, 1, 2) # connect_nodes_bi(self.nodes, 0, 1) #------------------------------------------------- time.sleep(2) print("The network is split") self.mark_logs("The network is split 2") s = "Node 1 generates a block" print("\n" + s) self.mark_logs(s) blocks.extend(self.nodes[1].generate(1)) # block height 2 bl2 = blocks[2] print bl2 time.sleep(2) # Node(0): [0]->[1]->[2h] # | # | # Node(1): [0]->[1]->[2h] # \ # \ # Node(2): [0]->[1]->[2h] # # Node(3): [0]->[1] print("\n\nSplit nodes (1)----x x---(2)") # self.split_network() #------------------------------------------------- stop_nodes(self.nodes) wait_bitcoinds() self.nodes = self.setup_nodes() connect_nodes_bi(self.nodes, 0, 1) #------------------------------------------------- self.is_network_split = True time.sleep(2) print("The network is split") self.mark_logs("The network is split") print("\nNode1 generating 7 honest block") blocks.extend(self.nodes[1].generate(7)) # block height 3 bl3 = blocks[3] print bl3 time.sleep(2) print("\nNode3 generating 8 mal block") blocks.extend(self.nodes[3].generate(8)) # block height 2M for i in range(10, 18): print blocks[i] time.sleep(2) # raw_input("press enter to go on..") print("\nNode2 generating 8 mal block") blocks.extend(self.nodes[2].generate(8)) # block height 2m for i in range(18, 26): print blocks[i] time.sleep(2) # Node(0): [0]->[1]->[2h]->[3h] # | # | # Node(1): [0]->[1]->[2h]->[3h] # # # Node(2): [0]->[1]->[2h]->[3m] # # Node(3): [0]->[1]->[2M] # raw_input("press enter to go on..") for i in range(0, 4): self.dump_ordered_tips(self.nodes[i].getchaintips()) print "---" print("\n\nJoin nodes (1)--(2)") # raw_input("press enter to join the netorks..") self.mark_logs("Joining network") # self.join_network() #------------------------------------------------- stop_nodes(self.nodes) wait_bitcoinds() self.nodes = self.setup_nodes() connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) #------------------------------------------------- time.sleep(10) print("\nNetwork joined") self.mark_logs("Network joined") for i in range(0, 4): self.dump_ordered_tips(self.nodes[i].getchaintips()) print "---" # Node(0): [0]->[1]->[2h]->[3h] **Active** # | # | # | # Node(1): [0]->[1]->[2h]->[3h] **Active** # \ \ # \ +->[3m] # \ # Node(2): [0]->[1]->[2h]->[3m] **Active** # \ # +->[3h] # # Node(3): [0]->[1]->[2M] # raw_input("press enter to go on..") try: print "\nChecking finality of block[", bl2, "]" print " Node0 has: %d" % self.nodes[0].getblockfinalityindex(bl2) print " Node1 has: %d" % self.nodes[1].getblockfinalityindex(bl2) print "\nChecking finality of block[", bl3, "]" print " Node0 has: %d" % self.nodes[0].getblockfinalityindex(bl3) print " Node1 has: %d" % self.nodes[1].getblockfinalityindex(bl3) except JSONRPCException, e: errorString = e.error['message'] print errorString
def run_test (self): print "Mining blocks..." self.nodes[0].generate(4) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[1].generate(102) self.sync_all() assert_equal(self.nodes[0].getbalance(), 40) assert_equal(self.nodes[1].getbalance(), 20) assert_equal(self.nodes[2].getbalance(), 0) # At this point in time, commitment tree is the empty root # Node 0 creates a joinsplit transaction mytaddr0 = get_coinbase_address(self.nodes[0]) myzaddr0 = self.nodes[0].z_getnewaddress('sprout') recipients = [] recipients.append({"address":myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001')}) myopid = self.nodes[0].z_sendmany(mytaddr0, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) # Sync up mempools and mine the transaction. All nodes have the same anchor. self.sync_all() self.nodes[0].generate(1) self.sync_all() # Stop nodes. stop_nodes(self.nodes) wait_bitcoinds() # Relaunch nodes and partition network into two: # A: node 0 # B: node 1, 2 self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-regtestprotectcoinbase', '-debug=zrpc']] * 3 ) connect_nodes_bi(self.nodes,1,2) # Partition B, node 1 mines an empty block self.nodes[1].generate(1) # Partition A, node 0 creates a joinsplit transaction recipients = [] recipients.append({"address":myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001')}) myopid = self.nodes[0].z_sendmany(mytaddr0, recipients) txid = wait_and_assert_operationid_status(self.nodes[0], myopid) rawhex = self.nodes[0].getrawtransaction(txid) # Partition A, node 0 mines a block with the transaction self.nodes[0].generate(1) # Partition B, node 1 mines the same joinsplit transaction txid2 = self.nodes[1].sendrawtransaction(rawhex) assert_equal(txid, txid2) self.nodes[1].generate(1) # Check that Partition B is one block ahead and that they have different tips assert_equal(self.nodes[0].getblockcount() + 1, self.nodes[1].getblockcount()) assert( self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash()) # Shut down all nodes so any in-memory state is saved to disk stop_nodes(self.nodes) wait_bitcoinds() # Relaunch nodes and reconnect the entire network self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-regtestprotectcoinbase', '-debug=zrpc']] * 3 ) connect_nodes_bi(self.nodes,0, 1) connect_nodes_bi(self.nodes,1, 2) connect_nodes_bi(self.nodes,0, 2) # Mine a new block and let it propagate self.nodes[1].generate(1) # Due to a bug in v1.0.0-1.0.3, node 0 will die with a tree root assertion, so sync_all() will throw an exception. self.sync_all() # v1.0.4 will reach here safely assert_equal( self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash()) assert_equal( self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash())
class headers(BitcoinTestFramework): alert_filename = None def setup_chain(self, split=False): print("Initializing test directory " + self.options.tmpdir) initialize_chain_clean(self.options.tmpdir, NUMB_OF_NODES) self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") with open(self.alert_filename, 'w'): pass # Just open then close to create zero-length file def setup_network(self, split=False, minAge=FINALITY_MIN_AGE): self.nodes = [] self.nodes = start_nodes( NUMB_OF_NODES, self.options.tmpdir, extra_args=[[ "-debug=cbh", "-cbhsafedepth=" + str(FINALITY_SAFE_DEPTH), "-cbhminage=" + str(minAge) ], [ "-debug=cbh", "-cbhsafedepth=" + str(FINALITY_SAFE_DEPTH), "-cbhminage=" + str(minAge) ], [ "-debug=cbh", "-cbhsafedepth=" + str(FINALITY_SAFE_DEPTH), "-cbhminage=" + str(minAge) ], [ "-debug=cbh", "-cbhsafedepth=" + str(FINALITY_SAFE_DEPTH), "-cbhminage=" + str(minAge) ]]) if not split: # 2 and 3 are joint only if split==false connect_nodes_bi(self.nodes, 2, 3) connect_nodes_bi(self.nodes, 3, 2) sync_blocks(self.nodes[2:NUMB_OF_NODES]) sync_mempools(self.nodes[2:NUMB_OF_NODES]) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 0) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 2, 1) self.is_network_split = split self.sync_all() def disconnect_nodes(self, from_connection, node_num): ip_port = "127.0.0.1:" + str(p2p_port(node_num)) from_connection.disconnectnode(ip_port) # poll until version handshake complete to avoid race conditions # with transaction relaying while any(peer['version'] == 0 for peer in from_connection.getpeerinfo()): time.sleep(0.1) def split_network(self): # Split the network of 4 nodes into nodes 0-1-2 and 3. assert not self.is_network_split self.disconnect_nodes(self.nodes[2], 3) self.disconnect_nodes(self.nodes[3], 2) self.is_network_split = True def join_network(self): #Join the (previously split) network pieces together: 0-1-2-3 assert self.is_network_split connect_nodes_bi(self.nodes, 2, 3) connect_nodes_bi(self.nodes, 3, 2) # self.sync_all() sync_blocks(self.nodes, 1, False, 5) self.is_network_split = False def mark_logs(self, msg): self.nodes[0].dbg_log(msg) self.nodes[1].dbg_log(msg) self.nodes[2].dbg_log(msg) self.nodes[3].dbg_log(msg) def swap_bytes(self, input_buf): return codecs.encode(codecs.decode(input_buf, 'hex')[::-1], 'hex').decode() def is_in_block(self, tx, bhash, node_idx=0): blk_txs = self.nodes[node_idx].getblock(bhash, True)['tx'] for i in blk_txs: if (i == tx): return True return False def is_in_mempool(self, tx, node_idx=0): mempool = self.nodes[node_idx].getrawmempool() for i in mempool: if (i == tx): return True return False def run_test(self): blocks = [] self.bl_count = 0 blocks.append(self.nodes[1].getblockhash(0)) small_target_h = 3 s = " Node1 generates %d blocks" % (CBH_DELTA + small_target_h) print(s) print self.mark_logs(s) blocks.extend(self.nodes[1].generate(CBH_DELTA + small_target_h)) self.sync_all() #------------------------------------------------------------------------------------------------------- print "Trying to send a tx with a scriptPubKey referencing a block too recent..." #------------------------------------------------------------------------------------------------------- # Create a tx having in its scriptPubKey a custom referenced block in the CHECKBLOCKATHEIGHT part # select necessary utxos for doing the PAYMENT usp = self.nodes[1].listunspent() PAYMENT = Decimal('1.0') FEE = Decimal('0.00005') amount = Decimal('0') inputs = [] print " Node1 sends %f coins to Node2" % PAYMENT for x in usp: amount += Decimal(x['amount']) inputs.append({"txid": x['txid'], "vout": x['vout']}) if amount >= PAYMENT + FEE: break outputs = { self.nodes[1].getnewaddress(): (Decimal(amount) - PAYMENT - FEE), self.nodes[2].getnewaddress(): PAYMENT } rawTx = self.nodes[1].createrawtransaction(inputs, outputs) # build an object from the raw tx in order to be able to modify it tx_01 = CTransaction() f = cStringIO.StringIO(unhexlify(rawTx)) tx_01.deserialize(f) decodedScriptOrig = self.nodes[1].decodescript( binascii.hexlify(tx_01.vout[1].scriptPubKey)) scriptOrigAsm = decodedScriptOrig['asm'] # print "Original scriptPubKey asm 1: ", scriptOrigAsm # print # store the hashed script, it is reused params = scriptOrigAsm.split() hash_script = hex_str_to_bytes(params[2]) # new referenced block height modTargetHeigth = CBH_DELTA + small_target_h - FINALITY_MIN_AGE + 5 # new referenced block hash modTargetHash = hex_str_to_bytes( self.swap_bytes(blocks[modTargetHeigth])) # build modified script modScriptPubKey = CScript([ OP_DUP, OP_HASH160, hash_script, OP_EQUALVERIFY, OP_CHECKSIG, modTargetHash, modTargetHeigth, OP_CHECKBLOCKATHEIGHT ]) tx_01.vout[1].scriptPubKey = modScriptPubKey tx_01.rehash() decodedScriptMod = self.nodes[1].decodescript( binascii.hexlify(tx_01.vout[1].scriptPubKey)) print " Modified scriptPubKey in tx 1: ", decodedScriptMod['asm'] signedRawTx = self.nodes[1].signrawtransaction(ToHex(tx_01)) h = self.nodes[1].getblockcount() assert_greater_than(FINALITY_MIN_AGE, h - modTargetHeigth) #raw_input("\npress enter to go on ..") try: txid = self.nodes[1].sendrawtransaction(signedRawTx['hex']) print " Tx sent: ", txid # should fail, therefore force test failure assert_equal(True, False) except JSONRPCException, e: print " ==> tx has been rejected as expected:" print " referenced block height=%d, chainActive.height=%d, minimumAge=%d" % ( modTargetHeigth, h, FINALITY_MIN_AGE) print #------------------------------------------------------------------------------------------------------- print "Check that small digit height for referenced blocks works in scriptPubKey" #------------------------------------------------------------------------------------------------------- # check that small height works for 'check block at height' in script #-------------------------------------------------------------------- node1_pay = Decimal('0.5') s = " Node1 sends %f coins to Node3 for checking script in tx" % node1_pay print s self.mark_logs(s) tx1 = self.nodes[1].sendtoaddress(self.nodes[3].getnewaddress(), node1_pay) print " ==> tx sent: ", tx1 sync_mempools(self.nodes[0:4]) assert_equal(self.is_in_mempool(tx1), True) script = self.nodes[1].getrawtransaction( tx1, 1)['vout'][0]['scriptPubKey']['asm'] tokens = script.split() small_h = int(tokens[6]) small_h_hash = self.swap_bytes(tokens[5]) print " ScriptPubKey: ", script assert_equal(small_h, small_target_h) assert_equal(small_h_hash, blocks[int(small_h)]) print(" Node1 generating 1 honest block") blocks.extend(self.nodes[1].generate(1)) self.sync_all() print " | Node0 balance: ", self.nodes[0].getbalance() print " | Node1 balance: ", self.nodes[1].getbalance() print " | Node2 balance: ", self.nodes[2].getbalance() print " | Node3 balance: ", self.nodes[3].getbalance() # check tx is no more in mempool assert_equal(self.is_in_mempool(tx1), False) # check tx is in the block just mined assert_equal(self.is_in_block(tx1, blocks[-1], 3), True) # check the balance is the one expected assert_equal(self.nodes[3].getbalance(), node1_pay) s = " Node3 sends 0.25 coins to Node2 for checking script in tx" print s self.mark_logs(s) tx2 = self.nodes[3].sendtoaddress(self.nodes[2].getnewaddress(), 0.25) print " ==> tx sent: ", tx2 sync_mempools(self.nodes[0:4]) assert_equal(self.is_in_mempool(tx2), True) print(" Node1 generating 1 honest block") blocks.extend(self.nodes[1].generate(1)) self.sync_all() print " | Node0 balance: ", self.nodes[0].getbalance() print " | Node1 balance: ", self.nodes[1].getbalance() print " | Node2 balance: ", self.nodes[2].getbalance() print " | Node3 balance: ", self.nodes[3].getbalance() # check tx is no more in mempool assert_equal(self.is_in_mempool(tx2), False) # check tx is in the block just mined assert_equal(self.is_in_block(tx2, blocks[-1], 1), True) print " ==> OK, small digit height works in scripts:" print #-------------------------------------------------------------------- print "Verify that a legal tx, when the referenced block is reverted, becomes invalid until the necessary depth of the referenced block height has been reached..." print " Restarting network with -cbhminage=0" # restart Nodes and check their balance: node1 does not have 1000 coins but node2 does not have either stop_nodes(self.nodes) wait_bitcoinds() self.setup_network(False, 0) chunks = 305 s = " Node0 generates %d blocks" % chunks print(s) self.mark_logs(s) blocks.extend(self.nodes[0].generate(chunks)) self.sync_all() print " Split network: (0)---(1)---(2) (3)" self.split_network() print " Node0 generating 1 honest block" blocks.extend(self.nodes[0].generate(1)) sync_blocks(self.nodes, 1, False, 5) # self.sync_all() # time.sleep(5) # we will perform on attack aimed at reverting from this block (latest generated) upward hash_attacked = blocks[-1] h_attacked = self.nodes[1].getblockcount() assert hash_attacked == blocks[h_attacked] hash_attacked_swapped = self.swap_bytes(hash_attacked) hex_s = "%04x" % h_attacked h_attacked_swapped = self.swap_bytes(hex_s) h_safe_estimated = h_attacked + FINALITY_SAFE_DEPTH + 1 print " Honest network has current h[%d]" % h_attacked # we will create a transaction whose output will have a CHECKBLOCKATHEIGHT on this block h_checked = h_attacked - CBH_DELTA hex_s = "%04x" % h_checked h_checked_swapped = self.swap_bytes(hex_s) hash_checked = blocks[h_checked] hash_checked_swapped = self.swap_bytes(hash_checked) # select necessary utxos for doing the PAYMENT, there might be a lot of them usp = self.nodes[1].listunspent() PAYMENT = Decimal('1000.0') FEE = Decimal('0.00005') amount = Decimal('0') inputs = [] for x in usp: amount += Decimal(x['amount']) inputs.append({"txid": x['txid'], "vout": x['vout']}) if amount >= PAYMENT + FEE: break print " Creating raw tx referencing the current block %d where Node1 sends %f coins to Node2..." % ( h_attacked, PAYMENT) outputs = { self.nodes[1].getnewaddress(): (Decimal(amount) - PAYMENT - FEE), self.nodes[2].getnewaddress(): PAYMENT } rawTx = self.nodes[1].createrawtransaction(inputs, outputs) # replace hash and h referenced in tx's script with the ones of target block from_buf = str(hash_checked_swapped) + '02' + str(h_checked_swapped) to_buf = str(hash_attacked_swapped) + '02' + str(h_attacked_swapped) rawTxReplaced = rawTx.replace(from_buf, to_buf) # modifying just one vout is enough for tampering the whole tx script = self.nodes[1].decoderawtransaction( rawTx)['vout'][0]['scriptPubKey']['asm'] decodedRep = self.nodes[1].decoderawtransaction(rawTxReplaced) scriptRep = decodedRep['vout'][0]['scriptPubKey']['asm'] print " Changed script in tx" print " from: ", script print " to: ", scriptRep signedRawTx = self.nodes[1].signrawtransaction(rawTx) signedRawTxReplaced = self.nodes[1].signrawtransaction(rawTxReplaced) print " | Node0 balance: ", self.nodes[0].getbalance() print " | Node1 balance: ", self.nodes[1].getbalance() print " | Node2 balance: ", self.nodes[2].getbalance() print " | Node3 balance: ", self.nodes[3].getbalance() amountRep = Decimal('0') changeRep = Decimal('0') nAm = -1 nCh = -1 # get the amount and the change of the tx, they might not be ordered as vout entries for x in decodedRep['vout']: if x['value'] == PAYMENT: amountRep = x['value'] nAm = x['n'] else: changeRep = x['value'] nCh = x['n'] # the tx modified has a script that does not pass the check at referenced block, tx 1000 coins (and also related change) # will be unspendable once the chain is reverted tx_1000 = self.nodes[1].sendrawtransaction(signedRawTxReplaced['hex']) print " ==> tx sent: ", tx_1000 print " amount (vout[%d]): %f" % (nAm, amountRep) print " change (vout[%d]): %f" % (nCh, changeRep) sync_mempools(self.nodes[0:3]) assert_equal(self.is_in_mempool(tx_1000, 1), True) print " OK, tx is in mempool..." print " | Node0 balance: ", self.nodes[0].getbalance() print " | Node1 balance: ", self.nodes[1].getbalance() print " | Node2 balance: ", self.nodes[2].getbalance() print " | Node3 balance: ", self.nodes[3].getbalance() print(" Node0 generating 1 honest block") blocks.extend(self.nodes[0].generate(1)) time.sleep(5) # check tx is no more in mempool assert_equal(self.is_in_mempool(tx_1000, 1), False) # check tx is in the block just mined assert_equal(self.is_in_block(tx_1000, blocks[-1], 1), True) print " OK, tx is not in mempool anymore (it is contained in the block just mined)" print " Block: (%d) %s" % (int( self.nodes[2].getblockcount()), blocks[-1]) print " | Node0 balance: ", self.nodes[0].getbalance() print " | Node1 balance: ", self.nodes[1].getbalance() print " | Node2 balance: ", self.nodes[2].getbalance() print " | Node3 balance: ", self.nodes[3].getbalance() print " Node3 generating 3 malicious blocks thus reverting the honest chain once the ntw is joined!" blocks.extend(self.nodes[3].generate(3)) time.sleep(2) self.join_network() time.sleep(2) print " Network joined: (0)---(1)---(2)---(3)" self.mark_logs("Network joined") # check attacked transaction is back in the mempool of nodes belonging to the honest portion of the joined network assert_equal(self.is_in_mempool(tx_1000, 0), True) assert_equal(self.is_in_mempool(tx_1000, 1), True) assert_equal(self.is_in_mempool(tx_1000, 2), True) assert_equal(self.is_in_mempool(tx_1000, 3), False) print " ==> the block has been reverted, the tx is back in the mempool of the reverted nodes!" print " | Node0 balance: ", self.nodes[0].getbalance() print " | Node1 balance: ", self.nodes[1].getbalance() print " | Node2 balance: ", self.nodes[2].getbalance() print " | Node3 balance: ", self.nodes[3].getbalance() print(" Node0 generating 1 honest block") blocks.extend(self.nodes[0].generate(1)) time.sleep(2) # check tx_1000 is in the block just mined assert_equal(self.is_in_block(tx_1000, blocks[-1], 2), True) print " ==> TX referencing reverted block has been mined in a new block!!" print " Block: (%d) %s" % (int( self.nodes[3].getblockcount()), blocks[-1]) # restart Nodes and check their balance: node1 does not have 1000 coins but node2 does not have either stop_nodes(self.nodes) wait_bitcoinds() self.setup_network(False, 0) print " Balances after node restart:" print " | Node0 balance: ", self.nodes[0].getbalance() print " | Node1 balance: ", self.nodes[1].getbalance() print " | Node2 balance: ", self.nodes[2].getbalance() print " | Node3 balance: ", self.nodes[3].getbalance() print " Node3 generating %d honest blocks more" % ( FINALITY_SAFE_DEPTH - 2) blocks.extend(self.nodes[3].generate(FINALITY_SAFE_DEPTH - 2)) self.sync_all() # if safe depth is set to FINALITY_SAFE_DEPTH, from the previos block on the tx will become valid h_safe = self.nodes[1].getblockcount() assert_equal(h_safe, h_safe_estimated) print " OK, at h[%d] the attacked tx should have been restored, node will have it after a restart" % h_safe node1_bal_before = Decimal(self.nodes[1].getbalance()) node2_bal_before = Decimal(self.nodes[2].getbalance()) print " Balances before node restart:" print " | Node0 balance: ", self.nodes[0].getbalance() print " | Node1 balance: ", self.nodes[1].getbalance() print " | Node2 balance: ", self.nodes[2].getbalance() print " | Node2 balance: ", self.nodes[3].getbalance() # restart Nodes and check their balance, at this point the 1000 coins should be in the wallet of node2 stop_nodes(self.nodes) wait_bitcoinds() self.setup_network(False, 0) node1_bal_after = Decimal(self.nodes[1].getbalance()) node2_bal_after = Decimal(self.nodes[2].getbalance()) print " Balances after node restart:" print " | Node0 balance: ", self.nodes[0].getbalance() print " | Node1 balance: ", self.nodes[1].getbalance() print " | Node2 balance: ", self.nodes[2].getbalance() print " | Node2 balance: ", self.nodes[3].getbalance() # ensure both the amount (to the recipient) and the change (to the sender) have been restored assert_equal(node1_bal_before + changeRep, node1_bal_after) assert_equal(node2_bal_before + amountRep, node2_bal_after)
def run_test(self): # helper functions def getaddresstxids(node_index, addresses, start, end): return self.nodes[node_index].getaddresstxids({ 'addresses': addresses, 'start': start, 'end': end }) def getaddressdeltas(node_index, addresses, start, end, chainInfo=None): params = { 'addresses': addresses, 'start': start, 'end': end, } if chainInfo is not None: params.update({'chainInfo': chainInfo}) return self.nodes[node_index].getaddressdeltas(params) # default received value is the balance value def check_balance(node_index, address, expected_balance, expected_received=None): if isinstance(address, list): bal = self.nodes[node_index].getaddressbalance( {'addresses': address}) else: bal = self.nodes[node_index].getaddressbalance(address) assert_equal(bal['balance'], expected_balance) if expected_received is None: expected_received = expected_balance assert_equal(bal['received'], expected_received) # begin test self.nodes[0].generate(105) self.sync_all() assert_equal(self.nodes[0].getbalance(), 5 * 10) assert_equal(self.nodes[1].getblockcount(), 105) assert_equal(self.nodes[1].getbalance(), 0) # only the oldest 5; subsequent are not yet mature unspent_txids = [u['txid'] for u in self.nodes[0].listunspent()] # Currently our only unspents are coinbase transactions, choose any one tx = self.nodes[0].getrawtransaction(unspent_txids[0], 1) # It just so happens that the first output is the mining reward, # which has type pay-to-public-key-hash, and the second output # is the founders' reward, which has type pay-to-script-hash. addr_p2pkh = tx['vout'][0]['scriptPubKey']['addresses'][0] addr_p2sh = tx['vout'][1]['scriptPubKey']['addresses'][0] # Check that balances from mining are correct (105 blocks mined); in # regtest, all mining rewards from a single call to generate() are sent # to the same pair of addresses. check_balance(1, addr_p2pkh, 105 * 10 * COIN) check_balance(1, addr_p2sh, 105 * 2.5 * COIN) # Multiple address arguments, results are the sum check_balance(1, [addr_p2sh, addr_p2pkh], 105 * 12.5 * COIN) assert_equal(len(self.nodes[1].getaddresstxids(addr_p2pkh)), 105) assert_equal(len(self.nodes[1].getaddresstxids(addr_p2sh)), 105) # test getaddresstxids for lightwalletd assert_equal(len(self.nodes[3].getaddresstxids(addr_p2pkh)), 105) assert_equal(len(self.nodes[3].getaddresstxids(addr_p2sh)), 105) # only the oldest 5 transactions are in the unspent list, # dup addresses are ignored height_txids = getaddresstxids(1, [addr_p2pkh, addr_p2pkh], 1, 5) assert_equal(sorted(height_txids), sorted(unspent_txids)) height_txids = getaddresstxids(1, [addr_p2sh], 1, 5) assert_equal(sorted(height_txids), sorted(unspent_txids)) # each txid should appear only once height_txids = getaddresstxids(1, [addr_p2pkh, addr_p2sh], 1, 5) assert_equal(sorted(height_txids), sorted(unspent_txids)) # do some transfers, make sure balances are good txids_a1 = [] addr1 = self.nodes[1].getnewaddress() expected = 0 expected_deltas = [] # for checking getaddressdeltas (below) for i in range(5): # first transaction happens at height 105, mined in block 106 txid = self.nodes[0].sendtoaddress(addr1, i + 1) txids_a1.append(txid) self.nodes[0].generate(1) self.sync_all() expected += i + 1 expected_deltas.append({ 'height': 106 + i, 'satoshis': (i + 1) * COIN, 'txid': txid, }) check_balance(1, addr1, expected * COIN) assert_equal(sorted(self.nodes[0].getaddresstxids(addr1)), sorted(txids_a1)) assert_equal(sorted(self.nodes[1].getaddresstxids(addr1)), sorted(txids_a1)) # Restart all nodes to ensure indices are saved to disk and recovered stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() bal = self.nodes[1].getaddressbalance(addr1) assert_equal(bal['balance'], expected * COIN) assert_equal(bal['received'], expected * COIN) assert_equal(sorted(self.nodes[0].getaddresstxids(addr1)), sorted(txids_a1)) assert_equal(sorted(self.nodes[1].getaddresstxids(addr1)), sorted(txids_a1)) # Send 3 from addr1, but -- subtlety alert! -- addr1 at this # time has 4 UTXOs, with values 1, 2, 3, 4. Sending value 3 requires # using up the value 4 UTXO, because of the tx fee # (the 3 UTXO isn't quite large enough). # # The txid from sending *from* addr1 is also added to the list of # txids associated with that address (test will verify below). addr2 = self.nodes[2].getnewaddress() txid = self.nodes[1].sendtoaddress(addr2, 3) self.sync_all() # the one tx in the mempool refers to addresses addr1 and addr2, # check that duplicate addresses are processed correctly mempool = self.nodes[0].getaddressmempool( {'addresses': [addr2, addr1, addr2]}) assert_equal(len(mempool), 3) # test getaddressmempool for lightwalletd node mempool = self.nodes[3].getaddressmempool( {'addresses': [addr2, addr1, addr2]}) assert_equal(len(mempool), 3) # addr2 (first arg) assert_equal(mempool[0]['address'], addr2) assert_equal(mempool[0]['satoshis'], 3 * COIN) assert_equal(mempool[0]['txid'], txid) # addr1 (second arg) assert_equal(mempool[1]['address'], addr1) assert_equal(mempool[1]['satoshis'], (-4) * COIN) assert_equal(mempool[1]['txid'], txid) # addr2 (third arg) assert_equal(mempool[2]['address'], addr2) assert_equal(mempool[2]['satoshis'], 3 * COIN) assert_equal(mempool[2]['txid'], txid) # a single address can be specified as a string (not json object) addr1_mempool = self.nodes[0].getaddressmempool(addr1) assert_equal(len(addr1_mempool), 1) # Don't check the timestamp; it's local to the node, and can mismatch # due to propagation delay. del addr1_mempool[0]['timestamp'] for key in addr1_mempool[0].keys(): assert_equal(mempool[1][key], addr1_mempool[0][key]) tx = self.nodes[0].getrawtransaction(txid, 1) assert_equal(tx['vin'][0]['address'], addr1) assert_equal(tx['vin'][0]['value'], 4) assert_equal(tx['vin'][0]['valueSat'], 4 * COIN) txids_a1.append(txid) expected_deltas.append({ 'height': 111, 'satoshis': (-4) * COIN, 'txid': txid, }) self.sync_all() # ensure transaction is included in the next block self.nodes[0].generate(1) self.sync_all() # the send to addr2 tx is now in a mined block, no longer in the mempool mempool = self.nodes[0].getaddressmempool( {'addresses': [addr2, addr1]}) assert_equal(len(mempool), 0) # Test DisconnectBlock() by invalidating the most recent mined block tip = self.nodes[1].getchaintips()[0] for i in range(self.num_nodes): node = self.nodes[i] # the value 4 UTXO is no longer in our balance check_balance(i, addr1, (expected - 4) * COIN, expected * COIN) check_balance(i, addr2, 3 * COIN) assert_equal(node.getblockcount(), 111) node.invalidateblock(tip['hash']) assert_equal(node.getblockcount(), 110) mempool = node.getaddressmempool({'addresses': [addr2, addr1]}) assert_equal(len(mempool), 2) check_balance(i, addr1, expected * COIN) check_balance(i, addr2, 0) # now re-mine the addr1 to addr2 send self.nodes[0].generate(1) self.sync_all() for node in self.nodes: assert_equal(node.getblockcount(), 111) mempool = self.nodes[0].getaddressmempool( {'addresses': [addr2, addr1]}) assert_equal(len(mempool), 0) # the value 4 UTXO is no longer in our balance check_balance(2, addr1, (expected - 4) * COIN, expected * COIN) # Ensure the change from that transaction appears tx = self.nodes[0].getrawtransaction(txid, 1) change_vout = list( filter(lambda v: v['valueZat'] != 3 * COIN, tx['vout'])) change = change_vout[0]['scriptPubKey']['addresses'][0] # test getaddressbalance for node in (2, 3): bal = self.nodes[node].getaddressbalance(change) assert (bal['received'] > 0) # the inequality is due to randomness in the tx fee assert (bal['received'] < (4 - 3) * COIN) assert_equal(bal['received'], bal['balance']) assert_equal(self.nodes[2].getaddresstxids(change), [txid]) # Further checks that limiting by height works # various ranges for i in range(5): height_txids = getaddresstxids(1, [addr1], 106, 106 + i) assert_equal(height_txids, txids_a1[0:i + 1]) height_txids = getaddresstxids(1, [addr1], 1, 108) assert_equal(height_txids, txids_a1[0:3]) # Further check specifying multiple addresses txids_all = list(txids_a1) txids_all += self.nodes[1].getaddresstxids(addr_p2pkh) txids_all += self.nodes[1].getaddresstxids(addr_p2sh) multitxids = self.nodes[1].getaddresstxids( {'addresses': [addr1, addr_p2sh, addr_p2pkh]}) # No dups in return list from getaddresstxids assert_equal(len(multitxids), len(set(multitxids))) # set(txids_all) removes its (expected) duplicates assert_equal(set(multitxids), set(txids_all)) # test getaddressdeltas for node in (1, 3): deltas = self.nodes[node].getaddressdeltas({'addresses': [addr1]}) assert_equal(len(deltas), len(expected_deltas)) for i in range(len(deltas)): assert_equal(deltas[i]['address'], addr1) assert_equal(deltas[i]['height'], expected_deltas[i]['height']) assert_equal(deltas[i]['satoshis'], expected_deltas[i]['satoshis']) assert_equal(deltas[i]['txid'], expected_deltas[i]['txid']) # 106-111 is the full range (also the default) deltas_limited = getaddressdeltas(1, [addr1], 106, 111) assert_equal(deltas_limited, deltas) # only the first element missing deltas_limited = getaddressdeltas(1, [addr1], 107, 111) assert_equal(deltas_limited, deltas[1:]) deltas_limited = getaddressdeltas(1, [addr1], 109, 109) assert_equal(deltas_limited, deltas[3:4]) # the full range (also the default) deltas_info = getaddressdeltas(1, [addr1], 106, 111, chainInfo=True) assert_equal(deltas_info['deltas'], deltas) # check the additional items returned by chainInfo assert_equal(deltas_info['start']['height'], 106) block_hash = self.nodes[1].getblockhash(106) assert_equal(deltas_info['start']['hash'], block_hash) assert_equal(deltas_info['end']['height'], 111) block_hash = self.nodes[1].getblockhash(111) assert_equal(deltas_info['end']['hash'], block_hash) # Test getaddressutxos by comparing results with deltas utxos = self.nodes[3].getaddressutxos(addr1) # The value 4 note was spent, so won't show up in the utxo list, # so for comparison, remove the 4 (and -4 for output) from the # deltas list deltas = self.nodes[1].getaddressdeltas({'addresses': [addr1]}) deltas = list(filter(lambda d: abs(d['satoshis']) != 4 * COIN, deltas)) assert_equal(len(utxos), len(deltas)) for i in range(len(utxos)): assert_equal(utxos[i]['address'], addr1) assert_equal(utxos[i]['height'], deltas[i]['height']) assert_equal(utxos[i]['satoshis'], deltas[i]['satoshis']) assert_equal(utxos[i]['txid'], deltas[i]['txid']) # Check that outputs with the same address in the same tx return one txid # (can't use createrawtransaction() as it combines duplicate addresses) addr = "t2LMJ6Arw9UWBMWvfUr2QLHM4Xd9w53FftS" addressHash = unhexlify("97643ce74b188f4fb6bbbb285e067a969041caf2") scriptPubKey = CScript([OP_HASH160, addressHash, OP_EQUAL]) # Add an unrecognized script type to vout[], a legal script that pays, # but won't modify the addressindex (since the address can't be extracted). # (This extra output has no effect on the rest of the test.) scriptUnknown = CScript( [OP_HASH160, OP_DUP, OP_DROP, addressHash, OP_EQUAL]) unspent = list( filter(lambda u: u['amount'] >= 4, self.nodes[0].listunspent())) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]['txid'], 16), unspent[0]['vout'])) ] tx.vout = [ CTxOut(1 * COIN, scriptPubKey), CTxOut(2 * COIN, scriptPubKey), CTxOut(7 * COIN, scriptUnknown), ] tx = self.nodes[0].signrawtransaction( hexlify(tx.serialize()).decode('utf-8')) txid = self.nodes[0].sendrawtransaction(tx['hex'], True) self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[1].getaddresstxids(addr), [txid]) check_balance(2, addr, 3 * COIN)
def run_test(self): ''' Test that a backward transfer amount under its dust threshold is not accepted in the mempool. Since this dust threshold depends on minrelaytxfee and this is an optional zend flag, test that a node with a different value set behaves correctly and the network is not affected (no forks happen) ''' mark_logs("Node 1 generates 2 block",self.nodes,DEBUG_MODE) self.nodes[1].generate(2) self.sync_all() mark_logs("Node 0 generates {} block".format(MINIMAL_SC_HEIGHT-2),self.nodes,DEBUG_MODE) self.nodes[0].generate(MINIMAL_SC_HEIGHT-2) self.sync_all() #generate wCertVk and constant mc_test = CertTestUtils(self.options.tmpdir, self.options.srcdir) vk = mc_test.generate_params('sc1') constant = generate_random_field_element_hex() # create SC #------------------------------------------------------------------------------------------------------------ cmd_input = { 'version': 0, 'toaddress': "abcd", 'amount': 1.0, 'wCertVk': vk, 'withdrawalEpochLength': EPOCH_LENGTH, 'constant': constant } mark_logs("\nNode 1 create SC", self.nodes, DEBUG_MODE) try: res = self.nodes[1].sc_create(cmd_input) scid = res['scid'] pprint.pprint(res) self.sync_all() except JSONRPCException as e: error_string = e.error['message'] mark_logs(error_string,self.nodes,DEBUG_MODE) assert_true(False) mark_logs("\nNode 0 generates 1 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(1) self.sync_all() scid_swapped = str(swap_bytes(scid)) addr_node2 = self.nodes[2].getnewaddress() # this amount is next to the border of the dust (54 zat, according to mintxrelayfee default value) but it is sufficiently big not to be refused bwt_amount = Decimal('0.00000060') bwt_cert = [{"address": addr_node2, "amount": bwt_amount}, {"address": addr_node2, "amount": bwt_amount}] bwt_amount_array = [bwt_amount, bwt_amount] addr_array = [addr_node2, addr_node2] q = 10 bl_list = [] # advance some epoch and send a small backward transfer via a certificate for any epoch for i in range(3): if i == 1: # On the second loop, connect a fourth node from scratch with a greater mintxrelayfee, which would make the # node mempool reject the cert, and check this option does not prevent the chain update anyway mark_logs("Connecting a new Node3 with a greater -mintxrelayfee", self.nodes, DEBUG_MODE) self.nodes.append(start_node( 3, self.options.tmpdir , extra_args=[ '-logtimemicros=1', '-debug=cert', '-debug=sc', '-debug=py', '-debug=mempool', '-allowdustoutput=0', '-minrelaytxfee='+str(CUSTOM_FEE_RATE_ZEN_PER_KBYTE)])) connect_nodes_bi(self.nodes, 2, 3) self.sync_all() mark_logs("\nAdvance epoch...", self.nodes, DEBUG_MODE) self.nodes[0].generate(EPOCH_LENGTH - 1) self.sync_all() epoch_number, epoch_cum_tree_hash = get_epoch_data(scid, self.nodes[0], EPOCH_LENGTH) mark_logs("Node 1 sends a cert with a bwd transfers of {} coins to Node2".format(bwt_amount), self.nodes, DEBUG_MODE) #============================================================== proof = mc_test.create_test_proof( "sc1", scid_swapped, epoch_number, q, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, addr_array, bwt_amount_array) try: cert = self.nodes[1].sc_send_certificate(scid, epoch_number, q, epoch_cum_tree_hash, proof, bwt_cert, FT_SC_FEE, MBTR_SC_FEE) except JSONRPCException as e: error_string = e.error['message'] print ("Send certificate failed with reason {}".format(error_string)) assert_true(False) sync_blocks(self.nodes[0:2]) sync_mempools(self.nodes[0:2]) mark_logs("cert = {}".format(cert), self.nodes, DEBUG_MODE) if i == 1: # check that the certificate has ben accepted by Node0 but not by Node3 wich has a greater mintxrelayfee mp0 = self.nodes[0].getrawmempool() mp3 = self.nodes[3].getrawmempool() assert_true(cert in mp0) assert_false(cert in mp3) mark_logs("\nNode 0 generates 1 block", self.nodes, DEBUG_MODE) bl_last = self.nodes[0].generate(1)[-1] bl_list.append(bl_last) self.sync_all() # dust amont for a cert backward transfer is 54 Zat using the 100 Zat/Kbyte default mintxrelayfee rate # check that no certificates with dust amount can be sent via any command type dust_amount = Decimal("0.00000053") bwt_cert = [{"address": addr_node2, "amount": dust_amount}] bwt_amount_array = [dust_amount] addr_array = [addr_node2] quality = 0 proof = mc_test.create_test_proof( "sc1", scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, addr_array, bwt_amount_array) utx, change = get_spendable(self.nodes[0], CERT_FEE) raw_inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] raw_outs = { self.nodes[0].getnewaddress() : change } raw_bwt_outs = {addr_node2: dust_amount} raw_params = { "scid": scid, "quality": quality, "endEpochCumScTxCommTreeRoot": epoch_cum_tree_hash, "scProof": proof, "withdrawalEpochNumber": epoch_number } raw_cert = [] cert = [] try: raw_cert = self.nodes[0].createrawcertificate(raw_inputs, raw_outs, raw_bwt_outs, raw_params) signed_cert = self.nodes[0].signrawtransaction(raw_cert) mark_logs("Node 0 sends a raw cert with a bwd transfers of {} coins to Node2 ... expecting failure".format(dust_amount), self.nodes, DEBUG_MODE) cert = self.nodes[0].sendrawtransaction(signed_cert['hex']) assert False except JSONRPCException as e: error_string = e.error['message'] print ("======> " + error_string) try: mark_logs("Node 0 sends a cert with a bwd transfers of {} coins to Node2 ... expecting failure".format(dust_amount), self.nodes, DEBUG_MODE) cert = self.nodes[0].sc_send_certificate(scid, epoch_number, q, epoch_cum_tree_hash, proof, bwt_cert, FT_SC_FEE, MBTR_SC_FEE) assert False except JSONRPCException as e: error_string = e.error['message'] print ("======> " + error_string) bal = self.nodes[2].getbalance() utx = self.nodes[2].listunspent() print ("Node2 balance = {}".format(bal)) assert_equal(bal, 2*bwt_amount) # the dust threshold for a bwt (54 Zat) is lower than the one for a standard output due to the replay protection # extension in the pub script (63 Zat). As a result we can not spend exactly one UTXOs coming from backward transfer # otherwise we would create a dust output. mark_logs("Node2 tries to spent one utxo from bwt sending {} coins to Node0 ... expecting failure".format(utx[0]['amount']), self.nodes, DEBUG_MODE) # try spending one utxo inputs = [ {'txid' : utx[0]['txid'], 'vout' : utx[0]['vout']}] outputs = { self.nodes[0].getnewaddress() : utx[0]['amount'] } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) rawtx = self.nodes[2].signrawtransaction(rawtx) error_string = "" try: rawtx = self.nodes[2].sendrawtransaction(rawtx['hex']) assert False except JSONRPCException as e: error_string = e.error['message'] print (error_string) # we can spend a pair of them instead mark_logs("Node2 tries to spent both utxo from bwt sending {} coins to Node0".format(bal), self.nodes, DEBUG_MODE) # try spending two utxos inputs = [ {'txid' : utx[0]['txid'], 'vout' : utx[0]['vout']}, {'txid' : utx[1]['txid'], 'vout' : utx[1]['vout']}] outputs = { self.nodes[0].getnewaddress() : bal } rawtx = self.nodes[2].createrawtransaction(inputs, outputs) rawtx = self.nodes[2].signrawtransaction(rawtx) error_string = "" try: rawtx = self.nodes[2].sendrawtransaction(rawtx['hex']) except JSONRPCException as e: error_string = e.error['message'] print (error_string) assert False print ("tx = {}".format(rawtx)) sync_blocks(self.nodes[0:2]) sync_mempools(self.nodes[0:2]) # just to be sure tx is propagated time.sleep(2) mark_logs("Node 2 generates 1 block", self.nodes, DEBUG_MODE) self.nodes[2].generate(1) self.sync_all() mark_logs("\nChecking persistance stopping and restarting nodes", self.nodes, DEBUG_MODE) stop_nodes(self.nodes) wait_bitcoinds() self.setup_network(False)
def run_test(self): ''' Test the situation when bot a fw transfer and a certificate for the same scid are in the mempool and a block is mined" ''' def get_epoch_data(node, sc_creating_height, epoch_length): current_height = node.getblockcount() epoch_number = (current_height - sc_creating_height + 1) // epoch_length - 1 epoch_block_hash = node.getblockhash(sc_creating_height - 1 + ((epoch_number + 1) * epoch_length)) return epoch_number, epoch_block_hash # forward transfer amounts creation_amount = Decimal("1000") fwt_amount = Decimal("3.0") # node 1 earns some coins, they would be available after 100 blocks mark_logs("Node 1 generates 1 block", self.nodes, DEBUG_MODE) self.nodes[1].generate(1) self.sync_all() mark_logs("Node 0 generates 220 block", self.nodes, DEBUG_MODE) self.nodes[0].generate(220) self.sync_all() # generate a tx in mempool whose coins will be used by the tx creating the sc as input. This will make the creation tx orphan # and with null prio (that is because its inputs have 0 conf). As a consequence it would be processed after the forward transfer, making the block invalid. # Handling sc dependancies will prevent this scenario. tx = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), creation_amount); mark_logs("Node 0 sent {} coins to itself via {}".format(creation_amount, tx), self.nodes, DEBUG_MODE) self.sync_all() totScAmount = 0 # sidechain creation #------------------- # generate wCertVk and constant mcTest = MCTestUtils(self.options.tmpdir, self.options.srcdir) vk = mcTest.generate_params("sc1") constant = generate_random_field_element_hex() creating_tx = self.nodes[0].sc_create(EPOCH_LENGTH, "dada", creation_amount, vk, "", constant) mark_logs("Node 0 created a sidechain via {}".format(creating_tx), self.nodes, DEBUG_MODE) self.sync_all() decoded_tx = self.nodes[0].getrawtransaction(creating_tx, 1) scid = decoded_tx['vsc_ccout'][0]['scid'] mark_logs("created SC id: {}".format(scid), self.nodes, DEBUG_MODE) totScAmount += creation_amount mark_logs("Node 0 sends to sidechain ", self.nodes, DEBUG_MODE) txes = [] for i in range(1, BUNCH_SIZE+1): amounts = [] interm_amount = 0 for j in range(1, BUNCH_SIZE+1): scaddr = str(hex(j*i)) amount = j*i*Decimal('0.01') interm_amount += amount amounts.append({"address": scaddr, "amount": amount, "scid": scid}) txes.append(self.nodes[0].sc_sendmany(amounts)) mark_logs("Node 0 send many amounts (tot={}) to sidechain via {}".format(interm_amount, txes[-1]), self.nodes, DEBUG_MODE) self.sync_all() totScAmount += interm_amount mark_logs("Check creation tx is in mempools", self.nodes, DEBUG_MODE) assert_equal(True, creating_tx in self.nodes[1].getrawmempool()) #pprint.pprint(self.nodes[1].getrawmempool(True)) mp = self.nodes[1].getrawmempool(True) prio_cr_tx = mp[creating_tx]['currentpriority'] dep_cr_tx = mp[creating_tx]['depends'][0] mark_logs("creation tx prio {}".format(prio_cr_tx), self.nodes, DEBUG_MODE) assert_equal(0, prio_cr_tx) mark_logs("creation tx depends on {}".format(dep_cr_tx), self.nodes, DEBUG_MODE) assert_equal(tx, dep_cr_tx) mark_logs("Check fw txes are in mempools and their prio is greater than sc creation prio", self.nodes, DEBUG_MODE) for fwt in txes: assert_equal(True, fwt in self.nodes[1].getrawmempool()) prio_fwt = mp[fwt]['currentpriority'] dep_fwt = mp[fwt]['depends'][-1] assert_true(prio_fwt > prio_cr_tx) assert_equal(dep_fwt, creating_tx) mark_logs("Node1 generates 1 block", self.nodes, DEBUG_MODE) bl_hash = self.nodes[1].generate(1)[0] self.sync_all() mark_logs("Check mempools are empty", self.nodes, DEBUG_MODE) assert_equal(0, len(self.nodes[0].getrawmempool())) mark_logs("Check that all fw txes are in block", self.nodes, DEBUG_MODE) block = self.nodes[0].getblock(bl_hash, True) vtx = block['tx'] for fwt in txes: assert_equal(True, fwt in vtx) mark_logs("Check that creating tx is the third in list (after coinbase)", self.nodes, DEBUG_MODE) assert_equal(creating_tx, vtx[2]) #------------------------------------------------------- mark_logs("stopping and restarting nodes with '-deprecatedgetblocktemplate=1'", self.nodes, DEBUG_MODE) stop_nodes(self.nodes) wait_bitcoinds() self.setup_network(False, True) mark_logs("Node 0 invalidates last block", self.nodes, DEBUG_MODE) self.nodes[0].invalidateblock(bl_hash) mark_logs("Check creation tx is in mempool", self.nodes, DEBUG_MODE) assert_equal(True, creating_tx in self.nodes[0].getrawmempool()) mark_logs("Check fw txes are in mempool", self.nodes, DEBUG_MODE) for fwt in txes: assert_equal(True, fwt in self.nodes[0].getrawmempool()) mp = self.nodes[0].getrawmempool(True) prio_cr_tx = mp[creating_tx]['currentpriority'] dep_cr_tx = mp[creating_tx]['depends'][0] mark_logs("creation tx prio {}".format(prio_cr_tx), self.nodes, DEBUG_MODE) #assert_equal(0, prio_cr_tx) TODO lower prio via rpc mark_logs("creation tx depends on {}".format(dep_cr_tx), self.nodes, DEBUG_MODE) assert_equal(tx, dep_cr_tx) mark_logs("Check fw txes are in mempools and their prio is greater than sc creation prio", self.nodes, DEBUG_MODE) for fwt in txes: assert_equal(True, fwt in self.nodes[0].getrawmempool()) prio_fwt = mp[fwt]['currentpriority'] dep_fwt = mp[fwt]['depends'][-1] #assert_true(prio_fwt > prio_cr_tx) TODO see above assert_equal(dep_fwt, creating_tx) mark_logs("Node0 generates 1 block", self.nodes, DEBUG_MODE) bl_hash = self.nodes[0].generate(1)[0] self.sync_all() mark_logs("Check mempool is empty", self.nodes, DEBUG_MODE) assert_equal(0, len(self.nodes[0].getrawmempool())) mark_logs("Check that all fw txes are in block", self.nodes, DEBUG_MODE) block = self.nodes[0].getblock(bl_hash, True) vtx = block['tx'] for fwt in txes: assert_equal(True, fwt in vtx) mark_logs("Check that creating tx is the third in list (after coinbase)", self.nodes, DEBUG_MODE) assert_equal(creating_tx, vtx[2]) mark_logs("Node0 generates 5 more blocks", self.nodes, DEBUG_MODE) self.nodes[0].generate(5) self.sync_all() mark_logs("Check that sc balance is as expected", self.nodes, DEBUG_MODE) pprint.pprint(self.nodes[1].getscinfo(scid)) assert_equal(totScAmount, self.nodes[1].getscinfo(scid)['balance']) mark_logs("Check that both nodes share the same view of sc info", self.nodes, DEBUG_MODE) assert_equal(self.nodes[0].getscinfo(scid), self.nodes[1].getscinfo(scid))
def run_test(self): self.nodes[0].generate(105) self.sync_all() chain_height = self.nodes[1].getblockcount() assert_equal(chain_height, 105) # Test getrawtransaction changes and the getspentinfo RPC # send coinbase to address addr1 addr1 = self.nodes[1].getnewaddress() txid1 = self.nodes[0].sendtoaddress(addr1, 2) self.sync_all() block_hash1 = self.nodes[0].generate(1) self.sync_all() # send from addr1 to addr2 # (the only utxo on node 1 is from address addr1) addr2 = self.nodes[2].getnewaddress() txid2 = self.nodes[1].sendtoaddress(addr2, 1) self.sync_all() # addr1 to addr2 transaction is not confirmed, so it has no height tx2 = self.nodes[2].getrawtransaction(txid2, 1) assert ('height' not in tx2) # confirm addr1 to addr2 transaction block_hash2 = self.nodes[0].generate(1) self.sync_all() # Restart all nodes to ensure index files are saved to disk and recovered stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Check new fields added to getrawtransaction tx1 = self.nodes[2].getrawtransaction(txid1, 1) assert_equal(tx1['vin'][0]['value'], 10) # coinbase assert_equal(tx1['vin'][0]['valueSat'], 10 * COIN) # we want the non-change (payment) output vout = filter(lambda o: o['value'] == 2, tx1['vout']) n = vout[0]['n'] assert_equal(vout[0]['spentTxId'], txid2) assert_equal(vout[0]['spentIndex'], 0) assert_equal(vout[0]['spentHeight'], 107) assert_equal(tx1['height'], 106) tx2 = self.nodes[2].getrawtransaction(txid2, 1) assert_equal(tx2['vin'][0]['address'], addr1) assert_equal(tx2['vin'][0]['value'], 2) assert_equal(tx2['vin'][0]['valueSat'], 2 * COIN) # since this transaction's outputs haven't yet been # spent, these fields should not be present assert ('spentTxId' not in tx2['vout'][0]) assert ('spentIndex' not in tx2['vout'][0]) assert ('spentHeight' not in tx2['vout'][0]) assert_equal(tx2['height'], 107) # Given a transaction output, getspentinfo() returns a reference # to the (later, confirmed) transaction that spent that output, # that is, the transaction that used this output as an input. spentinfo = self.nodes[2].getspentinfo({'txid': txid1, 'index': n}) assert_equal(spentinfo['height'], 107) assert_equal(spentinfo['index'], 0) assert_equal(spentinfo['txid'], txid2) # specifying an output that hasn't been spent should fail try: self.nodes[1].getspentinfo({'txid': txid2, 'index': 0}) fail('getspentinfo should have thrown an exception') except JSONRPCException, e: assert_equal(e.error['message'], "Unable to get spent info")
def run_test(self): print "Mining blocks..." self.nodes[0].generate(4) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[1].generate(102) self.sync_all() assert_equal(self.nodes[0].getbalance(), 40) assert_equal(self.nodes[1].getbalance(), 20) assert_equal(self.nodes[2].getbalance(), 0) # At this point in time, commitment tree is the empty root # Node 0 creates a joinsplit transaction mytaddr0 = get_coinbase_address(self.nodes[0]) myzaddr0 = self.nodes[0].z_getnewaddress('sprout') recipients = [] recipients.append({ "address": myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001') }) myopid = self.nodes[0].z_sendmany(mytaddr0, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) # Sync up mempools and mine the transaction. All nodes have the same anchor. self.sync_all() self.nodes[0].generate(1) self.sync_all() # Stop nodes. stop_nodes(self.nodes) wait_bitcoinds() # Relaunch nodes and partition network into two: # A: node 0 # B: node 1, 2 self.nodes = start_nodes( 3, self.options.tmpdir, extra_args=[['-regtestprotectcoinbase', '-debug=zrpc']] * 3) connect_nodes_bi(self.nodes, 1, 2) # Partition B, node 1 mines an empty block self.nodes[1].generate(1) # Partition A, node 0 creates a joinsplit transaction recipients = [] recipients.append({ "address": myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001') }) myopid = self.nodes[0].z_sendmany(mytaddr0, recipients) txid = wait_and_assert_operationid_status(self.nodes[0], myopid) rawhex = self.nodes[0].getrawtransaction(txid) # Partition A, node 0 mines a block with the transaction self.nodes[0].generate(1) # Partition B, node 1 mines the same joinsplit transaction txid2 = self.nodes[1].sendrawtransaction(rawhex) assert_equal(txid, txid2) self.nodes[1].generate(1) # Check that Partition B is one block ahead and that they have different tips assert_equal(self.nodes[0].getblockcount() + 1, self.nodes[1].getblockcount()) assert (self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash()) # Shut down all nodes so any in-memory state is saved to disk stop_nodes(self.nodes) wait_bitcoinds() # Relaunch nodes and reconnect the entire network self.nodes = start_nodes( 3, self.options.tmpdir, extra_args=[['-regtestprotectcoinbase', '-debug=zrpc']] * 3) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) # Mine a new block and let it propagate self.nodes[1].generate(1) # Due to a bug in v1.0.0-1.0.3, node 0 will die with a tree root assertion, so sync_all() will throw an exception. self.sync_all() # v1.0.4 will reach here safely assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash()) assert_equal(self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash())
class WalletTest(BitcoinTestFramework): def setup_chain(self): print("Initializing test directory " + self.options.tmpdir) initialize_chain_clean(self.options.tmpdir, 4) def setup_network(self, split=False): self.nodes = start_nodes(3, self.options.tmpdir) 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 run_test(self): print "Mining blocks..." self.nodes[0].generate(4) self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[1].generate(101) self.sync_all() assert_equal(self.nodes[0].getbalance(), 40) assert_equal(self.nodes[1].getbalance(), 10) assert_equal(self.nodes[2].getbalance(), 0) assert_equal(self.nodes[0].getbalance("*"), 40) assert_equal(self.nodes[1].getbalance("*"), 10) assert_equal(self.nodes[2].getbalance("*"), 0) # Send 21 BTC from 0 to 2 using sendtoaddress call. # Second transaction will be child of first, and will require a fee self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 0) # Have node0 mine a block, thus it will collect its own fee. self.sync_all() self.nodes[0].generate(1) self.sync_all() # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) self.sync_all() # node0 should end up with 50 btc in block rewards plus fees, but # minus the 21 plus fees sent to node2 assert_equal(self.nodes[0].getbalance(), 50 - 21) assert_equal(self.nodes[2].getbalance(), 21) assert_equal(self.nodes[0].getbalance("*"), 50 - 21) assert_equal(self.nodes[2].getbalance("*"), 21) # Node0 should have three 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), 3) # Check 'generated' field of listunspent # Node 0: has one coinbase utxo and two regular utxos assert_equal( sum(int(uxto["generated"] is True) for uxto in node0utxos), 1) # Node 1: has 101 coinbase utxos and no regular utxos node1utxos = self.nodes[1].listunspent(1) assert_equal(len(node1utxos), 101) assert_equal( sum(int(uxto["generated"] is True) for uxto in node1utxos), 101) # Node 2: has no coinbase utxos and two regular utxos node2utxos = self.nodes[2].listunspent(1) assert_equal(len(node2utxos), 2) assert_equal( sum(int(uxto["generated"] is True) for uxto in node2utxos), 0) # Catch an attempt to send a transaction with an absurdly high fee. # Send 1.0 from an utxo of value 10.0 but don't specify a change output, so then # the change of 9.0 becomes the fee, which is greater than estimated fee of 0.0019. inputs = [] outputs = {} for utxo in node2utxos: if utxo["amount"] == Decimal("10.0"): break assert_equal(utxo["amount"], Decimal("10.0")) inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) outputs[self.nodes[2].getnewaddress("")] = Decimal("1.0") raw_tx = self.nodes[2].createrawtransaction(inputs, outputs) signed_tx = self.nodes[2].signrawtransaction(raw_tx) try: self.nodes[2].sendrawtransaction(signed_tx["hex"]) except JSONRPCException, e: errorString = e.error['message'] assert ("absurdly high fees" in errorString) assert ("900000000 > 190000" in errorString) # 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"] raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) txns_to_send.append(self.nodes[0].signrawtransaction(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) self.nodes[1].sendrawtransaction(txns_to_send[2]["hex"], True) # Have node1 mine a block to confirm transactions: self.sync_all() self.nodes[1].generate(1) self.sync_all() assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 50) assert_equal(self.nodes[0].getbalance("*"), 0) assert_equal(self.nodes[2].getbalance("*"), 50) # Send 10 BTC normal address = self.nodes[0].getnewaddress("") self.nodes[2].settxfee(Decimal('0.001')) self.nodes[2].sendtoaddress(address, 10, "", "", False) self.sync_all() self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('39.99900000')) assert_equal(self.nodes[0].getbalance(), Decimal('10.00000000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('39.99900000')) assert_equal(self.nodes[0].getbalance("*"), Decimal('10.00000000')) # Send 10 BTC with subtract fee from amount self.nodes[2].sendtoaddress(address, 10, "", "", True) self.sync_all() self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('29.99900000')) assert_equal(self.nodes[0].getbalance(), Decimal('19.99900000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('29.99900000')) assert_equal(self.nodes[0].getbalance("*"), Decimal('19.99900000')) # Sendmany 10 BTC self.nodes[2].sendmany("", {address: 10}, 0, "", []) self.sync_all() self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('19.99800000')) assert_equal(self.nodes[0].getbalance(), Decimal('29.99900000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('19.99800000')) assert_equal(self.nodes[0].getbalance("*"), Decimal('29.99900000')) # Sendmany 10 BTC with subtract fee from amount self.nodes[2].sendmany("", {address: 10}, 0, "", [address]) self.sync_all() self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000')) assert_equal(self.nodes[0].getbalance(), Decimal('39.99800000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000')) assert_equal(self.nodes[0].getbalance("*"), Decimal('39.99800000')) # 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) self.nodes.append(start_node(3, self.options.tmpdir)) connect_nodes_bi(self.nodes, 0, 3) sync_blocks(self.nodes) relayed = self.nodes[0].resendwallettransactions() assert_equal(set(relayed), set([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 rawtx #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() inputs = [{"txid": usp[0]['txid'], "vout": usp[0]['vout']}] outputs = { self.nodes[1].getnewaddress(): 9.998, self.nodes[0].getnewaddress(): 11.11 } rawTx = self.nodes[1].createrawtransaction(inputs, outputs).replace( "c0833842", "00000000") #replace 11.11 with 0.0 (int32) decRawTx = self.nodes[1].decoderawtransaction(rawTx) signedRawTx = self.nodes[1].signrawtransaction(rawTx) decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex']) zeroValueTxid = decRawTx['txid'] self.nodes[1].sendrawtransaction(signedRawTx['hex']) self.sync_all() self.nodes[1].generate(1) #mine a block self.sync_all() unspentTxs = self.nodes[0].listunspent( ) #zero value tx must be in listunspents output found = False for uTx in unspentTxs: if uTx['txid'] == zeroValueTxid: found = True assert_equal(uTx['amount'], Decimal('0.00000000')) assert (found) #do some -walletbroadcast tests stop_nodes(self.nodes) wait_bitcoinds() self.nodes = start_nodes( 3, self.options.tmpdir, [["-walletbroadcast=0"], ["-walletbroadcast=0"], ["-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() txIdNotBroadcasted = self.nodes[0].sendtoaddress( self.nodes[2].getnewaddress(), 2) txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) self.sync_all() self.nodes[1].generate(1) #mine a block, tx should not be in there self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000') ) #should not be changed because tx was not broadcasted assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000') ) #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(txObjNotBroadcasted['hex']) self.sync_all() self.nodes[1].generate(1) self.sync_all() txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) assert_equal(self.nodes[2].getbalance(), Decimal('11.99800000')) #should not be assert_equal(self.nodes[2].getbalance("*"), Decimal('11.99800000')) #should not be #create another tx txIdNotBroadcasted = self.nodes[0].sendtoaddress( self.nodes[2].getnewaddress(), 2) #restart the nodes with -walletbroadcast=1 stop_nodes(self.nodes) wait_bitcoinds() self.nodes = start_nodes(3, self.options.tmpdir) 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) self.nodes[0].generate(1) sync_blocks(self.nodes) #tx should be added to balance because after restarting the nodes tx should be broadcastet assert_equal(self.nodes[2].getbalance(), Decimal('13.99800000')) #should not be assert_equal(self.nodes[2].getbalance("*"), Decimal('13.99800000')) #should not be # send from node 0 to node 2 taddr mytaddr = self.nodes[2].getnewaddress() mytxid = self.nodes[0].sendtoaddress(mytaddr, 10.0) self.sync_all() self.nodes[0].generate(1) self.sync_all() mybalance = self.nodes[2].z_getbalance(mytaddr) assert_equal(mybalance, Decimal('10.0')) mytxdetails = self.nodes[2].gettransaction(mytxid) myvjoinsplits = mytxdetails["vjoinsplit"] assert_equal(0, len(myvjoinsplits)) # z_sendmany is expected to fail if tx size breaks limit myzaddr = self.nodes[0].z_getnewaddress() recipients = [] num_t_recipients = 3000 amount_per_recipient = Decimal('0.00000001') errorString = '' for i in xrange(0, num_t_recipients): newtaddr = self.nodes[2].getnewaddress() recipients.append({ "address": newtaddr, "amount": amount_per_recipient }) # Issue #2759 Workaround START # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process # loop above to create new addresses, that when z_sendmany is called with a large amount of # rpc data in recipients, the connection fails with a 'broken pipe' error. Making a RPC call # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP # connection into a good state to handle a large amount of data in recipients. self.nodes[0].getinfo() # Issue #2759 Workaround END try: self.nodes[0].z_sendmany(myzaddr, recipients) except JSONRPCException, e: errorString = e.error['message']
class RawTransactionsTest(BitcoinTestFramework): def setup_chain(self): print("Initializing test directory "+self.options.tmpdir) initialize_chain_clean(self.options.tmpdir, 3) def setup_network(self, split=False): self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-experimentalfeatures', '-developerencryptwallet']] * 4) 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 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(101) self.sync_all() 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() : 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() : 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 outputs.has_key(out['scriptPubKey']['addresses'][0]): 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 outputs.has_key(out['scriptPubKey']['addresses'][0]): 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 outputs.has_key(out['scriptPubKey']['addresses'][0]): 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,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(3, self.options.tmpdir) 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() 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('11.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('10.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
def run_test(self): # Sanity-check the test harness assert_equal(self.nodes[0].getblockcount(), 200) # Get a new Orchard account on node 0 acct0 = self.nodes[0].z_getnewaccount()['account'] ua0 = self.nodes[0].z_getaddressforaccount(acct0, ['orchard'])['address'] # Activate NU5 self.nodes[0].generate(5) self.sync_all() # Get a recipient address acct1 = self.nodes[1].z_getnewaccount()['account'] ua1 = self.nodes[1].z_getaddressforaccount(acct1, ['orchard'])['address'] # Send a transaction to node 1 so that it has an Orchard note to spend. recipients = [{"address": ua1, "amount": 10}] myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders') wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Check the value sent to ua1 was received assert_equal( { 'pools': { 'orchard': { 'valueZat': 10_0000_0000 } }, 'minimum_confirmations': 1 }, self.nodes[1].z_getbalanceforaccount(acct1)) # Create an Orchard spend, so that the note commitment tree root gets altered. recipients = [{"address": ua0, "amount": 1}] myopid = self.nodes[1].z_sendmany(ua1, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[1], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify the balance on both nodes assert_equal( { 'pools': { 'orchard': { 'valueZat': 9_0000_0000 } }, 'minimum_confirmations': 1 }, self.nodes[1].z_getbalanceforaccount(acct1)) assert_equal( { 'pools': { 'orchard': { 'valueZat': 1_0000_0000 } }, 'minimum_confirmations': 1 }, self.nodes[0].z_getbalanceforaccount(acct0)) # Split the network. We'll advance the state of nodes 0/1 so that after # we re-join the network, we need to roll back more than one block after # the wallet is restored, into a chain state that the wallet never observed. self.split_network() self.sync_all() self.nodes[0].generate(2) self.sync_all() # Shut down the network and delete node 0's wallet stop_nodes(self.nodes) wait_bitcoinds() tmpdir = self.options.tmpdir os.remove(os.path.join(tmpdir, "node0", "regtest", "wallet.dat")) # Restart the network, still split; the split here is note necessary to reproduce # the error but it is sufficient, and we will later use the split to check the # corresponding rewind. self.setup_network(True) assert_equal( { 'pools': { 'orchard': { 'valueZat': 9_0000_0000 } }, 'minimum_confirmations': 1 }, self.nodes[1].z_getbalanceforaccount(acct1)) # Get a new account with an Orchard UA on node 0 acct0new = self.nodes[0].z_getnewaccount()['account'] ua0new = self.nodes[0].z_getaddressforaccount(acct0, ['orchard'])['address'] # Send a transaction to the Orchard account. When we mine this transaction, # the bug causes the state of note commitment tree in the wallet to not match # the state of the global note commitment tree. recipients = [{"address": ua0new, "amount": 1}] myopid = self.nodes[1].z_sendmany(ua1, recipients, 1, 0) rollback_tx = wait_and_assert_operationid_status(self.nodes[1], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal( { 'pools': { 'orchard': { 'valueZat': 1_0000_0000 } }, 'minimum_confirmations': 1 }, self.nodes[0].z_getbalanceforaccount(acct0new)) # Node 2 has no progress since the network was first split, so this should roll # everything back to the original fork point. self.nodes[2].generate(10) # Re-join the network self.join_network() assert_equal(set([rollback_tx]), set(self.nodes[1].getrawmempool())) # Resend un-mined transactions and sync the network self.nodes[1].resendwallettransactions() self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal( { 'pools': { 'orchard': { 'valueZat': 1_0000_0000 } }, 'minimum_confirmations': 1 }, self.nodes[0].z_getbalanceforaccount(acct0new)) # Spend from the note that was just received recipients = [{"address": ua1, "amount": Decimal('0.3')}] myopid = self.nodes[0].z_sendmany(ua0new, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal( { 'pools': { 'orchard': { 'valueZat': 8_3000_0000 } }, 'minimum_confirmations': 1 }, self.nodes[1].z_getbalanceforaccount(acct1))
def run_test(self): print("Mining blocks...") self.nodes[0].generate(4) self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) assert_equal(walletinfo['balance'], 0) blockchaininfo = self.nodes[0].getblockchaininfo() assert_equal(blockchaininfo['estimatedheight'], 4) self.sync_all() self.nodes[1].generate(101) self.sync_all() assert_equal(self.nodes[0].getbalance(), 40) assert_equal(self.nodes[1].getbalance(), 10) assert_equal(self.nodes[2].getbalance(), 0) assert_equal(self.nodes[0].getbalance("*"), 40) assert_equal(self.nodes[1].getbalance("*"), 10) assert_equal(self.nodes[2].getbalance("*"), 0) # Send 21 BTC from 0 to 2 using sendtoaddress call. # Second transaction will be child of first, and will require a fee self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 0) blockchaininfo = self.nodes[0].getblockchaininfo() assert_equal(blockchaininfo['estimatedheight'], 105) # Have node0 mine a block, thus it will collect its own fee. self.sync_all() self.nodes[0].generate(1) self.sync_all() # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) self.sync_all() # node0 should end up with 50 btc in block rewards plus fees, but # minus the 21 plus fees sent to node2 assert_equal(self.nodes[0].getbalance(), 50 - 21) assert_equal(self.nodes[2].getbalance(), 21) assert_equal(self.nodes[0].getbalance("*"), 50 - 21) assert_equal(self.nodes[2].getbalance("*"), 21) # Node0 should have three 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), 3) # Check 'generated' field of listunspent # Node 0: has one coinbase utxo and two regular utxos assert_equal( sum(int(uxto["generated"] is True) for uxto in node0utxos), 1) # Node 1: has 101 coinbase utxos and no regular utxos node1utxos = self.nodes[1].listunspent(1) assert_equal(len(node1utxos), 101) assert_equal( sum(int(uxto["generated"] is True) for uxto in node1utxos), 101) # Node 2: has no coinbase utxos and two regular utxos node2utxos = self.nodes[2].listunspent(1) assert_equal(len(node2utxos), 2) assert_equal( sum(int(uxto["generated"] is True) for uxto in node2utxos), 0) # Catch an attempt to send a transaction with an absurdly high fee. # Send 1.0 from an utxo of value 10.0 but don't specify a change output, so then # the change of 9.0 becomes the fee, which is greater than estimated fee of 0.0021. inputs = [] outputs = {} for utxo in node2utxos: if utxo["amount"] == Decimal("10.0"): break assert_equal(utxo["amount"], Decimal("10.0")) inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) outputs[self.nodes[2].getnewaddress("")] = Decimal("1.0") raw_tx = self.nodes[2].createrawtransaction(inputs, outputs) signed_tx = self.nodes[2].signrawtransaction(raw_tx) try: self.nodes[2].sendrawtransaction(signed_tx["hex"]) except JSONRPCException as e: errorString = e.error['message'] assert ("absurdly high fees" in errorString) assert ("900000000 > 10000000" in errorString) # 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"] raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) txns_to_send.append(self.nodes[0].signrawtransaction(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) self.nodes[1].sendrawtransaction(txns_to_send[2]["hex"], True) # Have node1 mine a block to confirm transactions: self.sync_all() self.nodes[1].generate(1) self.sync_all() assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 50) assert_equal(self.nodes[0].getbalance("*"), 0) assert_equal(self.nodes[2].getbalance("*"), 50) # Send 10 BTC normal address = self.nodes[0].getnewaddress("") self.nodes[2].settxfee(Decimal('0.001')) self.nodes[2].sendtoaddress(address, 10, "", "", False) self.sync_all() self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('39.99900000')) assert_equal(self.nodes[0].getbalance(), Decimal('10.00000000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('39.99900000')) assert_equal(self.nodes[0].getbalance("*"), Decimal('10.00000000')) # Send 10 BTC with subtract fee from amount self.nodes[2].sendtoaddress(address, 10, "", "", True) self.sync_all() self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('29.99900000')) assert_equal(self.nodes[0].getbalance(), Decimal('19.99900000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('29.99900000')) assert_equal(self.nodes[0].getbalance("*"), Decimal('19.99900000')) # Sendmany 10 BTC self.nodes[2].sendmany("", {address: 10}, 0, "", []) self.sync_all() self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('19.99800000')) assert_equal(self.nodes[0].getbalance(), Decimal('29.99900000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('19.99800000')) assert_equal(self.nodes[0].getbalance("*"), Decimal('29.99900000')) # Sendmany 10 BTC with subtract fee from amount self.nodes[2].sendmany("", {address: 10}, 0, "", [address]) self.sync_all() self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000')) assert_equal(self.nodes[0].getbalance(), Decimal('39.99800000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000')) assert_equal(self.nodes[0].getbalance("*"), Decimal('39.99800000')) # 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) self.nodes.append(start_node(3, self.options.tmpdir)) connect_nodes_bi(self.nodes, 0, 3) sync_blocks(self.nodes) relayed = self.nodes[0].resendwallettransactions() assert_equal(set(relayed), set([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 rawtx #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() inputs = [{"txid": usp[0]['txid'], "vout": usp[0]['vout']}] outputs = { self.nodes[1].getnewaddress(): 9.998, self.nodes[0].getnewaddress(): 11.11 } rawTx = self.nodes[1].createrawtransaction(inputs, outputs).replace( "c0833842", "00000000") #replace 11.11 with 0.0 (int32) decRawTx = self.nodes[1].decoderawtransaction(rawTx) signedRawTx = self.nodes[1].signrawtransaction(rawTx) decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex']) zeroValueTxid = decRawTx['txid'] self.nodes[1].sendrawtransaction(signedRawTx['hex']) self.sync_all() self.nodes[1].generate(1) #mine a block self.sync_all() unspentTxs = self.nodes[0].listunspent( ) #zero value tx must be in listunspents output found = False for uTx in unspentTxs: if uTx['txid'] == zeroValueTxid: found = True assert_equal(uTx['amount'], Decimal('0.00000000')) assert_equal(uTx['amountZat'], 0) assert (found) #do some -walletbroadcast tests stop_nodes(self.nodes) wait_bitcoinds() self.nodes = start_nodes( 3, self.options.tmpdir, [["-walletbroadcast=0"], ["-walletbroadcast=0"], ["-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() txIdNotBroadcasted = self.nodes[0].sendtoaddress( self.nodes[2].getnewaddress(), 2) txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) self.sync_all() self.nodes[1].generate(1) #mine a block, tx should not be in there self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000') ) #should not be changed because tx was not broadcasted assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000') ) #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(txObjNotBroadcasted['hex']) self.sync_all() self.nodes[1].generate(1) self.sync_all() txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) assert_equal(self.nodes[2].getbalance(), Decimal('11.99800000')) #should not be assert_equal(self.nodes[2].getbalance("*"), Decimal('11.99800000')) #should not be #create another tx txIdNotBroadcasted = self.nodes[0].sendtoaddress( self.nodes[2].getnewaddress(), 2) #restart the nodes with -walletbroadcast=1 stop_nodes(self.nodes) wait_bitcoinds() self.nodes = start_nodes(3, self.options.tmpdir) 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) self.nodes[0].generate(1) sync_blocks(self.nodes) # tx should be added to balance because after restarting the nodes tx should be broadcast assert_equal(self.nodes[2].getbalance(), Decimal('13.99800000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('13.99800000')) # check integer balances from getbalance assert_equal(self.nodes[2].getbalance("*", 1, False, True), 1399800000) # send from node 0 to node 2 taddr mytaddr = self.nodes[2].getnewaddress() mytxid = self.nodes[0].sendtoaddress(mytaddr, 10.0) self.sync_all() self.nodes[0].generate(1) self.sync_all() mybalance = self.nodes[2].z_getbalance(mytaddr) assert_equal(mybalance, Decimal('10.0')) # check integer balances from z_getbalance assert_equal(self.nodes[2].z_getbalance(mytaddr, 1, True), 1000000000) mytxdetails = self.nodes[2].gettransaction(mytxid) myvjoinsplits = mytxdetails["vjoinsplit"] assert_equal(0, len(myvjoinsplits)) assert ("joinSplitPubKey" not in mytxdetails) assert ("joinSplitSig" not in mytxdetails) # z_sendmany is expected to fail if tx size breaks limit myzaddr = self.nodes[0].z_getnewaddress() recipients = [] num_t_recipients = 1000 num_z_recipients = 2100 amount_per_recipient = Decimal('0.00000001') errorString = '' for i in range(0, num_t_recipients): newtaddr = self.nodes[2].getnewaddress() recipients.append({ "address": newtaddr, "amount": amount_per_recipient }) for i in range(0, num_z_recipients): newzaddr = self.nodes[2].z_getnewaddress() recipients.append({ "address": newzaddr, "amount": amount_per_recipient }) # Issue #2759 Workaround START # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process # loop above to create new addresses, that when z_sendmany is called with a large amount of # rpc data in recipients, the connection fails with a 'broken pipe' error. Making a RPC call # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP # connection into a good state to handle a large amount of data in recipients. self.nodes[0].getinfo() # Issue #2759 Workaround END try: self.nodes[0].z_sendmany(myzaddr, recipients) except JSONRPCException as e: errorString = e.error['message'] assert ("size of raw transaction would be larger than limit" in errorString) # add zaddr to node 2 myzaddr = self.nodes[2].z_getnewaddress() # send node 2 taddr to zaddr recipients = [] recipients.append({"address": myzaddr, "amount": 7}) mytxid = wait_and_assert_operationid_status( self.nodes[2], self.nodes[2].z_sendmany(mytaddr, recipients)) self.sync_all() # check balances zsendmanynotevalue = Decimal('7.0') zsendmanyfee = Decimal('0.0001') node2utxobalance = Decimal( '23.998') - zsendmanynotevalue - zsendmanyfee # check shielded balance status with getwalletinfo wallet_info = self.nodes[2].getwalletinfo() assert_equal(Decimal(wallet_info["shielded_unconfirmed_balance"]), zsendmanynotevalue) assert_equal(Decimal(wallet_info["shielded_balance"]), Decimal('0.0')) self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), node2utxobalance) assert_equal(self.nodes[2].getbalance("*"), node2utxobalance) # check zaddr balance with z_getbalance assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue) # check via z_gettotalbalance resp = self.nodes[2].z_gettotalbalance() assert_equal(Decimal(resp["transparent"]), node2utxobalance) assert_equal(Decimal(resp["private"]), zsendmanynotevalue) assert_equal(Decimal(resp["total"]), node2utxobalance + zsendmanynotevalue) # check confirmed shielded balance with getwalletinfo wallet_info = self.nodes[2].getwalletinfo() assert_equal(Decimal(wallet_info["shielded_unconfirmed_balance"]), Decimal('0.0')) assert_equal(Decimal(wallet_info["shielded_balance"]), zsendmanynotevalue) # there should be at least one Sapling output mytxdetails = self.nodes[2].getrawtransaction(mytxid, 1) assert_greater_than(len(mytxdetails["vShieldedOutput"]), 0) # the Sapling output should take in all the public value assert_equal(mytxdetails["valueBalance"], -zsendmanynotevalue) # send from private note to node 0 and node 2 node0balance = self.nodes[0].getbalance() # 25.99794745 node2balance = self.nodes[2].getbalance() # 16.99790000 recipients = [] recipients.append({ "address": self.nodes[0].getnewaddress(), "amount": 1 }) recipients.append({ "address": self.nodes[2].getnewaddress(), "amount": 1.0 }) wait_and_assert_operationid_status( self.nodes[2], self.nodes[2].z_sendmany(myzaddr, recipients)) self.sync_all() self.nodes[2].generate(1) self.sync_all() node0balance += Decimal('1.0') node2balance += Decimal('1.0') assert_equal(Decimal(self.nodes[0].getbalance()), node0balance) assert_equal(Decimal(self.nodes[0].getbalance("*")), node0balance) assert_equal(Decimal(self.nodes[2].getbalance()), node2balance) assert_equal(Decimal(self.nodes[2].getbalance("*")), node2balance) #send a tx with value in a string (PR#6380 +) txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2") txObj = self.nodes[0].gettransaction(txId) assert_equal(txObj['amount'], Decimal('-2.00000000')) assert_equal(txObj['amountZat'], -200000000) txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001") txObj = self.nodes[0].gettransaction(txId) assert_equal(txObj['amount'], Decimal('-0.00010000')) assert_equal(txObj['amountZat'], -10000) #check if JSON parser can handle scientific notation in strings txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1e-4") txObj = self.nodes[0].gettransaction(txId) assert_equal(txObj['amount'], Decimal('-0.00010000')) assert_equal(txObj['amountZat'], -10000) #this should fail errorString = "" try: txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1f-4") except JSONRPCException as e: errorString = e.error['message'] assert_equal("Invalid amount" in errorString, True) errorString = "" try: self.nodes[0].generate( "2" ) #use a string to as block amount parameter must fail because it's not interpreted as amount except JSONRPCException as e: errorString = e.error['message'] assert_equal("not an integer" in errorString, True) myzaddr = self.nodes[0].z_getnewaddress() recipients = [{"address": myzaddr, "amount": Decimal('0.0')}] errorString = '' # Make sure that amount=0 transactions can use the default fee # without triggering "absurd fee" errors try: myopid = self.nodes[0].z_sendmany(myzaddr, recipients) assert (myopid) except JSONRPCException as e: errorString = e.error['message'] print(errorString) assert (False) # This fee is larger than the default fee and since amount=0 # it should trigger error fee = Decimal('0.1') recipients = [{"address": myzaddr, "amount": Decimal('0.0')}] minconf = 1 errorString = '' try: myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee) except JSONRPCException as e: errorString = e.error['message'] assert ('Small transaction amount' in errorString) # This fee is less than default and greater than amount, but still valid fee = Decimal('0.0000001') recipients = [{"address": myzaddr, "amount": Decimal('0.00000001')}] minconf = 1 errorString = '' try: myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee) assert (myopid) except JSONRPCException as e: errorString = e.error['message'] print(errorString) assert (False) # Make sure amount=0, fee=0 transaction are valid to add to mempool # though miners decide whether to add to a block fee = Decimal('0.0') minconf = 1 recipients = [{"address": myzaddr, "amount": Decimal('0.0')}] errorString = '' try: myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee) assert (myopid) except JSONRPCException as e: errorString = e.error['message'] print(errorString) assert (False)
def run_test (self): print "Mining blocks..." self.nodes[0].generate(4) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[1].generate(101) self.sync_all() assert_equal(self.nodes[0].getbalance(), 40) assert_equal(self.nodes[1].getbalance(), 10) assert_equal(self.nodes[2].getbalance(), 0) assert_equal(self.nodes[0].getbalance("*"), 40) assert_equal(self.nodes[1].getbalance("*"), 10) assert_equal(self.nodes[2].getbalance("*"), 0) # Send 21 BTC from 0 to 2 using sendtoaddress call. # Second transaction will be child of first, and will require a fee self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 0) # Have node0 mine a block, thus it will collect its own fee. self.sync_all() self.nodes[0].generate(1) self.sync_all() # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) self.sync_all() # node0 should end up with 50 btc in block rewards plus fees, but # minus the 21 plus fees sent to node2 assert_equal(self.nodes[0].getbalance(), 50-21) assert_equal(self.nodes[2].getbalance(), 21) assert_equal(self.nodes[0].getbalance("*"), 50-21) assert_equal(self.nodes[2].getbalance("*"), 21) # Node0 should have three 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), 3) # Check 'generated' field of listunspent # Node 0: has one coinbase utxo and two regular utxos assert_equal(sum(int(uxto["generated"] is True) for uxto in node0utxos), 1) # Node 1: has 101 coinbase utxos and no regular utxos node1utxos = self.nodes[1].listunspent(1) assert_equal(len(node1utxos), 101) assert_equal(sum(int(uxto["generated"] is True) for uxto in node1utxos), 101) # Node 2: has no coinbase utxos and two regular utxos node2utxos = self.nodes[2].listunspent(1) assert_equal(len(node2utxos), 2) assert_equal(sum(int(uxto["generated"] is True) for uxto in node2utxos), 0) # 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"] raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) txns_to_send.append(self.nodes[0].signrawtransaction(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) self.nodes[1].sendrawtransaction(txns_to_send[2]["hex"], True) # Have node1 mine a block to confirm transactions: self.sync_all() self.nodes[1].generate(1) self.sync_all() assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 50) assert_equal(self.nodes[0].getbalance("*"), 0) assert_equal(self.nodes[2].getbalance("*"), 50) # Send 10 BTC normal address = self.nodes[0].getnewaddress("") self.nodes[2].settxfee(Decimal('0.001')) self.nodes[2].sendtoaddress(address, 10, "", "", False) self.sync_all() self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('39.99900000')) assert_equal(self.nodes[0].getbalance(), Decimal('10.00000000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('39.99900000')) assert_equal(self.nodes[0].getbalance("*"), Decimal('10.00000000')) # Send 10 BTC with subtract fee from amount self.nodes[2].sendtoaddress(address, 10, "", "", True) self.sync_all() self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('29.99900000')) assert_equal(self.nodes[0].getbalance(), Decimal('19.99900000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('29.99900000')) assert_equal(self.nodes[0].getbalance("*"), Decimal('19.99900000')) # Sendmany 10 BTC self.nodes[2].sendmany("", {address: 10}, 0, "", []) self.sync_all() self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('19.99800000')) assert_equal(self.nodes[0].getbalance(), Decimal('29.99900000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('19.99800000')) assert_equal(self.nodes[0].getbalance("*"), Decimal('29.99900000')) # Sendmany 10 BTC with subtract fee from amount self.nodes[2].sendmany("", {address: 10}, 0, "", [address]) self.sync_all() self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000')) assert_equal(self.nodes[0].getbalance(), Decimal('39.99800000')) assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000')) assert_equal(self.nodes[0].getbalance("*"), Decimal('39.99800000')) # 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) self.nodes.append(start_node(3, self.options.tmpdir)) connect_nodes_bi(self.nodes, 0, 3) sync_blocks(self.nodes) relayed = self.nodes[0].resendwallettransactions() assert_equal(set(relayed), set([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 rawtx #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() inputs = [{"txid":usp[0]['txid'], "vout":usp[0]['vout']}] outputs = {self.nodes[1].getnewaddress(): 9.998, self.nodes[0].getnewaddress(): 11.11} rawTx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") #replace 11.11 with 0.0 (int32) decRawTx = self.nodes[1].decoderawtransaction(rawTx) signedRawTx = self.nodes[1].signrawtransaction(rawTx) decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex']) zeroValueTxid= decRawTx['txid'] self.nodes[1].sendrawtransaction(signedRawTx['hex']) self.sync_all() self.nodes[1].generate(1) #mine a block self.sync_all() unspentTxs = self.nodes[0].listunspent() #zero value tx must be in listunspents output found = False for uTx in unspentTxs: if uTx['txid'] == zeroValueTxid: found = True assert_equal(uTx['amount'], Decimal('0.00000000')); assert(found) #do some -walletbroadcast tests stop_nodes(self.nodes) wait_bitcoinds() self.nodes = start_nodes(3, self.options.tmpdir, [["-walletbroadcast=0"],["-walletbroadcast=0"],["-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() txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2); txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) self.sync_all() self.nodes[1].generate(1) #mine a block, tx should not be in there self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000')); #should not be changed because tx was not broadcasted assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000')); #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(txObjNotBroadcasted['hex']) self.sync_all() self.nodes[1].generate(1) self.sync_all() txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) assert_equal(self.nodes[2].getbalance(), Decimal('11.99800000')); #should not be assert_equal(self.nodes[2].getbalance("*"), Decimal('11.99800000')); #should not be #create another tx txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2); #restart the nodes with -walletbroadcast=1 stop_nodes(self.nodes) wait_bitcoinds() self.nodes = start_nodes(3, self.options.tmpdir) 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) self.nodes[0].generate(1) sync_blocks(self.nodes) #tx should be added to balance because after restarting the nodes tx should be broadcastet assert_equal(self.nodes[2].getbalance(), Decimal('13.99800000')); #should not be assert_equal(self.nodes[2].getbalance("*"), Decimal('13.99800000')); #should not be # send from node 0 to node 2 taddr mytaddr = self.nodes[2].getnewaddress(); mytxid = self.nodes[0].sendtoaddress(mytaddr, 10.0); self.sync_all() self.nodes[0].generate(1) self.sync_all() mybalance = self.nodes[2].z_getbalance(mytaddr) assert_equal(mybalance, Decimal('10.0')); mytxdetails = self.nodes[2].gettransaction(mytxid) myvjoinsplits = mytxdetails["vjoinsplit"] assert_equal(0, len(myvjoinsplits)) # z_sendmany is expected to fail if tx size breaks limit myzaddr = self.nodes[0].z_getnewaddress() recipients = [] num_t_recipients = 3000 amount_per_recipient = Decimal('0.00000001') errorString = '' for i in xrange(0,num_t_recipients): newtaddr = self.nodes[2].getnewaddress() recipients.append({"address":newtaddr, "amount":amount_per_recipient}) try: self.nodes[0].z_sendmany(myzaddr, recipients) except JSONRPCException,e: errorString = e.error['message']
def run_test(self): print "Mining blocks..." self.nodes[0].generate(4) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 11.4375 * 4) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[1].generate(101) self.sync_all() assert_equal(self.nodes[0].getbalance(), 11.4375 * 4) assert_equal(self.nodes[1].getbalance(), 11.4375) assert_equal(self.nodes[2].getbalance(), 0) assert_equal(self.nodes[0].getbalance("*"), 11.4375 * 4) assert_equal(self.nodes[1].getbalance("*"), 11.4375) assert_equal(self.nodes[2].getbalance("*"), 0) # Send 21 BTC from 0 to 2 using sendtoaddress call. # Second transaction will be child of first, and will require a fee self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 12) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11.4375) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 0) # Have node0 mine a block, thus it will collect its own fee. self.sync_all() self.nodes[0].generate(1) self.sync_all() # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) self.sync_all() # node0 should end up with (11.4375*4 + 8.75) btc in block rewards plus fees, but # minus the 23.4375 plus fees sent to node2 assert_equal(self.nodes[0].getbalance(), (11.4375 * 4 + 8.75) - 23.4375) assert_equal(self.nodes[2].getbalance(), 23.4375) assert_equal(self.nodes[0].getbalance("*"), (11.4375 * 4 + 8.75) - 23.4375) assert_equal(self.nodes[2].getbalance("*"), 23.4375) # Node0 should have three 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), 3) # Check 'generated' field of listunspent # Node 0: has one coinbase utxo and two regular utxos assert_equal( sum(int(uxto["generated"] is True) for uxto in node0utxos), 1) # Node 1: has 101 coinbase utxos and no regular utxos node1utxos = self.nodes[1].listunspent(1) assert_equal(len(node1utxos), 101) assert_equal( sum(int(uxto["generated"] is True) for uxto in node1utxos), 101) # Node 2: has no coinbase utxos and two regular utxos node2utxos = self.nodes[2].listunspent(1) assert_equal(len(node2utxos), 2) assert_equal( sum(int(uxto["generated"] is True) for uxto in node2utxos), 0) # 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"] raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) txns_to_send.append(self.nodes[0].signrawtransaction(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) self.nodes[1].sendrawtransaction(txns_to_send[2]["hex"], True) # Have node1 mine a block to confirm transactions: self.sync_all() self.nodes[1].generate(1) self.sync_all() assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 11.4375 * 4 + 8.75) assert_equal(self.nodes[0].getbalance("*"), 0) assert_equal(self.nodes[2].getbalance("*"), 11.4375 * 4 + 8.75) # Send 11.4375 BTC normal address = self.nodes[0].getnewaddress("") self.nodes[2].settxfee(Decimal('0.001')) txid = self.nodes[2].sendtoaddress(address, 11.4375, "", "", False) self.sync_all() self.nodes[2].generate(1) self.sync_all() # 43.0615 = (11.4375*3 + 8.75) - 0.001 assert_equal(self.nodes[2].getbalance(), Decimal('43.0615')) assert_equal(self.nodes[0].getbalance(), Decimal('11.4375')) assert_equal(self.nodes[2].getbalance("*"), Decimal('43.0615')) assert_equal(self.nodes[0].getbalance("*"), Decimal('11.4375')) # Send 11.4375 BTC with subtract fee from amount txid = self.nodes[2].sendtoaddress(address, 11.4375, "", "", True) self.sync_all() self.nodes[2].generate(1) self.sync_all() # 31.624 = (11.4375*2 + 8.75) - 0.001 assert_equal(self.nodes[2].getbalance(), Decimal('31.624')) assert_equal(self.nodes[0].getbalance(), Decimal('22.874')) assert_equal(self.nodes[2].getbalance("*"), Decimal('31.624')) assert_equal(self.nodes[0].getbalance("*"), Decimal('22.874')) # Sendmany 10 BTC self.nodes[2].sendmany("", {address: 10}, 0, "", []) self.sync_all() self.nodes[2].generate(1) self.sync_all() # 21.623 = 31.624 -10 - 0.001 assert_equal(self.nodes[2].getbalance(), Decimal('21.623')) assert_equal(self.nodes[0].getbalance(), Decimal('32.874')) assert_equal(self.nodes[2].getbalance("*"), Decimal('21.623')) assert_equal(self.nodes[0].getbalance("*"), Decimal('32.874')) # Sendmany 10 BTC with subtract fee from amount self.nodes[2].sendmany("", {address: 10}, 0, "", [address]) self.sync_all() self.nodes[2].generate(1) self.sync_all() # 11.623 = 21.623 - 10 assert_equal(self.nodes[2].getbalance(), Decimal('11.623')) assert_equal(self.nodes[0].getbalance(), Decimal('42.873')) assert_equal(self.nodes[2].getbalance("*"), Decimal('11.623')) assert_equal(self.nodes[0].getbalance("*"), Decimal('42.873')) # 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) self.nodes.append(start_node(3, self.options.tmpdir)) connect_nodes_bi(self.nodes, 0, 3) sync_blocks(self.nodes) relayed = self.nodes[0].resendwallettransactions() assert_equal(set(relayed), set([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 rawtx #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() # position 0 might randomly contain an amount different than the wanted one, this is # because coinbase has changed across forks (also in regtest) # That would lead to failure in checks when calling sendrawtransaction newbal = usp[0]['amount'] # print newbal, "\n" inputs = [{"txid": usp[0]['txid'], "vout": usp[0]['vout']}] # outputs = {self.nodes[1].getnewaddress(): 11.4365, self.nodes[0].getnewaddress(): 11.11} outputs = { self.nodes[1].getnewaddress(): newbal, self.nodes[0].getnewaddress(): 11.11 } rawTx = self.nodes[1].createrawtransaction(inputs, outputs).replace( "c0833842", "00000000") #replace 11.11 with 0.0 (int32) decRawTx = self.nodes[1].decoderawtransaction(rawTx) signedRawTx = self.nodes[1].signrawtransaction(rawTx) decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex']) zeroValueTxid = decRawTx['txid'] self.nodes[1].sendrawtransaction(signedRawTx['hex']) self.sync_all() self.nodes[1].generate(1) #mine a block self.sync_all() unspentTxs = self.nodes[0].listunspent( ) #zero value tx must be in listunspents output found = False for uTx in unspentTxs: if uTx['txid'] == zeroValueTxid: found = True assert_equal(uTx['amount'], Decimal('0.00000000')) assert (found) #do some -walletbroadcast tests stop_nodes(self.nodes) wait_bitcoinds() self.nodes = start_nodes( 3, self.options.tmpdir, [["-walletbroadcast=0"], ["-walletbroadcast=0"], ["-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() txIdNotBroadcasted = self.nodes[0].sendtoaddress( self.nodes[2].getnewaddress(), 2) txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) self.sync_all() self.nodes[1].generate(1) #mine a block, tx should not be in there self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('11.623')) #should not be changed because tx was not broadcasted assert_equal(self.nodes[2].getbalance("*"), Decimal('11.623')) #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(txObjNotBroadcasted['hex']) self.sync_all() self.nodes[1].generate(1) self.sync_all() txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) assert_equal(self.nodes[2].getbalance(), Decimal('13.623')) #should not be assert_equal(self.nodes[2].getbalance("*"), Decimal('13.623')) #should not be #create another tx txIdNotBroadcasted = self.nodes[0].sendtoaddress( self.nodes[2].getnewaddress(), 2) #restart the nodes with -walletbroadcast=1 stop_nodes(self.nodes) wait_bitcoinds() self.nodes = start_nodes(3, self.options.tmpdir) 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) self.nodes[0].generate(1) sync_blocks(self.nodes) #tx should be added to balance because after restarting the nodes tx should be broadcastet assert_equal(self.nodes[2].getbalance(), Decimal('15.623')) #should not be assert_equal(self.nodes[2].getbalance("*"), Decimal('15.623')) #should not be # send from node 0 to node 2 taddr mytaddr = self.nodes[2].getnewaddress() mytxid = self.nodes[0].sendtoaddress(mytaddr, 10.0) self.sync_all() self.nodes[0].generate(1) self.sync_all() mybalance = self.nodes[2].z_getbalance(mytaddr) assert_equal(mybalance, Decimal('10.0')) mytxdetails = self.nodes[2].gettransaction(mytxid) myvjoinsplits = mytxdetails["vjoinsplit"] assert_equal(0, len(myvjoinsplits)) # z_sendmany is expected to fail if tx size breaks limit myzaddr = self.nodes[0].z_getnewaddress() recipients = [] num_t_recipients = 3000 amount_per_recipient = Decimal('0.00000001') errorString = '' for i in xrange(0, num_t_recipients): newtaddr = self.nodes[2].getnewaddress() recipients.append({ "address": newtaddr, "amount": amount_per_recipient }) # Issue #2759 Workaround START # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process # loop above to create new addresses, that when z_sendmany is called with a large amount of # rpc data in recipients, the connection fails with a 'broken pipe' error. Making a RPC call # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP # connection into a good state to handle a large amount of data in recipients. self.nodes[0].getinfo() # Issue #2759 Workaround END try: self.nodes[0].z_sendmany(myzaddr, recipients) except JSONRPCException, e: errorString = e.error['message']
def run_test(self): # Sanity-check the test harness assert_equal(self.nodes[0].getblockcount(), 200) # Send some Orchard funds to node 2 for later spending after we split the network acct0 = self.nodes[0].z_getnewaccount()['account'] ua0 = self.nodes[0].z_getaddressforaccount(acct0, ['sapling', 'orchard'])['address'] recipients = [{"address": ua0, "amount": 10}] myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders') wait_and_assert_operationid_status(self.nodes[0], myopid) # Mine the tx & activate NU5 self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal( {'pools': {'orchard': {'valueZat': 10_0000_0000}}, 'minimum_confirmations': 1}, self.nodes[0].z_getbalanceforaccount(acct0)) # Send to a new orchard-only unified address acct1 = self.nodes[1].z_getnewaccount()['account'] ua1 = self.nodes[1].z_getaddressforaccount(acct1, ['orchard'])['address'] recipients = [{"address": ua1, "amount": 1}] myopid = self.nodes[0].z_sendmany(ua0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal( {'pools': {'orchard': {'valueZat': 9_0000_0000}}, 'minimum_confirmations': 1}, self.nodes[0].z_getbalanceforaccount(acct0)) assert_equal( {'pools': {'orchard': {'valueZat': 1_0000_0000}}, 'minimum_confirmations': 1}, self.nodes[1].z_getbalanceforaccount(acct1)) # Send another Orchard transaction from node 0 back to itself, so that the # note commitment tree gets advanced. recipients = [{"address": ua0, "amount": 1}] myopid = self.nodes[0].z_sendmany(ua0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Shut down the nodes, and restart so that we can check wallet load stop_nodes(self.nodes); wait_bitcoinds() self.setup_network() assert_equal( {'pools': {'orchard': {'valueZat': 9_0000_0000}}, 'minimum_confirmations': 1}, self.nodes[0].z_getbalanceforaccount(acct0)) recipients = [{"address": ua0, "amount": Decimal('0.5')}] myopid = self.nodes[1].z_sendmany(ua1, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[1], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal( {'pools': {'orchard': {'valueZat': 9_5000_0000}}, 'minimum_confirmations': 1}, self.nodes[0].z_getbalanceforaccount(acct0))
def run_test(self): # Sanity-check the test harness self.nodes[0].generate(200) assert_equal(self.nodes[0].getblockcount(), 200) self.sync_all() # Verify Sapling address is persisted in wallet (even when Sapling is not yet active) sapling_addr = self.nodes[0].z_getnewaddress('sapling') # Make sure the node has the addresss addresses = self.nodes[0].z_listaddresses() assert_true(sapling_addr in addresses, "Should contain address before restart") # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Make sure we still have the address after restarting addresses = self.nodes[0].z_listaddresses() assert_true(sapling_addr in addresses, "Should contain address after restart") # Activate Sapling self.nodes[0].generate(1) self.sync_all() # Node 0 shields funds to Sapling address taddr0 = self.nodes[0].getnewaddress() recipients = [] recipients.append({"address": sapling_addr, "amount": Decimal('20')}) myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify shielded balance assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('20')) # Verify size of shielded pools pools = self.nodes[0].getblockchaininfo()['valuePools'] assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Verify size of shielded pools pools = self.nodes[0].getblockchaininfo()['valuePools'] assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling # Node 0 sends some shielded funds to Node 1 dest_addr = self.nodes[1].z_getnewaddress('sapling') recipients = [] recipients.append({"address": dest_addr, "amount": Decimal('15')}) myopid = self.nodes[0].z_sendmany(sapling_addr, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify balances assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15')) # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Verify balances assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15')) # Verify importing a spending key will update and persist the nullifiers and witnesses correctly sk0 = self.nodes[0].z_exportkey(sapling_addr) self.nodes[2].z_importkey(sk0, "yes") assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5')) # Restart the nodes stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Verify nullifiers persisted correctly by checking balance # Prior to PR #3590, there will be an error as spent notes are considered unspent: # Assertion failed: expected: <25.00000000> but was: <5> assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5')) # Verity witnesses persisted correctly by sending shielded funds recipients = [] recipients.append({"address": dest_addr, "amount": Decimal('1')}) myopid = self.nodes[2].z_sendmany(sapling_addr, recipients, 1, 0) wait_and_assert_operationid_status(self.nodes[2], myopid) self.sync_all() self.nodes[0].generate(1) self.sync_all() # Verify balances assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('4')) assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('16'))
def run_test(self): self.nodes[0].generate(105) self.sync_all() chain_height = self.nodes[1].getblockcount() assert_equal(chain_height, 105) # Test getrawtransaction changes and the getspentinfo RPC # send coinbase to address a a = self.nodes[1].getnewaddress() txid_a = self.nodes[0].sendtoaddress(a, 2) self.sync_all() self.nodes[0].generate(1) self.sync_all() # send from a to b # (the only utxo on node 1 is from address a) b = self.nodes[2].getnewaddress() txid_b = self.nodes[1].sendtoaddress(b, 1) self.sync_all() # a to b transaction is not confirmed, so it has no height tx_b = self.nodes[2].getrawtransaction(txid_b, 1) assert ('height' not in tx_b) self.sync_all() tx_a = self.nodes[2].getrawtransaction(txid_a, 1) # txid_b is not yet confirmed, so height is invalid (-1) vout = list(filter(lambda o: o['value'] == 2, tx_a['vout'])) assert_equal(vout[0]['spentTxId'], txid_b) assert_equal(vout[0]['spentIndex'], 0) assert_equal(vout[0]['spentHeight'], -1) # confirm txid_b (a to b transaction) self.nodes[0].generate(1) self.sync_all() # Restart all nodes to ensure index files are saved to disk and recovered stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() # Check new fields added to getrawtransaction tx_a = self.nodes[2].getrawtransaction(txid_a, 1) assert_equal(tx_a['vin'][0]['value'], 10) # coinbase assert_equal(tx_a['vin'][0]['valueSat'], 10 * COIN) # we want the non-change (payment) output vout = list(filter(lambda o: o['value'] == 2, tx_a['vout'])) assert_equal(vout[0]['spentTxId'], txid_b) assert_equal(vout[0]['spentIndex'], 0) assert_equal(vout[0]['spentHeight'], 107) assert_equal(tx_a['height'], 106) tx_b = self.nodes[2].getrawtransaction(txid_b, 1) assert_equal(tx_b['vin'][0]['address'], a) assert_equal(tx_b['vin'][0]['value'], 2) assert_equal(tx_b['vin'][0]['valueSat'], 2 * COIN) # since this transaction's outputs haven't yet been # spent, these fields should not be present assert ('spentTxId' not in tx_b['vout'][0]) assert ('spentIndex' not in tx_b['vout'][0]) assert ('spentHeight' not in tx_b['vout'][0]) assert_equal(tx_b['height'], 107)
assert_equal(sc_post_regeneration["last certificate epoch"], Decimal(0)) assert_equal( sc_post_regeneration["balance"], creation_amount + fwt_amount + fwt_amount_immature_at_epoch - bwt_amount) assert (cert_epoch_1 not in self.nodes[0].getrawmempool()) assert (speding_bwd_tx not in self.nodes[0].getrawmempool()) assert_equal(node2_balance_ante_cert, self.nodes[2].getbalance()) assert_equal(node3_balance_ante_cert, self.nodes[3].getbalance()) mark_logs( "Checking certificates persistance stopping and restarting nodes", self.nodes, DEBUG_MODE) stop_nodes(self.nodes) wait_bitcoinds() self.setup_network(False) for idx, node in enumerate(self.nodes): mark_logs("Checking Node{} after restart".format(idx), self.nodes, DEBUG_MODE) sc_post_regeneration = node.getscinfo(scid) assert_equal(sc_post_regeneration["last certificate epoch"], Decimal(0)) assert_equal( sc_post_regeneration["balance"], creation_amount + fwt_amount + fwt_amount_immature_at_epoch - bwt_amount) assert (cert_epoch_1 not in self.nodes[0].getrawmempool()) assert (speding_bwd_tx not in self.nodes[0].getrawmempool())
def main(self): import optparse parser = optparse.OptionParser(usage="%prog [options]") parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true", help="Leave bitcoinds and test.* datadir on exit or error") parser.add_option("--noshutdown", dest="noshutdown", default=False, action="store_true", help="Don't stop bitcoinds after the test execution") parser.add_option("--zendir", dest="zendir", default="ZenCore/src", help="Source directory containing zend/zen-cli (default: %default)") parser.add_option("--scjarpath", dest="scjarpath", default="../examples/simpleapp/target/Sidechains-SDK-simpleapp-0.2.0.jar;../examples/simpleapp/target/lib/* com.horizen.examples.SimpleApp", #New option. Main class path won't be needed in future help="Directory containing .jar file for SC (default: %default)") parser.add_option("--tmpdir", dest="tmpdir", default="../examples/simpleapp/target/tmp", help="Root directory for datadirs") parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true", help="Print out all RPC calls as they are made") self.add_options(parser) self.sc_add_options(parser) (self.options, self.args) = parser.parse_args() if self.options.trace_rpc: import logging logging.basicConfig(level=logging.DEBUG) os.environ['PATH'] = self.options.zendir+":"+os.environ['PATH'] check_json_precision() success = False try: if not os.path.isdir(self.options.tmpdir): os.makedirs(self.options.tmpdir) print("Initializing test directory "+self.options.tmpdir) self.setup_chain() self.setup_network() self.sc_setup_chain() self.sc_setup_network() self.run_test() success = True except JSONRPCException as e: print("JSONRPC error: "+e.error['message']) traceback.print_tb(sys.exc_info()[2]) except SCAPIException as e: #New exception for SC API print("SCAPI error: "+e.error) traceback.print_tb(sys.exc_info()[2]) except TimeoutException as e: print("Timeout while: " + e.operation) #Timeout for SC Operations traceback.print_tb(sys.exc_info()[2]) except AssertionError as e: print("Assertion failed: "+e.message) traceback.print_tb(sys.exc_info()[2]) except Exception as e: print("Unexpected exception caught during testing: "+str(e)) traceback.print_tb(sys.exc_info()[2]) if not self.options.noshutdown: #Support for tests with MC only, SC only, MC/SC if hasattr(self,"sc_nodes"): print("Stopping SC nodes") stop_sc_nodes(self.sc_nodes) if hasattr(self, "nodes"): print("Stopping MC nodes") stop_nodes(self.nodes) wait_bitcoinds() else: print("Note: client processes were not stopped and may still be running") if not self.options.nocleanup and not self.options.noshutdown: print("Cleaning up") shutil.rmtree(self.options.tmpdir) if success: print("Test successful") sys.exit(0) else: print("Failed") sys.exit(1)
def run_test(self): def get_source(listed_addresses, source): return next(src for src in listed_addresses if src['source'] == source) print("Testing height 1 (Sapling)") self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[0].getblockcount(), 1) listed_addresses = self.list_addresses(0, ['mnemonic_seed']) # There should be a single address from the coinbase, which was derived # from the mnemonic seed. assert 'transparent' in get_source(listed_addresses, 'mnemonic_seed') # If we import a t-address, we should see imported_watchonly as a source. taddr_import = self.nodes[1].getnewaddress() self.nodes[0].importaddress(taddr_import) listed_addresses = self.list_addresses(0, ['imported_watchonly', 'mnemonic_seed']) imported_watchonly_src = get_source(listed_addresses, 'imported_watchonly') assert_equal(imported_watchonly_src['transparent']['addresses'][0], taddr_import) account = self.nodes[0].z_getnewaccount()['account'] sprout_1 = self.nodes[0].z_getnewaddress('sprout') sapling_1 = self.nodes[0].z_getnewaddress('sapling') unified_1 = self.nodes[0].z_getaddressforaccount(account)['address'] types_and_addresses = [ ('sprout', sprout_1), ('sapling', sapling_1), ('unified', unified_1), ] for addr_type, addr in types_and_addresses: res = self.nodes[0].z_validateaddress(addr) assert res['isvalid'] # assert res['ismine'] # this isn't present for unified addresses assert_equal(res['type'], addr_type) # We should see the following sources: # - imported_watchonly (for the previously-imported t-addr) # - legacy_random (for the new Sprout address) # - mnemonic_seed (for the previous t-addrs and the new Sapling and Unified addrs) listed_addresses = self.list_addresses(0, ['imported_watchonly', 'legacy_random', 'mnemonic_seed']) legacy_random_src = get_source(listed_addresses, 'legacy_random') mnemonic_seed_src = get_source(listed_addresses, 'mnemonic_seed') # Check Sprout addrs assert_equal(legacy_random_src['sprout']['addresses'], [sprout_1]) # Check Sapling addrs assert_equal( set([(obj['zip32KeyPath'], x) for obj in mnemonic_seed_src['sapling'] for x in obj['addresses']]), set([("m/32'/1'/2147483647'/0'", sapling_1)]), ) # Check Unified addrs unified_obj = mnemonic_seed_src['unified'] assert_equal(unified_obj[0]['account'], 0) assert_equal(unified_obj[0]['addresses'][0]['address'], unified_1) assert 'diversifier_index' in unified_obj[0]['addresses'][0] assert_equal(unified_obj[0]['addresses'][0]['receiver_types'], ['p2pkh', 'sapling', 'orchard']) # import the key for sapling_1 into node 1 sapling_1_key = self.nodes[0].z_exportkey(sapling_1) self.nodes[1].z_importkey(sapling_1_key) # verify that we see the imported source listed_addresses = self.list_addresses(1, ['imported', 'mnemonic_seed']) imported_src = get_source(listed_addresses, 'imported') assert_equal(imported_src['sapling'][0]['addresses'], [sapling_1]) # stop the nodes & restart to ensure that the imported address # still shows up in listaddresses output stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() listed_addresses = self.list_addresses(1, ['imported', 'mnemonic_seed']) imported_src = get_source(listed_addresses, 'imported') assert_equal(imported_src['sapling'][0]['addresses'], [sapling_1]) print("Testing height 2 (NU5)") self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[0].getblockcount(), 2) # Sprout address generation is no longer allowed sapling_2 = self.nodes[0].z_getnewaddress('sapling') unified_2 = self.nodes[0].z_getaddressforaccount(account)['address'] types_and_addresses = [ ('sapling', sapling_2), ('unified', unified_2), ] for addr_type, addr in types_and_addresses: res = self.nodes[0].z_validateaddress(addr) assert res['isvalid'] # assert res['ismine'] # this isn't present for unified addresses assert_equal(res['type'], addr_type) # We should see the same sources (address generation does not change across the NU5 boundary). listed_addresses = self.list_addresses(0, ['imported_watchonly', 'legacy_random', 'mnemonic_seed']) legacy_random_src = get_source(listed_addresses, 'legacy_random') mnemonic_seed_src = get_source(listed_addresses, 'mnemonic_seed') # Check Sprout addrs assert_equal(legacy_random_src['sprout']['addresses'], [sprout_1]) # Check Sapling addrs assert_equal( set([(obj['zip32KeyPath'], x) for obj in mnemonic_seed_src['sapling'] for x in obj['addresses']]), set([ ("m/32'/1'/2147483647'/0'", sapling_1), ("m/32'/1'/2147483647'/1'", sapling_2), ]), ) # Check Unified addrs unified_obj = mnemonic_seed_src['unified'] assert_equal(unified_obj[0]['account'], 0) assert_equal( set([addr['address'] for addr in unified_obj[0]['addresses']]), set([unified_1, unified_2]), ) assert 'diversifier_index' in unified_obj[0]['addresses'][0] assert 'diversifier_index' in unified_obj[0]['addresses'][1] assert_equal(unified_obj[0]['addresses'][0]['receiver_types'], ['p2pkh', 'sapling', 'orchard']) assert_equal(unified_obj[0]['addresses'][1]['receiver_types'], ['p2pkh', 'sapling', 'orchard']) print("Generate mature coinbase, spend to create and detect change") self.nodes[0].generate(100) self.sync_all() self.nodes[0].sendmany('', {taddr_import: 1}) listed_addresses = self.list_addresses(0, ['imported_watchonly', 'legacy_random', 'mnemonic_seed']) mnemonic_seed_src = get_source(listed_addresses, 'mnemonic_seed') assert len(mnemonic_seed_src['transparent']['changeAddresses']) > 0