def test_no_blockhash(self): txid = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1) blockhash, = self.nodes[2].generate(1) self.sync_all() txs = self.nodes[0].listtransactions() assert_array_result(txs, {"txid": txid}, { "category": "receive", "amount": 1, "blockhash": blockhash, "confirmations": 1, }) assert_equal( self.nodes[0].listsinceblock(), {"lastblock": blockhash, "removed": [], "transactions": txs}) assert_equal( self.nodes[0].listsinceblock(""), {"lastblock": blockhash, "removed": [], "transactions": txs})
def assert_category(self, category, address, txid, skip): assert_array_result(self.nodes[0].listtransactions(skip=skip), {"address": address}, {"category": category}) assert_array_result(self.nodes[0].listsinceblock()["transactions"], {"address": address}, {"category": category}) assert_array_result(self.nodes[0].gettransaction(txid)["details"], {"address": address}, {"category": category})
def run_test(self): self.nodes[0].generate(1) # Get out of IBD self.sync_all() # Simple send, 0 to 1: txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, {"category": "send", "amount": Decimal("-0.1"), "confirmations": 0}) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, {"category": "receive", "amount": Decimal("0.1"), "confirmations": 0}) # mine a block, confirmations should change: self.nodes[0].generate(1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, {"category": "send", "amount": Decimal("-0.1"), "confirmations": 1}) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, {"category": "receive", "amount": Decimal("0.1"), "confirmations": 1}) # send-to-self: txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.2) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid, "category": "send"}, {"amount": Decimal("-0.2")}) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid, "category": "receive"}, {"amount": Decimal("0.2")}) # sendmany from node1: twice to self, twice to node2: send_to = {self.nodes[0].getnewaddress(): 0.11, self.nodes[1].getnewaddress(): 0.22, self.nodes[0].getnewaddress(): 0.33, self.nodes[1].getnewaddress(): 0.44} txid = self.nodes[1].sendmany("", send_to) self.sync_all() assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-0.11")}, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), {"category": "receive", "amount": Decimal("0.11")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-0.22")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "receive", "amount": Decimal("0.22")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-0.33")}, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), {"category": "receive", "amount": Decimal("0.33")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-0.44")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "receive", "amount": Decimal("0.44")}, {"txid": txid}) pubkey = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['pubkey'] multisig = self.nodes[1].createmultisig(1, [pubkey]) self.nodes[0].importaddress(multisig["redeemScript"], "watchonly", False, True) txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1) self.nodes[1].generate(1) self.sync_all() assert len(self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=False)) == 0 assert_array_result(self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=True), {"category": "receive", "amount": Decimal("0.1")}, {"txid": txid, "label": "watchonly"}) self.run_rbf_opt_in_test()
def run_test(self): # Generate block to get out of IBD self.nodes[0].generate(1) self.log.info("listreceivedbyaddress Test") # Send from node 0 to 1 addr = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # Check not listed in listreceivedbyaddress because has 0 confirmations assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": addr}, {}, True) # Bury Tx under 10 block so it will be returned by listreceivedbyaddress self.nodes[1].generate(10) self.sync_all() assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": addr}, { "address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [ txid, ] }) # With min confidence < 10 assert_array_result(self.nodes[1].listreceivedbyaddress(5), {"address": addr}, { "address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [ txid, ] }) # With min confidence > 10, should not find Tx assert_array_result(self.nodes[1].listreceivedbyaddress(11), {"address": addr}, {}, True) # Empty Tx empty_addr = self.nodes[1].getnewaddress() assert_array_result(self.nodes[1].listreceivedbyaddress(0, True), {"address": empty_addr}, { "address": empty_addr, "label": "", "amount": 0, "confirmations": 0, "txids": [] }) #Test Address filtering #Only on addr expected = { "address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [ txid, ] } res = self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True, address_filter=addr) assert_array_result(res, {"address": addr}, expected) assert_equal(len(res), 1) #Error on invalid address assert_raises_rpc_error(-4, "address_filter parameter was invalid", self.nodes[1].listreceivedbyaddress, minconf=0, include_empty=True, include_watchonly=True, address_filter="bamboozling") #Another address receive money res = self.nodes[1].listreceivedbyaddress(0, True, True) assert_equal(len(res), 2) #Right now 2 entries other_addr = self.nodes[1].getnewaddress() txid2 = self.nodes[0].sendtoaddress(other_addr, 0.1) self.nodes[0].generate(1) self.sync_all() #Same test as above should still pass expected = { "address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 11, "txids": [ txid, ] } res = self.nodes[1].listreceivedbyaddress(0, True, True, addr) assert_array_result(res, {"address": addr}, expected) assert_equal(len(res), 1) #Same test as above but with other_addr should still pass expected = { "address": other_addr, "label": "", "amount": Decimal("0.1"), "confirmations": 1, "txids": [ txid2, ] } res = self.nodes[1].listreceivedbyaddress(0, True, True, other_addr) assert_array_result(res, {"address": other_addr}, expected) assert_equal(len(res), 1) #Should be two entries though without filter res = self.nodes[1].listreceivedbyaddress(0, True, True) assert_equal(len(res), 3) #Became 3 entries #Not on random addr other_addr = self.nodes[0].getnewaddress( ) # note on node[0]! just a random addr res = self.nodes[1].listreceivedbyaddress(0, True, True, other_addr) assert_equal(len(res), 0) self.log.info("getreceivedbyaddress Test") # Send from node 0 to 1 addr = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # Check balance is 0 because of 0 confirmations balance = self.nodes[1].getreceivedbyaddress(addr) assert_equal(balance, Decimal("0.0")) # Check balance is 0.1 balance = self.nodes[1].getreceivedbyaddress(addr, 0) assert_equal(balance, Decimal("0.1")) # Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress self.nodes[1].generate(10) self.sync_all() balance = self.nodes[1].getreceivedbyaddress(addr) assert_equal(balance, Decimal("0.1")) # Trying to getreceivedby for an address the wallet doesn't own should return an error assert_raises_rpc_error(-4, "Address not found in wallet", self.nodes[0].getreceivedbyaddress, addr) self.log.info("listreceivedbylabel + getreceivedbylabel Test") # set pre-state addrArr = self.nodes[1].getnewaddress() label = self.nodes[1].getaccount(addrArr) received_by_label_json = [ r for r in self.nodes[1].listreceivedbylabel() if r["label"] == label ][0] balance_by_label = self.nodes[1].getreceivedbylabel(label) txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # listreceivedbylabel should return received_by_label_json because of 0 confirmations assert_array_result(self.nodes[1].listreceivedbylabel(), {"label": label}, received_by_label_json) # getreceivedbyaddress should return same balance because of 0 confirmations balance = self.nodes[1].getreceivedbylabel(label) assert_equal(balance, balance_by_label) self.nodes[1].generate(10) self.sync_all() # listreceivedbylabel should return updated received list assert_array_result( self.nodes[1].listreceivedbylabel(), {"label": label}, { "label": received_by_label_json["label"], "amount": (received_by_label_json["amount"] + Decimal("0.1")) }) # getreceivedbylabel should return updated receive total balance = self.nodes[1].getreceivedbylabel(label) assert_equal(balance, balance_by_label + Decimal("0.1")) # Create a new label named "mynewlabel" that has a 0 balance self.nodes[1].getlabeladdress(label="mynewlabel", force=True) received_by_label_json = [ r for r in self.nodes[1].listreceivedbylabel(0, True) if r["label"] == "mynewlabel" ][0] # Test includeempty of listreceivedbylabel assert_equal(received_by_label_json["amount"], Decimal("0.0")) # Test getreceivedbylabel for 0 amount labels balance = self.nodes[1].getreceivedbylabel("mynewlabel") assert_equal(balance, Decimal("0.0"))
def run_test(self): # Generate block to get out of IBD self.nodes[0].generate(1) sync_blocks(self.nodes) self.log.info("listreceivedbyaddress Test") # Send from node 0 to 1 addr = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # Check not listed in listreceivedbyaddress because has 0 confirmations assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": addr}, {}, True) # Bury Tx under 10 block so it will be returned by listreceivedbyaddress self.nodes[1].generate(10) self.sync_all() assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": addr}, {"address": addr, "account": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]}) # With min confidence < 10 assert_array_result(self.nodes[1].listreceivedbyaddress(5), {"address": addr}, {"address": addr, "account": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]}) # With min confidence > 10, should not find Tx assert_array_result(self.nodes[1].listreceivedbyaddress(11), {"address": addr}, {}, True) # Empty Tx addr = self.nodes[1].getnewaddress() assert_array_result(self.nodes[1].listreceivedbyaddress(0, True), {"address": addr}, {"address": addr, "account": "", "amount": 0, "confirmations": 0, "txids": []}) self.log.info("getreceivedbyaddress Test") # Send from node 0 to 1 addr = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # Check balance is 0 because of 0 confirmations balance = self.nodes[1].getreceivedbyaddress(addr) assert_equal(balance, Decimal("0.0")) # Check balance is 0.1 balance = self.nodes[1].getreceivedbyaddress(addr, 0) assert_equal(balance, Decimal("0.1")) # Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress self.nodes[1].generate(10) self.sync_all() balance = self.nodes[1].getreceivedbyaddress(addr) assert_equal(balance, Decimal("0.1")) # Trying to getreceivedby for an address the wallet doesn't own should return an error assert_raises_rpc_error(-4, "Address not found in wallet", self.nodes[0].getreceivedbyaddress, addr) self.log.info("listreceivedbyaccount + getreceivedbyaccount Test") # set pre-state addrArr = self.nodes[1].getnewaddress() account = self.nodes[1].getaccount(addrArr) received_by_account_json = [r for r in self.nodes[1].listreceivedbyaccount() if r["account"] == account][0] balance_by_account = self.nodes[1].getreceivedbyaccount(account) txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # listreceivedbyaccount should return received_by_account_json because of 0 confirmations assert_array_result(self.nodes[1].listreceivedbyaccount(), {"account": account}, received_by_account_json) # getreceivedbyaddress should return same balance because of 0 confirmations balance = self.nodes[1].getreceivedbyaccount(account) assert_equal(balance, balance_by_account) self.nodes[1].generate(10) self.sync_all() # listreceivedbyaccount should return updated account balance assert_array_result(self.nodes[1].listreceivedbyaccount(), {"account": account}, {"account": received_by_account_json["account"], "amount": (received_by_account_json["amount"] + Decimal("0.1"))}) # getreceivedbyaddress should return updates balance balance = self.nodes[1].getreceivedbyaccount(account) assert_equal(balance, balance_by_account + Decimal("0.1")) # Create a new account named "mynewaccount" that has a 0 balance self.nodes[1].getaccountaddress("mynewaccount") received_by_account_json = [r for r in self.nodes[1].listreceivedbyaccount(0, True) if r["account"] == "mynewaccount"][0] # Test includeempty of listreceivedbyaccount assert_equal(received_by_account_json["amount"], Decimal("0.0")) # Test getreceivedbyaccount for 0 amount accounts balance = self.nodes[1].getreceivedbyaccount("mynewaccount") assert_equal(balance, Decimal("0.0"))
def run_rbf_opt_in_test(self): # Check whether a transaction signals opt-in RBF itself def is_opt_in(node, txid): rawtx = node.getrawtransaction(txid, 1) for x in rawtx["vin"]: if x["sequence"] < 0xfffffffe: return True return False # Find an unconfirmed output matching a certain txid def get_unconfirmed_utxo_entry(node, txid_to_match): utxo = node.listunspent(0, 0) for i in utxo: if i["txid"] == txid_to_match: return i return None # 1. Chain a few transactions that don't opt-in. txid_1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) assert (not is_opt_in(self.nodes[0], txid_1)) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_1}, {"bip125-replaceable": "no"}) sync_mempools(self.nodes) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_1}, {"bip125-replaceable": "no"}) # Tx2 will build off txid_1, still not opting in to RBF. utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[0], txid_1) assert_equal(utxo_to_use["safe"], True) utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1) utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1) assert_equal(utxo_to_use["safe"], False) # Create tx2 using createrawtransaction inputs = [{"txid": utxo_to_use["txid"], "vout": utxo_to_use["vout"]}] outputs = {self.nodes[0].getnewaddress(): 0.999} tx2 = self.nodes[1].createrawtransaction(inputs, outputs) tx2_signed = self.nodes[1].signrawtransactionwithwallet(tx2)["hex"] txid_2 = self.nodes[1].sendrawtransaction(tx2_signed) # ...and check the result assert (not is_opt_in(self.nodes[1], txid_2)) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_2}, {"bip125-replaceable": "no"}) sync_mempools(self.nodes) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_2}, {"bip125-replaceable": "no"}) # Tx3 will opt-in to RBF utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[0], txid_2) inputs = [{"txid": txid_2, "vout": utxo_to_use["vout"]}] outputs = {self.nodes[1].getnewaddress(): 0.998} tx3 = self.nodes[0].createrawtransaction(inputs, outputs) tx3_modified = tx_from_hex(tx3) tx3_modified.vin[0].nSequence = 0 tx3 = bytes_to_hex_str(tx3_modified.serialize()) tx3_signed = self.nodes[0].signrawtransactionwithwallet(tx3)['hex'] txid_3 = self.nodes[0].sendrawtransaction(tx3_signed) assert (is_opt_in(self.nodes[0], txid_3)) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_3}, {"bip125-replaceable": "yes"}) sync_mempools(self.nodes) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_3}, {"bip125-replaceable": "yes"}) # Tx4 will chain off tx3. Doesn't signal itself, but depends on one # that does. utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_3) inputs = [{"txid": txid_3, "vout": utxo_to_use["vout"]}] outputs = {self.nodes[0].getnewaddress(): 0.997} tx4 = self.nodes[1].createrawtransaction(inputs, outputs) tx4_signed = self.nodes[1].signrawtransactionwithwallet(tx4)["hex"] txid_4 = self.nodes[1].sendrawtransaction(tx4_signed) assert (not is_opt_in(self.nodes[1], txid_4)) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "yes"}) sync_mempools(self.nodes) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "yes"}) # Replace tx3, and check that tx4 becomes unknown tx3_b = tx3_modified tx3_b.vout[0].nValue -= int(Decimal("0.004") * COIN) # bump the fee tx3_b = bytes_to_hex_str(tx3_b.serialize()) tx3_b_signed = self.nodes[0].signrawtransactionwithwallet(tx3_b)['hex'] txid_3b = self.nodes[0].sendrawtransaction(tx3_b_signed, True) assert (is_opt_in(self.nodes[0], txid_3b)) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "unknown"}) sync_mempools(self.nodes) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "unknown"}) # Check gettransaction as well: for n in self.nodes[0:2]: assert_equal(n.gettransaction(txid_1)["bip125-replaceable"], "no") assert_equal(n.gettransaction(txid_2)["bip125-replaceable"], "no") assert_equal(n.gettransaction(txid_3)["bip125-replaceable"], "yes") assert_equal( n.gettransaction(txid_3b)["bip125-replaceable"], "yes") assert_equal( n.gettransaction(txid_4)["bip125-replaceable"], "unknown") # After mining a transaction, it's no longer BIP125-replaceable self.nodes[0].generate(1) assert (txid_3b not in self.nodes[0].getrawmempool()) assert_equal( self.nodes[0].gettransaction(txid_3b)["bip125-replaceable"], "no") assert_equal( self.nodes[0].gettransaction(txid_4)["bip125-replaceable"], "unknown")
def run_test(self): # Check that there's no UTXO on none of the nodes assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("Mining blocks...") self.nodes[0].generate(1) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 50) assert_equal(walletinfo['balance'], 0) self.sync_all(self.nodes[0:3]) self.nodes[1].generate(101) self.sync_all(self.nodes[0:3]) assert_equal(self.nodes[0].getbalance(), 50) assert_equal(self.nodes[1].getbalance(), 50) assert_equal(self.nodes[2].getbalance(), 0) # Check that only first and second nodes have UTXOs utxos = self.nodes[0].listunspent() assert_equal(len(utxos), 1) assert_equal(len(self.nodes[1].listunspent()), 1) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("test gettxout") confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"] # First, outputs that are unspent both in the chain and in the # mempool should appear with or without include_mempool txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=False) assert_equal(txout['value'], 50) txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=True) assert_equal(txout['value'], 50) # Send 21 BPS from 0 to 2 using sendtoaddress call. self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) self.log.info("test gettxout (second part)") # utxo spent in mempool should be visible if you exclude mempool # but invisible if you include mempool txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False) assert_equal(txout['value'], 50) txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True) assert txout is None # new utxo from mempool should be invisible if you exclude mempool # but visible if you include mempool txout = self.nodes[0].gettxout(mempool_txid, 0, False) assert txout is None txout1 = self.nodes[0].gettxout(mempool_txid, 0, True) txout2 = self.nodes[0].gettxout(mempool_txid, 1, True) # note the mempool tx will have randomly assigned indices # but 10 will go to node2 and the rest will go to node0 balance = self.nodes[0].getbalance() assert_equal(set([txout1['value'], txout2['value']]), set([10, balance])) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 0) # Have node0 mine a block, thus it will collect its own fee. self.nodes[0].generate(1) self.sync_all(self.nodes[0:3]) # Exercise locking of unspent outputs unspent_0 = self.nodes[2].listunspent()[0] unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} assert_raises_rpc_error(-8, "Invalid parameter, expected locked output", self.nodes[2].lockunspent, True, [unspent_0]) self.nodes[2].lockunspent(False, [unspent_0]) assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0]) assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) assert_equal([unspent_0], self.nodes[2].listlockunspent()) self.nodes[2].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[2].listlockunspent()), 0) assert_raises_rpc_error(-8, "txid must be of length 64 (not 34, for '0000000000000000000000000000000000')", self.nodes[2].lockunspent, False, [{"txid": "0000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[2].lockunspent, False, [{"txid": "ZZZ0000000000000000000000000000000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "Invalid parameter, unknown transaction", self.nodes[2].lockunspent, False, [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "Invalid parameter, vout index out of bounds", self.nodes[2].lockunspent, False, [{"txid": unspent_0["txid"], "vout": 999}]) # The lock on a manually selected output is ignored unspent_0 = self.nodes[1].listunspent()[0] self.nodes[1].lockunspent(False, [unspent_0]) tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 }) self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True}) # fundrawtransaction can lock an input self.nodes[1].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[1].listlockunspent()), 0) tx = self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True})['hex'] assert_equal(len(self.nodes[1].listlockunspent()), 1) # Send transaction tx = self.nodes[1].signrawtransactionwithwallet(tx)["hex"] self.nodes[1].sendrawtransaction(tx) assert_equal(len(self.nodes[1].listlockunspent()), 0) # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) self.sync_all(self.nodes[0:3]) # node0 should end up with 100 BPS in block rewards plus fees, but # minus the 21 plus fees sent to node2 assert_equal(self.nodes[0].getbalance(), 100 - 21) assert_equal(self.nodes[2].getbalance(), 21) # Node0 should have two unspent outputs. # Create a couple of transactions to send them to node2, submit them through # node1, and make sure both node0 and node2 pick them up properly: node0utxos = self.nodes[0].listunspent(1) assert_equal(len(node0utxos), 2) # create both transactions txns_to_send = [] for utxo in node0utxos: inputs = [] outputs = {} inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) outputs[self.nodes[2].getnewaddress()] = utxo["amount"] - 3 raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) txns_to_send.append(self.nodes[0].signrawtransactionwithwallet(raw_tx)) # Have node 1 (miner) send the transactions self.nodes[1].sendrawtransaction(hexstring=txns_to_send[0]["hex"], maxfeerate=0) self.nodes[1].sendrawtransaction(hexstring=txns_to_send[1]["hex"], maxfeerate=0) # Have node1 mine a block to confirm transactions: self.nodes[1].generate(1) self.sync_all(self.nodes[0:3]) assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 94) # Verify that a spent output cannot be locked anymore spent_0 = {"txid": node0utxos[0]["txid"], "vout": node0utxos[0]["vout"]} assert_raises_rpc_error(-8, "Invalid parameter, expected unspent output", self.nodes[0].lockunspent, False, [spent_0]) # Send 10 BPS normal address = self.nodes[0].getnewaddress("test") fee_per_byte = Decimal('0.001') / 1000 self.nodes[2].settxfee(fee_per_byte * 1000) txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(self.nodes[0].getbalance(), Decimal('10')) # Send 10 BPS with subtract fee from amount txid = self.nodes[2].sendtoaddress(address, 10, "", "", True) self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) # Sendmany 10 BPS txid = self.nodes[2].sendmany('', {address: 10}, 0, "", []) self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) node_0_bal += Decimal('10') node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(self.nodes[0].getbalance(), node_0_bal) # Sendmany 10 BPS with subtract fee from amount txid = self.nodes[2].sendmany('', {address: 10}, 0, "", [address]) self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) # Sendmany with explicit fee (BTC/kB) # Throw if no conf_target provided assert_raises_rpc_error(-8, "Selected estimate_mode requires a fee rate", self.nodes[2].sendmany, amounts={ address: 10 }, estimate_mode='bTc/kB') # Throw if negative feerate assert_raises_rpc_error(-3, "Amount out of range", self.nodes[2].sendmany, amounts={ address: 10 }, conf_target=-1, estimate_mode='bTc/kB') fee_per_kb = 0.0002500 explicit_fee_per_byte = Decimal(fee_per_kb) / 1000 txid = self.nodes[2].sendmany( amounts={ address: 10 }, conf_target=fee_per_kb, estimate_mode='bTc/kB', ) self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), explicit_fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal += Decimal('10') assert_equal(self.nodes[0].getbalance(), node_0_bal) # Sendmany with explicit fee (SAT/B) # Throw if no conf_target provided assert_raises_rpc_error(-8, "Selected estimate_mode requires a fee rate", self.nodes[2].sendmany, amounts={ address: 10 }, estimate_mode='sat/b') # Throw if negative feerate assert_raises_rpc_error(-3, "Amount out of range", self.nodes[2].sendmany, amounts={ address: 10 }, conf_target=-1, estimate_mode='sat/b') fee_sat_per_b = 2 fee_per_kb = fee_sat_per_b / 100000.0 explicit_fee_per_byte = Decimal(fee_per_kb) / 1000 txid = self.nodes[2].sendmany( amounts={ address: 10 }, conf_target=fee_sat_per_b, estimate_mode='sAT/b', ) self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) balance = self.nodes[2].getbalance() node_2_bal = self.check_fee_amount(balance, node_2_bal - Decimal('10'), explicit_fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(balance, node_2_bal) node_0_bal += Decimal('10') assert_equal(self.nodes[0].getbalance(), node_0_bal) self.start_node(3, self.nodes[3].extra_args) connect_nodes(self.nodes[0], 3) self.sync_all() # check if we can list zero value tx as available coins # 1. create raw_tx # 2. hex-changed one output to 0.0 # 3. sign and send # 4. check if recipient (node0) can list the zero value tx usp = self.nodes[1].listunspent(query_options={'minimumAmount': '49.998'})[0] inputs = [{"txid": usp['txid'], "vout": usp['vout']}] outputs = {self.nodes[1].getnewaddress(): 49.998, self.nodes[0].getnewaddress(): 11.11} raw_tx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") # replace 11.11 with 0.0 (int32) signed_raw_tx = self.nodes[1].signrawtransactionwithwallet(raw_tx) decoded_raw_tx = self.nodes[1].decoderawtransaction(signed_raw_tx['hex']) zero_value_txid = decoded_raw_tx['txid'] self.nodes[1].sendrawtransaction(signed_raw_tx['hex']) self.sync_all() self.nodes[1].generate(1) # mine a block self.sync_all() unspent_txs = self.nodes[0].listunspent() # zero value tx must be in listunspents output found = False for uTx in unspent_txs: if uTx['txid'] == zero_value_txid: found = True assert_equal(uTx['amount'], Decimal('0')) assert found # do some -walletbroadcast tests self.stop_nodes() self.start_node(0, ["-walletbroadcast=0"]) self.start_node(1, ["-walletbroadcast=0"]) self.start_node(2, ["-walletbroadcast=0"]) connect_nodes(self.nodes[0], 1) connect_nodes(self.nodes[1], 2) connect_nodes(self.nodes[0], 2) self.sync_all(self.nodes[0:3]) txid_not_broadcast = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast) self.nodes[1].generate(1) # mine a block, tx should not be in there self.sync_all(self.nodes[0:3]) assert_equal(self.nodes[2].getbalance(), node_2_bal) # should not be changed because tx was not broadcasted # now broadcast from another node, mine a block, sync, and check the balance self.nodes[1].sendrawtransaction(tx_obj_not_broadcast['hex']) self.nodes[1].generate(1) self.sync_all(self.nodes[0:3]) node_2_bal += 2 tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast) assert_equal(self.nodes[2].getbalance(), node_2_bal) # create another tx self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) # restart the nodes with -walletbroadcast=1 self.stop_nodes() self.start_node(0) self.start_node(1) self.start_node(2) connect_nodes(self.nodes[0], 1) connect_nodes(self.nodes[1], 2) connect_nodes(self.nodes[0], 2) self.sync_blocks(self.nodes[0:3]) self.nodes[0].generate(1) self.sync_blocks(self.nodes[0:3]) node_2_bal += 2 # tx should be added to balance because after restarting the nodes tx should be broadcast assert_equal(self.nodes[2].getbalance(), node_2_bal) # send a tx with value in a string (PR#6380 +) txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-2')) txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-0.0001')) # check if JSON parser can handle scientific notation in strings txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1e-4") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-0.0001')) # General checks for errors from incorrect inputs # This will raise an exception because the amount is negative assert_raises_rpc_error(-3, "Amount out of range", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "-1") # This will raise an exception because the amount type is wrong assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4") # This will raise an exception since generate does not accept a string assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2") if not self.options.descriptors: # This will raise an exception for the invalid private key format assert_raises_rpc_error(-5, "Invalid private key encoding", self.nodes[0].importprivkey, "invalid") # This will raise an exception for importing an address with the PS2H flag temp_address = self.nodes[1].getnewaddress("", "p2sh-segwit") assert_raises_rpc_error(-5, "Cannot use the p2sh flag with an address - use a script instead", self.nodes[0].importaddress, temp_address, "label", False, True) # This will raise an exception for attempting to dump the private key of an address you do not own assert_raises_rpc_error(-3, "Address does not refer to a key", self.nodes[0].dumpprivkey, temp_address) # This will raise an exception for attempting to get the private key of an invalid Bitcoin address assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].dumpprivkey, "invalid") # This will raise an exception for attempting to set a label for an invalid Bitcoin address assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].setlabel, "invalid address", "label") # This will raise an exception for importing an invalid address assert_raises_rpc_error(-5, "Invalid Bitcoin address or script", self.nodes[0].importaddress, "invalid") # This will raise an exception for attempting to import a pubkey that isn't in hex assert_raises_rpc_error(-5, "Pubkey must be a hex string", self.nodes[0].importpubkey, "not hex") # This will raise an exception for importing an invalid pubkey assert_raises_rpc_error(-5, "Pubkey is not a valid public key", self.nodes[0].importpubkey, "5361746f736869204e616b616d6f746f") # Import address and private key to check correct behavior of spendable unspents # 1. Send some coins to generate new UTXO address_to_import = self.nodes[2].getnewaddress() txid = self.nodes[0].sendtoaddress(address_to_import, 1) self.nodes[0].generate(1) self.sync_all(self.nodes[0:3]) # send with explicit btc/kb fee self.log.info("test explicit fee (sendtoaddress as btc/kb)") self.nodes[0].generate(1) self.sync_all(self.nodes[0:3]) prebalance = self.nodes[2].getbalance() assert prebalance > 2 address = self.nodes[1].getnewaddress() # Throw if no conf_target provided assert_raises_rpc_error(-8, "Selected estimate_mode requires a fee rate", self.nodes[2].sendtoaddress, address=address, amount=1.0, estimate_mode='BTc/Kb') # Throw if negative feerate assert_raises_rpc_error(-3, "Amount out of range", self.nodes[2].sendtoaddress, address=address, amount=1.0, conf_target=-1, estimate_mode='btc/kb') txid = self.nodes[2].sendtoaddress( address=address, amount=1.0, conf_target=0.00002500, estimate_mode='btc/kb', ) tx_size = self.get_vsize(self.nodes[2].gettransaction(txid)['hex']) self.sync_all(self.nodes[0:3]) self.nodes[0].generate(1) self.sync_all(self.nodes[0:3]) postbalance = self.nodes[2].getbalance() fee = prebalance - postbalance - Decimal('1') assert_fee_amount(fee, tx_size, Decimal('0.00002500')) # send with explicit sat/b fee self.sync_all(self.nodes[0:3]) self.log.info("test explicit fee (sendtoaddress as sat/b)") self.nodes[0].generate(1) prebalance = self.nodes[2].getbalance() assert prebalance > 2 address = self.nodes[1].getnewaddress() # Throw if no conf_target provided assert_raises_rpc_error(-8, "Selected estimate_mode requires a fee rate", self.nodes[2].sendtoaddress, address=address, amount=1.0, estimate_mode='SAT/b') # Throw if negative feerate assert_raises_rpc_error(-3, "Amount out of range", self.nodes[2].sendtoaddress, address=address, amount=1.0, conf_target=-1, estimate_mode='SAT/b') txid = self.nodes[2].sendtoaddress( address=address, amount=1.0, conf_target=2, estimate_mode='SAT/B', ) tx_size = self.get_vsize(self.nodes[2].gettransaction(txid)['hex']) self.sync_all(self.nodes[0:3]) self.nodes[0].generate(1) self.sync_all(self.nodes[0:3]) postbalance = self.nodes[2].getbalance() fee = prebalance - postbalance - Decimal('1') assert_fee_amount(fee, tx_size, Decimal('0.00002000')) # 2. Import address from node2 to node1 self.nodes[1].importaddress(address_to_import) # 3. Validate that the imported address is watch-only on node1 assert self.nodes[1].getaddressinfo(address_to_import)["iswatchonly"] # 4. Check that the unspents after import are not spendable assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": False}) # 5. Import private key of the previously imported address on node1 priv_key = self.nodes[2].dumpprivkey(address_to_import) self.nodes[1].importprivkey(priv_key) # 6. Check that the unspents are now spendable on node1 assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": True}) # Mine a block from node0 to an address from node1 coinbase_addr = self.nodes[1].getnewaddress() block_hash = self.nodes[0].generatetoaddress(1, coinbase_addr)[0] coinbase_txid = self.nodes[0].getblock(block_hash)['tx'][0] self.sync_all(self.nodes[0:3]) # Check that the txid and balance is found by node1 self.nodes[1].gettransaction(coinbase_txid) # check if wallet or blockchain maintenance changes the balance self.sync_all(self.nodes[0:3]) blocks = self.nodes[0].generate(2) self.sync_all(self.nodes[0:3]) balance_nodes = [self.nodes[i].getbalance() for i in range(3)] block_count = self.nodes[0].getblockcount() # Check modes: # - True: unicode escaped as \u.... # - False: unicode directly as UTF-8 for mode in [True, False]: self.nodes[0].rpc.ensure_ascii = mode # unicode check: Basic Multilingual Plane, Supplementary Plane respectively for label in [u'ббаБаА', u'№ Ё']: addr = self.nodes[0].getnewaddress() self.nodes[0].setlabel(addr, label) test_address(self.nodes[0], addr, labels=[label]) assert label in self.nodes[0].listlabels() self.nodes[0].rpc.ensure_ascii = True # restore to default # maintenance tests maintenance = [ '-rescan', '-reindex', ] chainlimit = 6 for m in maintenance: self.log.info("check " + m) self.stop_nodes() # set lower ancestor limit for later self.start_node(0, [m, "-limitancestorcount=" + str(chainlimit)]) self.start_node(1, [m, "-limitancestorcount=" + str(chainlimit)]) self.start_node(2, [m, "-limitancestorcount=" + str(chainlimit)]) if m == '-reindex': # reindex will leave rpc warm up "early"; Wait for it to finish self.wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)]) assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) # Exercise listsinceblock with the last two blocks coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) assert_equal(coinbase_tx_1["lastblock"], blocks[1]) assert_equal(len(coinbase_tx_1["transactions"]), 1) assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0) # ==Check that wallet prefers to use coins that don't exceed mempool limits ===== # Get all non-zero utxos together chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()] singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True) self.nodes[0].generate(1) node0_balance = self.nodes[0].getbalance() # Split into two chains rawtx = self.nodes[0].createrawtransaction([{"txid": singletxid, "vout": 0}], {chain_addrs[0]: node0_balance / 2 - Decimal('0.01'), chain_addrs[1]: node0_balance / 2 - Decimal('0.01')}) signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx) singletxid = self.nodes[0].sendrawtransaction(hexstring=signedtx["hex"], maxfeerate=0) self.nodes[0].generate(1) # Make a long chain of unconfirmed payments without hitting mempool limit # Each tx we make leaves only one output of change on a chain 1 longer # Since the amount to send is always much less than the outputs, we only ever need one output # So we should be able to generate exactly chainlimit txs for each original output sending_addr = self.nodes[1].getnewaddress() txid_list = [] for _ in range(chainlimit * 2): txid_list.append(self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))) assert_equal(self.nodes[0].getmempoolinfo()['size'], chainlimit * 2) assert_equal(len(txid_list), chainlimit * 2) # Without walletrejectlongchains, we will still generate a txid # The tx will be stored in the wallet but not accepted to the mempool extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001')) assert extra_txid not in self.nodes[0].getrawmempool() assert extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()] self.nodes[0].abandontransaction(extra_txid) total_txs = len(self.nodes[0].listtransactions("*", 99999)) # Try with walletrejectlongchains # Double chain limit but require combining inputs, so we pass SelectCoinsMinConf self.stop_node(0) extra_args = ["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)] self.start_node(0, extra_args=extra_args) # wait until the wallet has submitted all transactions to the mempool self.wait_until(lambda: len(self.nodes[0].getrawmempool()) == chainlimit * 2) # Prevent potential race condition when calling wallet RPCs right after restart self.nodes[0].syncwithvalidationinterfacequeue() node0_balance = self.nodes[0].getbalance() # With walletrejectlongchains we will not create the tx and store it in our wallet. assert_raises_rpc_error(-6, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01')) # Verify nothing new in wallet assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999))) # Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py assert_raises_rpc_error(-5, "Invalid address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac") assert not address_info["ismine"] assert not address_info["iswatchonly"] assert not address_info["isscript"] assert not address_info["ischange"] # Test getaddressinfo 'ischange' field on change address. self.nodes[0].generate(1) destination = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(destination, 0.123) tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex']) output_addresses = [vout['scriptPubKey']['addresses'][0] for vout in tx["vout"]] assert len(output_addresses) > 1 for address in output_addresses: ischange = self.nodes[0].getaddressinfo(address)['ischange'] assert_equal(ischange, address != destination) if ischange: change = address self.nodes[0].setlabel(change, 'foobar') assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False) # Test gettransaction response with different arguments. self.log.info("Testing gettransaction response with different arguments...") self.nodes[0].setlabel(change, 'baz') baz = self.nodes[0].listtransactions(label="baz", count=1)[0] expected_receive_vout = {"label": "baz", "address": baz["address"], "amount": baz["amount"], "category": baz["category"], "vout": baz["vout"]} expected_fields = frozenset({'amount', 'bip125-replaceable', 'confirmations', 'details', 'fee', 'hex', 'time', 'timereceived', 'trusted', 'txid', 'walletconflicts'}) verbose_field = "decoded" expected_verbose_fields = expected_fields | {verbose_field} self.log.debug("Testing gettransaction response without verbose") tx = self.nodes[0].gettransaction(txid=txid) assert_equal(set([*tx]), expected_fields) assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout) self.log.debug("Testing gettransaction response with verbose set to False") tx = self.nodes[0].gettransaction(txid=txid, verbose=False) assert_equal(set([*tx]), expected_fields) assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout) self.log.debug("Testing gettransaction response with verbose set to True") tx = self.nodes[0].gettransaction(txid=txid, verbose=True) assert_equal(set([*tx]), expected_verbose_fields) assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout) assert_equal(tx[verbose_field], self.nodes[0].decoderawtransaction(tx["hex"]))
def run_test(self): # Check that there's no UTXO on none of the nodes assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("Mining blocks...") self.nodes[0].generate(1) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 250) assert_equal(walletinfo['balance'], 0) self.sync_all([self.nodes[0:3]]) self.nodes[1].generate(101) self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 250) assert_equal(self.nodes[1].getbalance(), 250) assert_equal(self.nodes[2].getbalance(), 0) # Check that only first and second nodes have UTXOs utxos = self.nodes[0].listunspent() assert_equal(len(utxos), 1) assert_equal(len(self.nodes[1].listunspent()), 1) assert_equal(len(self.nodes[2].listunspent()), 0) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 0) # Exercise locking of unspent outputs unspent_0 = self.nodes[1].listunspent()[0] unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} self.nodes[1].lockunspent(False, [unspent_0]) assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[1].sendtoaddress, self.nodes[1].getnewaddress(), 20) assert_equal([unspent_0], self.nodes[1].listlockunspent()) self.nodes[1].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[1].listlockunspent()), 0) # Send 21 PIV from 1 to 0 using sendtoaddress call. self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 21) self.nodes[1].generate(1) self.sync_all([self.nodes[0:3]]) # Node0 should have two unspent outputs. # Create a couple of transactions to send them to node2, submit them through # node1, and make sure both node0 and node2 pick them up properly: node0utxos = self.nodes[0].listunspent(1) assert_equal(len(node0utxos), 2) # create both transactions fee_per_kbyte = Decimal('0.001') txns_to_send = [] for utxo in node0utxos: inputs = [] outputs = {} inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]}) outputs[self.nodes[2].getnewaddress()] = float(utxo["amount"]) - float(fee_per_kbyte) 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) # Have node1 mine a block to confirm transactions: self.nodes[1].generate(1) self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 0) node_2_expected_bal = Decimal('250') + Decimal('21') - 2 * fee_per_kbyte node_2_bal = self.nodes[2].getbalance() assert_equal(node_2_bal, node_2_expected_bal) # Send 10 PIV normal address = self.nodes[0].getnewaddress("test") self.nodes[2].settxfee(float(fee_per_kbyte)) txid = self.nodes[2].sendtoaddress(address, 10, "", "") fee = self.nodes[2].gettransaction(txid)["fee"] node_2_bal -= (Decimal('10') - fee) assert_equal(self.nodes[2].getbalance(), node_2_bal) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_0_bal = self.nodes[0].getbalance() assert_equal(node_0_bal, Decimal('10')) # Sendmany 10 PIV txid = self.nodes[2].sendmany('', {address: 10}, 0, "") fee = self.nodes[2].gettransaction(txid)["fee"] self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_0_bal += Decimal('10') node_2_bal -= (Decimal('10') - fee) assert_equal(self.nodes[2].getbalance(), node_2_bal) assert_equal(self.nodes[0].getbalance(), node_0_bal) assert_fee_amount(-fee, self.get_vsize(self.nodes[2].getrawtransaction(txid)), fee_per_kbyte) # This will raise an exception since generate does not accept a string assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2") # Import address and private key to check correct behavior of spendable unspents # 1. Send some coins to generate new UTXO address_to_import = self.nodes[2].getnewaddress() self.nodes[0].sendtoaddress(address_to_import, 1) self.nodes[0].generate(1) self.sync_all([self.nodes[0:3]]) # 2. Import address from node2 to node1 self.nodes[1].importaddress(address_to_import) # 3. Validate that the imported address is watch-only on node1 assert(self.nodes[1].validateaddress(address_to_import)["iswatchonly"]) # 4. Check that the unspents after import are not spendable listunspent = self.nodes[1].listunspent(1, 9999999, [], 2) assert_array_result(listunspent, {"address": address_to_import}, {"spendable": False}) # 5. Import private key of the previously imported address on node1 priv_key = self.nodes[2].dumpprivkey(address_to_import) self.nodes[1].importprivkey(priv_key) # 6. Check that the unspents are now spendable on node1 assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": True}) # check if wallet or blochchain maintenance changes the balance self.sync_all([self.nodes[0:3]]) blocks = self.nodes[0].generate(2) self.sync_all([self.nodes[0:3]]) balance_nodes = [self.nodes[i].getbalance() for i in range(3)] block_count = self.nodes[0].getblockcount() maintenance = [ '-rescan', '-reindex', ] for m in maintenance: self.log.info("check " + m) self.stop_nodes() # set lower ancestor limit for later self.start_node(0, [m]) self.start_node(1, [m]) self.start_node(2, [m]) if m == '-reindex': # reindex will leave rpc warm up "early"; Wait for it to finish wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)]) assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) # Exercise listsinceblock with the last two blocks coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) assert_equal(coinbase_tx_1["lastblock"], blocks[1]) assert_equal(len(coinbase_tx_1["transactions"]), 1) assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0)
def run_test(self): # Check that there's no UTXO on none of the nodes assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("Mining blocks...") self.nodes[0].generate(1) walletinfo = self.nodes[0].getwalletinfo() self.check_wallet_processed_blocks(0, walletinfo) assert_equal(walletinfo['immature_balance'], 250) assert_equal(walletinfo['balance'], 0) self.sync_all(self.nodes[0:3]) self.nodes[1].generate(101) self.sync_all(self.nodes[0:3]) assert_equal(self.nodes[0].getbalance(), 250) assert_equal(self.nodes[1].getbalance(), 250) assert_equal(self.nodes[2].getbalance(), 0) walletinfo = self.nodes[0].getwalletinfo() self.check_wallet_processed_blocks(0, walletinfo) self.check_wallet_processed_blocks(1, self.nodes[1].getwalletinfo()) self.check_wallet_processed_blocks(2, self.nodes[2].getwalletinfo()) # Check that only first and second nodes have UTXOs utxos = self.nodes[0].listunspent() assert_equal(len(utxos), 1) assert_equal(len(self.nodes[1].listunspent()), 1) assert_equal(len(self.nodes[2].listunspent()), 0) assert_equal(walletinfo['immature_balance'], 0) # Exercise locking of unspent outputs unspent_0 = self.nodes[1].listunspent()[0] assert unspent_0["solvable"] assert unspent_0["spendable"] assert unspent_0["safe"] unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} self.nodes[1].lockunspent(False, [unspent_0]) assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[1].sendtoaddress, self.nodes[1].getnewaddress(), 20) assert_equal([unspent_0], self.nodes[1].listlockunspent()) self.nodes[1].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[1].listlockunspent()), 0) # Send 21 PIV from 1 to 0 using sendtoaddress call. # Locked memory should use at least 32 bytes to sign the transaction self.log.info("test getmemoryinfo") memory_before = self.nodes[0].getmemoryinfo() self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 21) memory_after = self.nodes[0].getmemoryinfo() assert (memory_before['locked']['used'] + 32 <= memory_after['locked']['used']) self.sync_mempools(self.nodes[0:3]) # Node0 should have two unspent outputs. # One safe, the other one not yet node0utxos = self.nodes[0].listunspent(0) assert_equal(len(node0utxos), 2) newutxos = [x for x in node0utxos if x["txid"] != utxos[0]["txid"]] assert_equal(len(newutxos), 1) assert not newutxos[0]["safe"] # Mine the other tx self.nodes[1].generate(1) self.sync_all(self.nodes[0:3]) node0utxos = self.nodes[0].listunspent() assert_equal(len(node0utxos), 2) for u in node0utxos: assert u["safe"] # 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: # create both transactions fee_per_kbyte = Decimal('0.001') txns_to_send = [] for utxo in node0utxos: inputs = [] outputs = {} inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) outputs[self.nodes[2].getnewaddress()] = float( utxo["amount"]) - float(fee_per_kbyte) 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) # Have node1 mine a block to confirm transactions: self.nodes[1].generate(1) self.sync_all(self.nodes[0:3]) assert_equal(self.nodes[0].getbalance(), 0) node_2_expected_bal = Decimal('250') + Decimal( '21') - 2 * fee_per_kbyte node_2_bal = self.nodes[2].getbalance() assert_equal(node_2_bal, node_2_expected_bal) # Send 10 PIV normal self.log.info("test sendtoaddress") address = self.nodes[0].getnewaddress("test") self.nodes[2].settxfee(float(fee_per_kbyte)) txid = self.nodes[2].sendtoaddress(address, 10, "", "") fee = self.nodes[2].gettransaction(txid)["fee"] # fee < 0 node_2_bal -= (Decimal('10') - fee) assert_equal(self.nodes[2].getbalance(), node_2_bal) self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) node_0_bal = self.nodes[0].getbalance() assert_equal(node_0_bal, Decimal('10')) # Sendmany 10 PIV self.log.info("test sendmany") txid = self.nodes[2].sendmany('', {address: 10}, 0, "") fee = self.nodes[2].gettransaction(txid)["fee"] self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) node_0_bal += Decimal('10') node_2_bal -= (Decimal('10') - fee) assert_equal(self.nodes[2].getbalance(), node_2_bal) assert_equal(self.nodes[0].getbalance(), node_0_bal) assert_fee_amount( -fee, self.get_vsize(self.nodes[2].getrawtransaction(txid)), fee_per_kbyte) # Import address and private key to check correct behavior of spendable unspents # 1. Send some coins to generate new UTXO address_to_import = self.nodes[2].getnewaddress() self.nodes[0].sendtoaddress(address_to_import, 1) self.nodes[0].generate(1) self.sync_all(self.nodes[0:3]) # 2. Import address from node2 to node1 self.log.info("test importaddress") self.nodes[1].importaddress(address_to_import) # 3. Validate that the imported address is watch-only on node1 assert ( self.nodes[1].validateaddress(address_to_import)["iswatchonly"]) # 4. Check that the unspents after import are not spendable listunspent = self.nodes[1].listunspent(1, 9999999, [], 2) assert_array_result(listunspent, {"address": address_to_import}, {"spendable": False}) # 5. Import private key of the previously imported address on node1 priv_key = self.nodes[2].dumpprivkey(address_to_import) self.log.info("test importprivkey") self.nodes[1].importprivkey(priv_key) # 6. Check that the unspents are now spendable on node1 assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": True}) # check if wallet or blochchain maintenance changes the balance self.sync_all(self.nodes[0:3]) blocks = self.nodes[0].generate(2) self.sync_all(self.nodes[0:3]) balance_nodes = [self.nodes[i].getbalance() for i in range(3)] block_count = self.nodes[0].getblockcount() maintenance = [ '-rescan', '-reindex', ] for m in maintenance: self.log.info("check " + m) self.stop_nodes() # set lower ancestor limit for later self.start_node(0, [m]) self.start_node(1, [m]) self.start_node(2, [m]) if m == '-reindex': # reindex will leave rpc warm up "early"; Wait for it to finish wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)]) assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) # Exercise listsinceblock with the last two blocks self.check_wallet_processed_blocks(0, self.nodes[0].getwalletinfo()) coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) assert_equal(coinbase_tx_1["lastblock"], blocks[1]) assert_equal(len(coinbase_tx_1["transactions"]), 1) assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) assert_equal( len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0) # Excercise query_options parameter in listunspent # Node 1 has: # - 1 coin of 1.00 PIV # - 7 coins of 250.00 PIV # - 1 coin of 228.9999xxxx PIV assert_equal(9, self.len_listunspent({})) assert_equal(9, self.len_listunspent({"maximumCount": 10})) assert_equal(2, self.len_listunspent({"maximumCount": 2})) assert_equal(1, self.len_listunspent({"maximumCount": 1})) assert_equal(9, self.len_listunspent({"maximumCount": 0})) assert_equal(9, self.len_listunspent({"minimumAmount": 0.99999999})) assert_equal(9, self.len_listunspent({"minimumAmount": 1.00})) assert_equal(8, self.len_listunspent({"minimumAmount": 1.00000001})) assert_equal(8, self.len_listunspent({"minimumAmount": 228.9999})) assert_equal(7, self.len_listunspent({"minimumAmount": 229.00})) assert_equal(7, self.len_listunspent({"minimumAmount": 250.00})) assert_equal(0, self.len_listunspent({"minimumAmount": 250.00000001})) assert_equal(0, self.len_listunspent({"maximumAmount": 0.99999999})) assert_equal(1, self.len_listunspent({"maximumAmount": 1.00})) assert_equal(1, self.len_listunspent({"maximumAmount": 228.9999})) assert_equal(2, self.len_listunspent({"maximumAmount": 229.00})) assert_equal(2, self.len_listunspent({"maximumAmount": 249.99999999})) assert_equal(9, self.len_listunspent({"maximumAmount": 250.00})) assert_equal( 9, self.len_listunspent({ "minimumAmount": 1.00000000, "maximumAmount": 250.00 })) assert_equal( 2, self.len_listunspent({ "minimumAmount": 1.00000000, "maximumAmount": 249.99999999 })) assert_equal( 8, self.len_listunspent({ "minimumAmount": 1.00000001, "maximumAmount": 250.00 })) assert_equal( 7, self.len_listunspent({ "minimumAmount": 229.000000, "maximumAmount": 250.00 })) assert_equal( 7, self.len_listunspent({ "minimumAmount": 250.000000, "maximumAmount": 250.00 })) assert_equal( 8, self.len_listunspent({ "minimumAmount": 228.999900, "maximumAmount": 250.00 })) assert_equal( 0, self.len_listunspent({ "minimumAmount": 228.999900, "maximumAmount": 228.00 })) assert_equal( 1, self.len_listunspent({ "minimumAmount": 250.00, "minimumSumAmount": 249.99999999 })) assert_equal( 2, self.len_listunspent({ "minimumAmount": 250.00, "minimumSumAmount": 250.00000001 })) assert_equal( 5, self.len_listunspent({ "minimumAmount": 250.00, "minimumSumAmount": 1250.0000000 })) assert_equal(9, self.len_listunspent({"minimumSumAmount": 2500.00}))
def test_output_format(self): self.node_1_address = self.nodes[1].getnewaddress() simple_txid = self.nodes[0].sendtoaddress(self.node_1_address, 0.1) internal_transfer_txid = self.nodes[0].sendtoaddress( self.nodes[0].getnewaddress(), 0.3) send_to = { self.nodes[0].getnewaddress(): 0.11, self.nodes[1].getnewaddress(): 0.22, self.nodes[0].getnewaddress(): 0.33, self.node_1_address: 0.44 } several_outs_txid = self.nodes[0].sendmany("", send_to) watchonly_address = self.nodes[0].getnewaddress() watchonly_pubkey = self.nodes[0].validateaddress( watchonly_address)["pubkey"] self.nodes[2].importpubkey(watchonly_pubkey, "", True) watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address, Decimal("0.5")) self.sync_all() # simple send node_0_transactions = self.nodes[0].filtertransactions() assert_array_result(node_0_transactions, {"txid": simple_txid}, { "category": "send", "amount": Decimal("-0.1"), "confirmations": 0 }) result_tx = next(t for t in node_0_transactions if t["txid"] == simple_txid) assert_equal(len(result_tx["outputs"]), 1) assert_equal(result_tx["outputs"][0]["address"], self.node_1_address) assert_equal(result_tx["outputs"][0]["amount"], Decimal("-0.1")) node_1_transactions = self.nodes[1].filtertransactions() assert_array_result(node_1_transactions, {"txid": simple_txid}, { "category": "receive", "amount": Decimal("0.1"), "confirmations": 0 }) result_tx = next(t for t in node_1_transactions if t["txid"] == simple_txid) assert_equal(len(result_tx["outputs"]), 1) assert_equal(result_tx["outputs"][0]["address"], self.node_1_address) assert_equal(result_tx["outputs"][0]["amount"], Decimal("0.1")) # several outputs result_tx = next(t for t in self.nodes[0].filtertransactions() if t["txid"] == several_outs_txid) assert_equal(len(result_tx["outputs"]), 4) # internal transfer result_tx = next(t for t in self.nodes[0].filtertransactions() if t["txid"] == internal_transfer_txid) assert_equal(result_tx["category"], "internal_transfer") assert_equal(result_tx["amount"], Decimal("0")) assert_equal(result_tx["outputs"][0]["amount"], Decimal("0.3")) # watchonly node_2_transactions = self.nodes[2].filtertransactions( {"include_watchonly": True}) assert_array_result(node_2_transactions, {"txid": watchonly_txid}, { "category": "receive", "amount": Decimal("0.5") }) result_tx = next(t for t in node_2_transactions if t["txid"] == watchonly_txid) assert_equal(result_tx["outputs"][0]["involvesWatchonly"], 1) result_tx = next((t for t in self.nodes[2].filtertransactions( {"include_watchonly": False}) if t["txid"] == watchonly_txid), None) assert result_tx is None # coinbase sync_mempools(self.nodes) self.nodes[0].generatetoaddress( 1, self.nodes[0].getnewaddress()) # Clear node1's mempool sync_blocks(self.nodes) address = self.nodes[1].getnewaddress() self.nodes[1].generatetoaddress(1, address) tx = self.nodes[1].filtertransactions({"search": address})[0] assert_equal(tx['amount'], PROPOSER_REWARD)
def run_test(self): assert_raises_rpc_error(-3, 'Not an array', self.nodes[0].sendtypeto, 'unite', 'unite', 'out') outputs = [{'address': 'foo', 'amount': 1}] assert_raises_rpc_error(-5, 'Invalid Unit-e address', self.nodes[0].sendtypeto, 'unite', 'unite', outputs) outputs = [{'address': '2NBYu3St3rtzJb8AzvraXnXCUxEuCs23eZo', 'amount': self.nodes[0].getbalance() + 1}] assert_raises_rpc_error(-6, 'Insufficient funds', self.nodes[0].sendtypeto, 'unite', 'unite', outputs) # Multiple outputs node_1_address = self.nodes[1].getnewaddress() outputs = [ {'address': node_1_address, 'amount': 0.5}, {'address': '2NBYu3St3rtzJb8AzvraXnXCUxEuCs23eZo', 'amount': 0.25}] tx1_id = self.nodes[0].sendtypeto('unite', 'unite', outputs, 'comment', 'comment-to') tx = self.nodes[0].getrawtransaction(tx1_id, True) assert_equal(len(tx['vout']), 3) vout1 = next(o for o in tx['vout'] if node_1_address in o['scriptPubKey']['addresses']) assert_equal(vout1['value'], Decimal(0.5)) # Subtract fee from amount outputs = [{'address': node_1_address, 'amount': 0.5, 'subfee': True}] tx2_id = self.nodes[0].sendtypeto('unite', 'unite', outputs, 'comment', 'comment-to') estimate_fee = True fees = self.nodes[0].sendtypeto('unite', 'unite', outputs, 'comment', 'comment-to', estimate_fee) tx = self.nodes[0].getrawtransaction(tx2_id, True) vout2 = next(o for o in tx['vout'] if node_1_address in o['scriptPubKey']['addresses']) assert_equal(vout2['value'], Decimal(0.5) - fees['fee']) self.sync_all() self.nodes[1].generate(6) # coincontrol: inputs outputs = [{'address': '2NBYu3St3rtzJb8AzvraXnXCUxEuCs23eZo', 'amount': 0.6}] coin_control = {'inputs': [{'tx': tx1_id, 'n': vout1['n']}, {'tx': tx2_id, 'n': vout2['n']}]} estimate_fee = False tx3_id = self.nodes[1].sendtypeto( 'unite', 'unite', outputs, 'comment', 'comment-to', estimate_fee, coin_control) tx = self.nodes[1].getrawtransaction(tx3_id, True) assert_equal(len(tx['vin']), 2) assert_array_result(tx['vin'], {'txid': tx1_id}, {'vout': vout1['n']}) assert_array_result(tx['vin'], {'txid': tx2_id}, {'vout': vout2['n']}) # coincontrol: changeaddress change_address = self.nodes[1].getrawchangeaddress() coin_control = {'changeaddress': change_address} estimate_fee = False tx4_id = self.nodes[1].sendtypeto( 'unite', 'unite', outputs, 'comment', 'comment-to', estimate_fee, coin_control) tx = self.nodes[1].getrawtransaction(tx4_id, True) assert_equal(len(tx['vout']), 2) next(o for o in tx['vout'] if change_address in o['scriptPubKey']['addresses']) # Estimate fee estimate_fee = True outputs = [{'address': '2NBYu3St3rtzJb8AzvraXnXCUxEuCs23eZo', 'amount': 0.1}] fee_per_byte = Decimal('0.001') / 1000 self.nodes[0].settxfee(fee_per_byte * 1000) fees = self.nodes[0].sendtypeto('unite', 'unite', outputs, 'comment', 'comment-to', estimate_fee) assert_greater_than(Decimal('1e-7'), abs(fee_per_byte - fees['fee'] / fees['bytes'])) fee_per_byte *= 2 coin_control = {'fee_rate': fee_per_byte * 1000} fees = self.nodes[0].sendtypeto('unite', 'unite', outputs, 'comment', 'comment-to', estimate_fee, coin_control) assert_greater_than(Decimal('1e-7'), abs(fee_per_byte - fees['fee'] / fees['bytes']))
def run_test(self): # Leave IBD self.nodes[0].generate(1) # Simple send, 0 to 1: txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 10) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, {"category": "send", "amount": Decimal("-10"), "confirmations": 0}) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, {"category": "receive", "amount": Decimal('10'), "confirmations": 0}) # mine a block, confirmations should change: blockhash = self.nodes[0].generate(1)[0] blockheight = self.nodes[0].getblockheader(blockhash)['height'] self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, {"category": "send", "amount": Decimal("-10"), "confirmations": 1, "blockhash": blockhash, "blockheight": blockheight}) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, {"category": "receive", "amount": Decimal('10'), "confirmations": 1, "blockhash": blockhash, "blockheight": blockheight}) # send-to-self: txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 20) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid, "category": "send"}, {"amount": Decimal("-20")}) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid, "category": "receive"}, {"amount": Decimal('20')}) # sendmany from node1: twice to self, twice to node2: send_to = {self.nodes[0].getnewaddress(): 11, self.nodes[1].getnewaddress(): 22, self.nodes[0].getnewaddress(): 33, self.nodes[1].getnewaddress(): 44} txid = self.nodes[1].sendmany("", send_to) self.sync_all() assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-11")}, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), {"category": "receive", "amount": Decimal('11')}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-22")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "receive", "amount": Decimal('22')}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-33")}, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), {"category": "receive", "amount": Decimal('33')}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-44")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "receive", "amount": Decimal('44')}, {"txid": txid}) pubkey = self.nodes[1].getaddressinfo( self.nodes[1].getnewaddress())['pubkey'] multisig = self.nodes[1].createmultisig(1, [pubkey]) self.nodes[0].importaddress( multisig["redeemScript"], "watchonly", False, True) txid = self.nodes[1].sendtoaddress(multisig["address"], 10) self.nodes[1].generate(1) self.sync_all() assert_equal(len(self.nodes[0].listtransactions( label="watchonly", include_watchonly=True)), 1) assert_equal(len(self.nodes[0].listtransactions( dummy="watchonly", include_watchonly=True)), 1) assert len( self.nodes[0].listtransactions( label="watchonly", count=100, include_watchonly=False)) == 0 assert_array_result(self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=True), {"category": "receive", "amount": Decimal('10')}, {"txid": txid, "label": "watchonly"})
def run_test(self): """ listreceivedbyaddress Test """ # Send from node 0 to 1 addr = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() #Check not listed in listreceivedbyaddress because has 0 confirmations assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": addr}, {}, True) #Bury Tx under 10 block so it will be returned by listreceivedbyaddress self.nodes[1].generate(10) self.sync_all() assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": addr}, { "address": addr, "account": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [ txid, ] }) #With min confidence < 10 assert_array_result(self.nodes[1].listreceivedbyaddress(5), {"address": addr}, { "address": addr, "account": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [ txid, ] }) #With min confidence > 10, should not find Tx assert_array_result(self.nodes[1].listreceivedbyaddress(11), {"address": addr}, {}, True) #Empty Tx addr = self.nodes[1].getnewaddress() assert_array_result(self.nodes[1].listreceivedbyaddress(0, True), {"address": addr}, { "address": addr, "account": "", "amount": 0, "confirmations": 0, "txids": [] }) ''' getreceivedbyaddress Test ''' # Send from node 0 to 1 addr = self.nodes[1].getnewaddress() self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # Check balance is 0 because of 0 confirmations balance = self.nodes[1].getreceivedbyaddress(addr) if balance != Decimal("0.0"): raise AssertionError( "Wrong balance returned by getreceivedbyaddress, %0.2f" % balance) # Check balance is 0.1 balance = self.nodes[1].getreceivedbyaddress(addr, 0) if balance != Decimal("0.1"): raise AssertionError( "Wrong balance returned by getreceivedbyaddress, %0.2f" % balance) # Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress self.nodes[1].generate(10) self.sync_all() balance = self.nodes[1].getreceivedbyaddress(addr) if balance != Decimal("0.1"): raise AssertionError( "Wrong balance returned by getreceivedbyaddress, %0.2f" % balance) ''' listreceivedbyaccount + getreceivedbyaccount Test ''' # set pre-state addrArr = self.nodes[1].getnewaddress() account = self.nodes[1].getaccount(addrArr) received_by_account_json = get_sub_array_from_array( self.nodes[1].listreceivedbyaccount(), {"account": account}) if len(received_by_account_json) == 0: raise AssertionError("No accounts found in node") balance_by_account = self.nodes[1].getreceivedbyaccount(account) self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # listreceivedbyaccount should return received_by_account_json because of 0 confirmations assert_array_result(self.nodes[1].listreceivedbyaccount(), {"account": account}, received_by_account_json) # getreceivedbyaddress should return same balance because of 0 confirmations balance = self.nodes[1].getreceivedbyaccount(account) if balance != balance_by_account: raise AssertionError( "Wrong balance returned by getreceivedbyaccount, %0.2f" % balance) self.nodes[1].generate(10) self.sync_all() # listreceivedbyaccount should return updated account balance assert_array_result( self.nodes[1].listreceivedbyaccount(), {"account": account}, { "account": received_by_account_json["account"], "amount": (received_by_account_json["amount"] + Decimal("0.1")) }) # getreceivedbyaddress should return updates balance balance = self.nodes[1].getreceivedbyaccount(account) if balance != balance_by_account + Decimal("0.1"): raise AssertionError( "Wrong balance returned by getreceivedbyaccount, %0.2f" % balance) # Create a new account named "mynewaccount" that has a 0 balance self.nodes[1].getaccountaddress("mynewaccount") received_by_account_json = get_sub_array_from_array( self.nodes[1].listreceivedbyaccount(0, True), {"account": "mynewaccount"}) if len(received_by_account_json) == 0: raise AssertionError("No accounts found in node") # Test include empty of listreceivedbyaccount if received_by_account_json["amount"] != Decimal("0.0"): raise AssertionError( "Wrong balance returned by listreceivedbyaccount, %0.2f" % (received_by_account_json["amount"])) # Test getreceivedbyaccount for 0 amount accounts balance = self.nodes[1].getreceivedbyaccount("mynewaccount") if balance != Decimal("0.0"): raise AssertionError( "Wrong balance returned by getreceivedbyaccount, %0.2f" % balance)
def run_test(self): # Check that there's no UTXO on none of the nodes assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("Mining blocks...") self.nodes[0].generate(1) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 250) assert_equal(walletinfo['balance'], 0) self.sync_all([self.nodes[0:3]]) self.nodes[1].generate(101) self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 250) assert_equal(self.nodes[1].getbalance(), 250) assert_equal(self.nodes[2].getbalance(), 0) # Check that only first and second nodes have UTXOs utxos = self.nodes[0].listunspent() assert_equal(len(utxos), 1) assert_equal(len(self.nodes[1].listunspent()), 1) assert_equal(len(self.nodes[2].listunspent()), 0) # Send 21 PIV 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(), 21) #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.nodes[0].generate(1) self.sync_all([self.nodes[0:3]]) # Exercise locking of unspent outputs unspent_0 = self.nodes[2].listunspent()[0] unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} self.nodes[2].lockunspent(False, [unspent_0]) assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) assert_equal([unspent_0], self.nodes[2].listlockunspent()) self.nodes[2].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[2].listlockunspent()), 0) # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) self.sync_all([self.nodes[0:3]]) # node0 should end up with 100 PIV in block rewards plus fees, but # minus the 21 plus fees sent to node2 assert_equal(self.nodes[0].getbalance(), 500 - 21) assert_equal(self.nodes[2].getbalance(), 21) # Node0 should have two unspent outputs. # Create a couple of transactions to send them to node2, submit them through # node1, and make sure both node0 and node2 pick them up properly: node0utxos = self.nodes[0].listunspent(1) assert_equal(len(node0utxos), 2) # create both transactions txns_to_send = [] for utxo in node0utxos: inputs = [] outputs = {} inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) outputs[self.nodes[2].getnewaddress("from1")] = float( 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) # Have node1 mine a block to confirm transactions: self.nodes[1].generate(1) self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 500) assert_equal(self.nodes[2].getbalance("from1"), 500 - 21) # Send 10 PIV normal address = self.nodes[0].getnewaddress("test") fee_per_byte = Decimal('0.001') / 1000 self.nodes[2].settxfee(float(fee_per_byte * 1000)) txid = self.nodes[2].sendtoaddress(address, 10, "", "") fee = self.nodes[2].gettransaction(txid)["fee"] self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal = self.nodes[2].getbalance() assert_equal(self.nodes[0].getbalance(), Decimal('10')) # Send 10 PIV with subtract fee from amount txid = self.nodes[2].sendtoaddress(address, 10, "", "") self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance() - fee, node_2_bal) node_0_bal = self.nodes[0].getbalance() assert_equal(node_0_bal, Decimal('20')) # Sendmany 10 PIV txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "") self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_0_bal += Decimal('10') node_2_bal -= Decimal('10') #node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid))) assert_equal(self.nodes[0].getbalance(), node_0_bal) # Sendmany 10 PIV with subtract fee from amount txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "") self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal + (fee * 3)) #node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid))) # Test ResendWalletTransactions: # Create a couple of transactions, then start up a fourth # node (nodes[3]) and ask nodes[0] to rebroadcast. # EXPECT: nodes[3] should have those transactions in its mempool. txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) sync_mempools(self.nodes[0:2]) self.start_node(3) connect_nodes(self.nodes[0], 3) sync_blocks(self.nodes) # Exercise balance rpcs assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], 1) assert_equal(self.nodes[0].getunconfirmedbalance(), 1) #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(): 49.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'] assert_raises_rpc_error(-25, "", self.nodes[1].sendrawtransaction, signedRawTx['hex']) # This will raise an exception since generate does not accept a string assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2") # Import address and private key to check correct behavior of spendable unspents # 1. Send some coins to generate new UTXO address_to_import = self.nodes[2].getnewaddress() txid = self.nodes[0].sendtoaddress(address_to_import, 1) self.nodes[0].generate(1) self.sync_all([self.nodes[0:3]]) # 2. Import address from node2 to node1 self.nodes[1].importaddress(address_to_import) # 3. Validate that the imported address is watch-only on node1 assert ( self.nodes[1].validateaddress(address_to_import)["iswatchonly"]) # 4. Check that the unspents after import are not spendable listunspent = self.nodes[1].listunspent(1, 9999999, [], 3) assert_array_result(listunspent, {"address": address_to_import}, {"spendable": False}) # 5. Import private key of the previously imported address on node1 priv_key = self.nodes[2].dumpprivkey(address_to_import) self.nodes[1].importprivkey(priv_key) # 6. Check that the unspents are now spendable on node1 assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": True}) #check if wallet or blochchain maintenance changes the balance self.sync_all([self.nodes[0:3]]) blocks = self.nodes[0].generate(2) self.sync_all([self.nodes[0:3]]) balance_nodes = [self.nodes[i].getbalance() for i in range(3)] block_count = self.nodes[0].getblockcount() maintenance = [ '-rescan', '-reindex', '-zapwallettxes=1', '-zapwallettxes=2', #'-salvagewallet', ] chainlimit = 6 for m in maintenance: self.log.info("check " + m) self.stop_nodes() # set lower ancestor limit for later self.start_node(0, [m, "-limitancestorcount=" + str(chainlimit)]) self.start_node(1, [m, "-limitancestorcount=" + str(chainlimit)]) self.start_node(2, [m, "-limitancestorcount=" + str(chainlimit)]) if m == '-reindex': # reindex will leave rpc warm up "early"; Wait for it to finish wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)]) assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) # Exercise listsinceblock with the last two blocks coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) assert_equal(coinbase_tx_1["lastblock"], blocks[1]) assert_equal(len(coinbase_tx_1["transactions"]), 1) assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) assert_equal( len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0)
def run_test(self): # Leave IBD self.nodes[0].generate(1) # Simple send, 0 to 1: txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "account": "", "amount": Decimal("-0.1"), "confirmations": 0 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "account": "", "amount": Decimal("0.1"), "confirmations": 0 }) # mine a block, confirmations should change: self.nodes[0].generate(1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "account": "", "amount": Decimal("-0.1"), "confirmations": 1 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "account": "", "amount": Decimal("0.1"), "confirmations": 1 }) # send-to-self: txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.2) assert_array_result(self.nodes[0].listtransactions(), { "txid": txid, "category": "send" }, {"amount": Decimal("-0.2")}) assert_array_result(self.nodes[0].listtransactions(), { "txid": txid, "category": "receive" }, {"amount": Decimal("0.2")}) # sendmany from node1: twice to self, twice to node2: send_to = { self.nodes[0].getnewaddress(): 0.11, self.nodes[1].getnewaddress(): 0.22, self.nodes[0].getaccountaddress("from1"): 0.33, self.nodes[1].getaccountaddress("toself"): 0.44 } txid = self.nodes[1].sendmany("", send_to) self.sync_all() assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.11") }, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), { "category": "receive", "amount": Decimal("0.11") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.22") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "receive", "amount": Decimal("0.22") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.33") }, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), { "category": "receive", "amount": Decimal("0.33") }, { "txid": txid, "account": "from1" }) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.44") }, { "txid": txid, "account": "" }) assert_array_result(self.nodes[1].listtransactions(), { "category": "receive", "amount": Decimal("0.44") }, { "txid": txid, "account": "toself" }) multisig = self.nodes[1].createmultisig( 1, [self.nodes[1].getnewaddress()]) self.nodes[0].importaddress(multisig["redeemScript"], "watchonly", False, True) txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1) self.nodes[1].generate(1) self.sync_all() assert (len(self.nodes[0].listtransactions("watchonly", 100, 0, False)) == 0) assert_array_result( self.nodes[0].listtransactions("watchonly", 100, 0, True), { "category": "receive", "amount": Decimal("0.1") }, { "txid": txid, "account": "watchonly" })
def run_test(self): # Generate block to get out of IBD self.nodes[0].generate(1) self.log.info("listreceivedbyaddress Test") # Send from node 0 to 1 addr = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # Check not listed in listreceivedbyaddress because has 0 confirmations assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": addr}, {}, True) # Bury Tx under 10 block so it will be returned by listreceivedbyaddress self.nodes[1].generate(10) self.sync_all() assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": addr}, {"address": addr, "account": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]}) # With min confidence < 10 assert_array_result(self.nodes[1].listreceivedbyaddress(5), {"address": addr}, {"address": addr, "account": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]}) # With min confidence > 10, should not find Tx assert_array_result(self.nodes[1].listreceivedbyaddress(11), {"address": addr}, {}, True) # Empty Tx addr = self.nodes[1].getnewaddress() assert_array_result(self.nodes[1].listreceivedbyaddress(0, True), {"address": addr}, {"address": addr, "account": "", "amount": 0, "confirmations": 0, "txids": []}) self.log.info("getreceivedbyaddress Test") # Send from node 0 to 1 addr = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # Check balance is 0 because of 0 confirmations balance = self.nodes[1].getreceivedbyaddress(addr) assert_equal(balance, Decimal("0.0")) # Check balance is 0.1 balance = self.nodes[1].getreceivedbyaddress(addr, 0) assert_equal(balance, Decimal("0.1")) # Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress self.nodes[1].generate(10) self.sync_all() balance = self.nodes[1].getreceivedbyaddress(addr) assert_equal(balance, Decimal("0.1")) # Trying to getreceivedby for an address the wallet doesn't own should return an error assert_raises_rpc_error(-4, "Address not found in wallet", self.nodes[0].getreceivedbyaddress, addr) self.log.info("listreceivedbyaccount + getreceivedbyaccount Test") # set pre-state addrArr = self.nodes[1].getnewaddress() account = self.nodes[1].getaccount(addrArr) received_by_account_json = [r for r in self.nodes[1].listreceivedbyaccount() if r["account"] == account][0] balance_by_account = self.nodes[1].getreceivedbyaccount(account) txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # listreceivedbyaccount should return received_by_account_json because of 0 confirmations assert_array_result(self.nodes[1].listreceivedbyaccount(), {"account": account}, received_by_account_json) # getreceivedbyaddress should return same balance because of 0 confirmations balance = self.nodes[1].getreceivedbyaccount(account) assert_equal(balance, balance_by_account) self.nodes[1].generate(10) self.sync_all() # listreceivedbyaccount should return updated account balance assert_array_result(self.nodes[1].listreceivedbyaccount(), {"account": account}, {"account": received_by_account_json["account"], "amount": (received_by_account_json["amount"] + Decimal("0.1"))}) # getreceivedbyaddress should return updates balance balance = self.nodes[1].getreceivedbyaccount(account) assert_equal(balance, balance_by_account + Decimal("0.1")) # Create a new account named "mynewaccount" that has a 0 balance self.nodes[1].getaccountaddress("mynewaccount") received_by_account_json = [r for r in self.nodes[1].listreceivedbyaccount(0, True) if r["account"] == "mynewaccount"][0] # Test includeempty of listreceivedbyaccount assert_equal(received_by_account_json["amount"], Decimal("0.0")) # Test getreceivedbyaccount for 0 amount accounts balance = self.nodes[1].getreceivedbyaccount("mynewaccount") assert_equal(balance, Decimal("0.0"))
def run_with_paginatebypointer_test(self): def get_with_paginatebypointer(node, count=20, label="*", watchonly=False): i = 1 records = [] pointer = None while i < count: options = { "paginatebypointer": True, "nextpagepointer": pointer, } #if pointer is None: # del options["nextpagepointer"] result = node.listtransactions(label, i, 0, watchonly, options) pointer = result.get("nextpagepointer", None) records += result["records"] if len(records) >= count or pointer is None: break i += 1 return records # Simple send, 0 to 1: txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() assert_array_result(get_with_paginatebypointer(self.nodes[0]), {"txid": txid}, {"category": "send", "amount": Decimal("-0.1"), "confirmations": 0}) assert_array_result(get_with_paginatebypointer(self.nodes[1]), {"txid": txid}, {"category": "receive", "amount": Decimal("0.1"), "confirmations": 0}) # sendmany from node1: twice to self, twice to node2: send_to = {self.nodes[0].getnewaddress(): 0.111, self.nodes[1].getnewaddress(): 0.222, self.nodes[0].getnewaddress(): 0.333, self.nodes[1].getnewaddress(): 0.444} txid = self.nodes[1].sendmany("", send_to) self.sync_all() assert_array_result(get_with_paginatebypointer(self.nodes[1]), {"category": "send", "amount": Decimal("-0.111")}, {"txid": txid}) assert_array_result(get_with_paginatebypointer(self.nodes[0]), {"category": "receive", "amount": Decimal("0.111")}, {"txid": txid}) assert_array_result(get_with_paginatebypointer(self.nodes[1]), {"category": "send", "amount": Decimal("-0.222")}, {"txid": txid}) assert_array_result(get_with_paginatebypointer(self.nodes[1]), {"category": "receive", "amount": Decimal("0.222")}, {"txid": txid}) assert_array_result(get_with_paginatebypointer(self.nodes[1]), {"category": "send", "amount": Decimal("-0.333")}, {"txid": txid}) assert_array_result(get_with_paginatebypointer(self.nodes[0]), {"category": "receive", "amount": Decimal("0.333")}, {"txid": txid}) assert_array_result(get_with_paginatebypointer(self.nodes[1]), {"category": "send", "amount": Decimal("-0.444")}, {"txid": txid}) assert_array_result(get_with_paginatebypointer(self.nodes[1]), {"category": "receive", "amount": Decimal("0.444")}, {"txid": txid})
def run_test(self): # Check that there's no UTXO on none of the nodes assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("Mining blocks...") self.generate(self.nodes[0], 1, sync_fun=self.no_op) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 50) assert_equal(walletinfo['balance'], 0) self.sync_all(self.nodes[0:3]) self.generate(self.nodes[1], COINBASE_MATURITY + 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) assert_equal(self.nodes[0].getbalance(), 50) assert_equal(self.nodes[1].getbalance(), 50) assert_equal(self.nodes[2].getbalance(), 0) # Check that only first and second nodes have UTXOs utxos = self.nodes[0].listunspent() assert_equal(len(utxos), 1) assert_equal(len(self.nodes[1].listunspent()), 1) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("Test gettxout") confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"] # First, outputs that are unspent both in the chain and in the # mempool should appear with or without include_mempool txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=False) assert_equal(txout['value'], 50) txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=True) assert_equal(txout['value'], 50) # Send 21 BTC from 0 to 2 using sendtoaddress call. self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) self.log.info("Test gettxout (second part)") # utxo spent in mempool should be visible if you exclude mempool # but invisible if you include mempool txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False) assert_equal(txout['value'], 50) txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index) # by default include_mempool=True assert txout is None txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True) assert txout is None # new utxo from mempool should be invisible if you exclude mempool # but visible if you include mempool txout = self.nodes[0].gettxout(mempool_txid, 0, False) assert txout is None txout1 = self.nodes[0].gettxout(mempool_txid, 0, True) txout2 = self.nodes[0].gettxout(mempool_txid, 1, True) # note the mempool tx will have randomly assigned indices # but 10 will go to node2 and the rest will go to node0 balance = self.nodes[0].getbalance() assert_equal(set([txout1['value'], txout2['value']]), set([10, balance])) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 0) # Have node0 mine a block, thus it will collect its own fee. self.generate(self.nodes[0], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) # Exercise locking of unspent outputs unspent_0 = self.nodes[2].listunspent()[0] unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} # Trying to unlock an output which isn't locked should error assert_raises_rpc_error(-8, "Invalid parameter, expected locked output", self.nodes[2].lockunspent, True, [unspent_0]) # Locking an already-locked output should error self.nodes[2].lockunspent(False, [unspent_0]) assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0]) # Restarting the node should clear the lock self.restart_node(2) self.nodes[2].lockunspent(False, [unspent_0]) # Unloading and reloating the wallet should clear the lock assert_equal(self.nodes[0].listwallets(), [self.default_wallet_name]) self.nodes[2].unloadwallet(self.default_wallet_name) self.nodes[2].loadwallet(self.default_wallet_name) assert_equal(len(self.nodes[2].listlockunspent()), 0) # Locking non-persistently, then re-locking persistently, is allowed self.nodes[2].lockunspent(False, [unspent_0]) self.nodes[2].lockunspent(False, [unspent_0], True) # Restarting the node with the lock written to the wallet should keep the lock self.restart_node(2) assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0]) # Unloading and reloading the wallet with a persistent lock should keep the lock self.nodes[2].unloadwallet(self.default_wallet_name) self.nodes[2].loadwallet(self.default_wallet_name) assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0]) # Locked outputs should not be used, even if they are the only available funds assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) assert_equal([unspent_0], self.nodes[2].listlockunspent()) # Unlocking should remove the persistent lock self.nodes[2].lockunspent(True, [unspent_0]) self.restart_node(2) assert_equal(len(self.nodes[2].listlockunspent()), 0) # Reconnect node 2 after restarts self.connect_nodes(1, 2) self.connect_nodes(0, 2) assert_raises_rpc_error(-8, "txid must be of length 64 (not 34, for '0000000000000000000000000000000000')", self.nodes[2].lockunspent, False, [{"txid": "0000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[2].lockunspent, False, [{"txid": "ZZZ0000000000000000000000000000000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "Invalid parameter, unknown transaction", self.nodes[2].lockunspent, False, [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "Invalid parameter, vout index out of bounds", self.nodes[2].lockunspent, False, [{"txid": unspent_0["txid"], "vout": 999}]) # The lock on a manually selected output is ignored unspent_0 = self.nodes[1].listunspent()[0] self.nodes[1].lockunspent(False, [unspent_0]) tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 }) self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True}) # fundrawtransaction can lock an input self.nodes[1].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[1].listlockunspent()), 0) tx = self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True})['hex'] assert_equal(len(self.nodes[1].listlockunspent()), 1) # Send transaction tx = self.nodes[1].signrawtransactionwithwallet(tx)["hex"] self.nodes[1].sendrawtransaction(tx) assert_equal(len(self.nodes[1].listlockunspent()), 0) # Have node1 generate 100 blocks (so node0 can recover the fee) self.generate(self.nodes[1], COINBASE_MATURITY, sync_fun=lambda: self.sync_all(self.nodes[0:3])) # node0 should end up with 100 btc in block rewards plus fees, but # minus the 21 plus fees sent to node2 assert_equal(self.nodes[0].getbalance(), 100 - 21) assert_equal(self.nodes[2].getbalance(), 21) # Node0 should have two unspent outputs. # Create a couple of transactions to send them to node2, submit them through # node1, and make sure both node0 and node2 pick them up properly: node0utxos = self.nodes[0].listunspent(1) assert_equal(len(node0utxos), 2) # create both transactions txns_to_send = [] for utxo in node0utxos: inputs = [] outputs = {} inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) outputs[self.nodes[2].getnewaddress()] = utxo["amount"] - 3 raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) txns_to_send.append(self.nodes[0].signrawtransactionwithwallet(raw_tx)) # Have node 1 (miner) send the transactions self.nodes[1].sendrawtransaction(hexstring=txns_to_send[0]["hex"], maxfeerate=0) self.nodes[1].sendrawtransaction(hexstring=txns_to_send[1]["hex"], maxfeerate=0) # Have node1 mine a block to confirm transactions: self.generate(self.nodes[1], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 94) # Verify that a spent output cannot be locked anymore spent_0 = {"txid": node0utxos[0]["txid"], "vout": node0utxos[0]["vout"]} assert_raises_rpc_error(-8, "Invalid parameter, expected unspent output", self.nodes[0].lockunspent, False, [spent_0]) # Send 10 BTC normal address = self.nodes[0].getnewaddress("test") fee_per_byte = Decimal('0.001') / 1000 self.nodes[2].settxfee(fee_per_byte * 1000) txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(self.nodes[0].getbalance(), Decimal('10')) # Send 10 BTC with subtract fee from amount txid = self.nodes[2].sendtoaddress(address, 10, "", "", True) self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) self.log.info("Test sendmany") # Sendmany 10 BTC txid = self.nodes[2].sendmany('', {address: 10}, 0, "", []) self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) node_0_bal += Decimal('10') node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(self.nodes[0].getbalance(), node_0_bal) # Sendmany 10 BTC with subtract fee from amount txid = self.nodes[2].sendmany('', {address: 10}, 0, "", [address]) self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) self.log.info("Test sendmany with fee_rate param (explicit fee rate in sat/vB)") fee_rate_sat_vb = 2 fee_rate_btc_kvb = fee_rate_sat_vb * 1e3 / 1e8 explicit_fee_rate_btc_kvb = Decimal(fee_rate_btc_kvb) / 1000 # Test passing fee_rate as a string txid = self.nodes[2].sendmany(amounts={address: 10}, fee_rate=str(fee_rate_sat_vb)) self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) balance = self.nodes[2].getbalance() node_2_bal = self.check_fee_amount(balance, node_2_bal - Decimal('10'), explicit_fee_rate_btc_kvb, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(balance, node_2_bal) node_0_bal += Decimal('10') assert_equal(self.nodes[0].getbalance(), node_0_bal) # Test passing fee_rate as an integer amount = Decimal("0.0001") txid = self.nodes[2].sendmany(amounts={address: amount}, fee_rate=fee_rate_sat_vb) self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) balance = self.nodes[2].getbalance() node_2_bal = self.check_fee_amount(balance, node_2_bal - amount, explicit_fee_rate_btc_kvb, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(balance, node_2_bal) node_0_bal += amount assert_equal(self.nodes[0].getbalance(), node_0_bal) for key in ["totalFee", "feeRate"]: assert_raises_rpc_error(-8, "Unknown named parameter key", self.nodes[2].sendtoaddress, address=address, amount=1, fee_rate=1, key=1) # Test setting explicit fee rate just below the minimum. self.log.info("Test sendmany raises 'fee rate too low' if fee_rate of 0.99999999 is passed") assert_raises_rpc_error(-6, "Fee rate (0.999 sat/vB) is lower than the minimum fee rate setting (1.000 sat/vB)", self.nodes[2].sendmany, amounts={address: 10}, fee_rate=0.999) self.log.info("Test sendmany raises if an invalid fee_rate is passed") # Test fee_rate with zero values. msg = "Fee rate (0.000 sat/vB) is lower than the minimum fee rate setting (1.000 sat/vB)" for zero_value in [0, 0.000, 0.00000000, "0", "0.000", "0.00000000"]: assert_raises_rpc_error(-6, msg, self.nodes[2].sendmany, amounts={address: 1}, fee_rate=zero_value) msg = "Invalid amount" # Test fee_rate values that don't pass fixed-point parsing checks. for invalid_value in ["", 0.000000001, 1e-09, 1.111111111, 1111111111111111, "31.999999999999999999999"]: assert_raises_rpc_error(-3, msg, self.nodes[2].sendmany, amounts={address: 1.0}, fee_rate=invalid_value) # Test fee_rate values that cannot be represented in sat/vB. for invalid_value in [0.0001, 0.00000001, 0.00099999, 31.99999999, "0.0001", "0.00000001", "0.00099999", "31.99999999"]: assert_raises_rpc_error(-3, msg, self.nodes[2].sendmany, amounts={address: 10}, fee_rate=invalid_value) # Test fee_rate out of range (negative number). assert_raises_rpc_error(-3, OUT_OF_RANGE, self.nodes[2].sendmany, amounts={address: 10}, fee_rate=-1) # Test type error. for invalid_value in [True, {"foo": "bar"}]: assert_raises_rpc_error(-3, NOT_A_NUMBER_OR_STRING, self.nodes[2].sendmany, amounts={address: 10}, fee_rate=invalid_value) self.log.info("Test sendmany raises if an invalid conf_target or estimate_mode is passed") for target, mode in product([-1, 0, 1009], ["economical", "conservative"]): assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008", # max value of 1008 per src/policy/fees.h self.nodes[2].sendmany, amounts={address: 1}, conf_target=target, estimate_mode=mode) for target, mode in product([-1, 0], ["btc/kb", "sat/b"]): assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"', self.nodes[2].sendmany, amounts={address: 1}, conf_target=target, estimate_mode=mode) self.start_node(3, self.nodes[3].extra_args) self.connect_nodes(0, 3) self.sync_all() # check if we can list zero value tx as available coins # 1. create raw_tx # 2. hex-changed one output to 0.0 # 3. sign and send # 4. check if recipient (node0) can list the zero value tx usp = self.nodes[1].listunspent(query_options={'minimumAmount': '49.998'})[0] inputs = [{"txid": usp['txid'], "vout": usp['vout']}] outputs = {self.nodes[1].getnewaddress(): 49.998, self.nodes[0].getnewaddress(): 11.11} raw_tx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") # replace 11.11 with 0.0 (int32) signed_raw_tx = self.nodes[1].signrawtransactionwithwallet(raw_tx) decoded_raw_tx = self.nodes[1].decoderawtransaction(signed_raw_tx['hex']) zero_value_txid = decoded_raw_tx['txid'] self.nodes[1].sendrawtransaction(signed_raw_tx['hex']) self.sync_all() self.generate(self.nodes[1], 1) # mine a block unspent_txs = self.nodes[0].listunspent() # zero value tx must be in listunspents output found = False for uTx in unspent_txs: if uTx['txid'] == zero_value_txid: found = True assert_equal(uTx['amount'], Decimal('0')) assert found self.log.info("Test -walletbroadcast") self.stop_nodes() self.start_node(0, ["-walletbroadcast=0"]) self.start_node(1, ["-walletbroadcast=0"]) self.start_node(2, ["-walletbroadcast=0"]) self.connect_nodes(0, 1) self.connect_nodes(1, 2) self.connect_nodes(0, 2) self.sync_all(self.nodes[0:3]) txid_not_broadcast = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast) self.generate(self.nodes[1], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) # mine a block, tx should not be in there assert_equal(self.nodes[2].getbalance(), node_2_bal) # should not be changed because tx was not broadcasted # now broadcast from another node, mine a block, sync, and check the balance self.nodes[1].sendrawtransaction(tx_obj_not_broadcast['hex']) self.generate(self.nodes[1], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) node_2_bal += 2 tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast) assert_equal(self.nodes[2].getbalance(), node_2_bal) # create another tx self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) # restart the nodes with -walletbroadcast=1 self.stop_nodes() self.start_node(0) self.start_node(1) self.start_node(2) self.connect_nodes(0, 1) self.connect_nodes(1, 2) self.connect_nodes(0, 2) self.sync_blocks(self.nodes[0:3]) self.generate(self.nodes[0], 1, sync_fun=lambda: self.sync_blocks(self.nodes[0:3])) node_2_bal += 2 # tx should be added to balance because after restarting the nodes tx should be broadcast assert_equal(self.nodes[2].getbalance(), node_2_bal) # send a tx with value in a string (PR#6380 +) txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-2')) txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-0.0001')) # check if JSON parser can handle scientific notation in strings txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1e-4") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-0.0001')) # General checks for errors from incorrect inputs # This will raise an exception because the amount is negative assert_raises_rpc_error(-3, OUT_OF_RANGE, self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "-1") # This will raise an exception because the amount type is wrong assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4") # This will raise an exception since generate does not accept a string assert_raises_rpc_error(-1, "not an integer", self.generate, self.nodes[0], "2") if not self.options.descriptors: # This will raise an exception for the invalid private key format assert_raises_rpc_error(-5, "Invalid private key encoding", self.nodes[0].importprivkey, "invalid") # This will raise an exception for importing an address with the PS2H flag temp_address = self.nodes[1].getnewaddress("", "p2sh-segwit") assert_raises_rpc_error(-5, "Cannot use the p2sh flag with an address - use a script instead", self.nodes[0].importaddress, temp_address, "label", False, True) # This will raise an exception for attempting to dump the private key of an address you do not own assert_raises_rpc_error(-3, "Address does not refer to a key", self.nodes[0].dumpprivkey, temp_address) # This will raise an exception for attempting to get the private key of an invalid Bitcoin address assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].dumpprivkey, "invalid") # This will raise an exception for attempting to set a label for an invalid Bitcoin address assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].setlabel, "invalid address", "label") # This will raise an exception for importing an invalid address assert_raises_rpc_error(-5, "Invalid Bitcoin address or script", self.nodes[0].importaddress, "invalid") # This will raise an exception for attempting to import a pubkey that isn't in hex assert_raises_rpc_error(-5, "Pubkey must be a hex string", self.nodes[0].importpubkey, "not hex") # This will raise an exception for importing an invalid pubkey assert_raises_rpc_error(-5, "Pubkey is not a valid public key", self.nodes[0].importpubkey, "5361746f736869204e616b616d6f746f") # Bech32m addresses cannot be imported into a legacy wallet assert_raises_rpc_error(-5, "Bech32m addresses cannot be imported into legacy wallets", self.nodes[0].importaddress, "bcrt1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqc8gma6") # Import address and private key to check correct behavior of spendable unspents # 1. Send some coins to generate new UTXO address_to_import = self.nodes[2].getnewaddress() txid = self.nodes[0].sendtoaddress(address_to_import, 1) self.sync_mempools(self.nodes[0:3]) vout = find_vout_for_address(self.nodes[2], txid, address_to_import) self.nodes[2].lockunspent(False, [{"txid": txid, "vout": vout}]) self.generate(self.nodes[0], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) self.log.info("Test sendtoaddress with fee_rate param (explicit fee rate in sat/vB)") prebalance = self.nodes[2].getbalance() assert prebalance > 2 address = self.nodes[1].getnewaddress() amount = 3 fee_rate_sat_vb = 2 fee_rate_btc_kvb = fee_rate_sat_vb * 1e3 / 1e8 # Test passing fee_rate as an integer txid = self.nodes[2].sendtoaddress(address=address, amount=amount, fee_rate=fee_rate_sat_vb) tx_size = self.get_vsize(self.nodes[2].gettransaction(txid)['hex']) self.generate(self.nodes[0], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) postbalance = self.nodes[2].getbalance() fee = prebalance - postbalance - Decimal(amount) assert_fee_amount(fee, tx_size, Decimal(fee_rate_btc_kvb)) prebalance = self.nodes[2].getbalance() amount = Decimal("0.001") fee_rate_sat_vb = 1.23 fee_rate_btc_kvb = fee_rate_sat_vb * 1e3 / 1e8 # Test passing fee_rate as a string txid = self.nodes[2].sendtoaddress(address=address, amount=amount, fee_rate=str(fee_rate_sat_vb)) tx_size = self.get_vsize(self.nodes[2].gettransaction(txid)['hex']) self.generate(self.nodes[0], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) postbalance = self.nodes[2].getbalance() fee = prebalance - postbalance - amount assert_fee_amount(fee, tx_size, Decimal(fee_rate_btc_kvb)) for key in ["totalFee", "feeRate"]: assert_raises_rpc_error(-8, "Unknown named parameter key", self.nodes[2].sendtoaddress, address=address, amount=1, fee_rate=1, key=1) # Test setting explicit fee rate just below the minimum. self.log.info("Test sendtoaddress raises 'fee rate too low' if fee_rate of 0.99999999 is passed") assert_raises_rpc_error(-6, "Fee rate (0.999 sat/vB) is lower than the minimum fee rate setting (1.000 sat/vB)", self.nodes[2].sendtoaddress, address=address, amount=1, fee_rate=0.999) self.log.info("Test sendtoaddress raises if an invalid fee_rate is passed") # Test fee_rate with zero values. msg = "Fee rate (0.000 sat/vB) is lower than the minimum fee rate setting (1.000 sat/vB)" for zero_value in [0, 0.000, 0.00000000, "0", "0.000", "0.00000000"]: assert_raises_rpc_error(-6, msg, self.nodes[2].sendtoaddress, address=address, amount=1, fee_rate=zero_value) msg = "Invalid amount" # Test fee_rate values that don't pass fixed-point parsing checks. for invalid_value in ["", 0.000000001, 1e-09, 1.111111111, 1111111111111111, "31.999999999999999999999"]: assert_raises_rpc_error(-3, msg, self.nodes[2].sendtoaddress, address=address, amount=1.0, fee_rate=invalid_value) # Test fee_rate values that cannot be represented in sat/vB. for invalid_value in [0.0001, 0.00000001, 0.00099999, 31.99999999, "0.0001", "0.00000001", "0.00099999", "31.99999999"]: assert_raises_rpc_error(-3, msg, self.nodes[2].sendtoaddress, address=address, amount=10, fee_rate=invalid_value) # Test fee_rate out of range (negative number). assert_raises_rpc_error(-3, OUT_OF_RANGE, self.nodes[2].sendtoaddress, address=address, amount=1.0, fee_rate=-1) # Test type error. for invalid_value in [True, {"foo": "bar"}]: assert_raises_rpc_error(-3, NOT_A_NUMBER_OR_STRING, self.nodes[2].sendtoaddress, address=address, amount=1.0, fee_rate=invalid_value) self.log.info("Test sendtoaddress raises if an invalid conf_target or estimate_mode is passed") for target, mode in product([-1, 0, 1009], ["economical", "conservative"]): assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008", # max value of 1008 per src/policy/fees.h self.nodes[2].sendtoaddress, address=address, amount=1, conf_target=target, estimate_mode=mode) for target, mode in product([-1, 0], ["btc/kb", "sat/b"]): assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"', self.nodes[2].sendtoaddress, address=address, amount=1, conf_target=target, estimate_mode=mode) # 2. Import address from node2 to node1 self.nodes[1].importaddress(address_to_import) # 3. Validate that the imported address is watch-only on node1 assert self.nodes[1].getaddressinfo(address_to_import)["iswatchonly"] # 4. Check that the unspents after import are not spendable assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": False}) # 5. Import private key of the previously imported address on node1 priv_key = self.nodes[2].dumpprivkey(address_to_import) self.nodes[1].importprivkey(priv_key) # 6. Check that the unspents are now spendable on node1 assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": True}) # Mine a block from node0 to an address from node1 coinbase_addr = self.nodes[1].getnewaddress() block_hash = self.generatetoaddress(self.nodes[0], 1, coinbase_addr, sync_fun=lambda: self.sync_all(self.nodes[0:3]))[0] coinbase_txid = self.nodes[0].getblock(block_hash)['tx'][0] # Check that the txid and balance is found by node1 self.nodes[1].gettransaction(coinbase_txid) # check if wallet or blockchain maintenance changes the balance self.sync_all(self.nodes[0:3]) blocks = self.generate(self.nodes[0], 2, sync_fun=lambda: self.sync_all(self.nodes[0:3])) balance_nodes = [self.nodes[i].getbalance() for i in range(3)] block_count = self.nodes[0].getblockcount() # Check modes: # - True: unicode escaped as \u.... # - False: unicode directly as UTF-8 for mode in [True, False]: self.nodes[0].rpc.ensure_ascii = mode # unicode check: Basic Multilingual Plane, Supplementary Plane respectively for label in [u'ббаБаА', u'№ Ё']: addr = self.nodes[0].getnewaddress() self.nodes[0].setlabel(addr, label) test_address(self.nodes[0], addr, labels=[label]) assert label in self.nodes[0].listlabels() self.nodes[0].rpc.ensure_ascii = True # restore to default # -reindex tests chainlimit = 6 self.log.info("Test -reindex") self.stop_nodes() # set lower ancestor limit for later self.start_node(0, ['-reindex', "-limitancestorcount=" + str(chainlimit)]) self.start_node(1, ['-reindex', "-limitancestorcount=" + str(chainlimit)]) self.start_node(2, ['-reindex', "-limitancestorcount=" + str(chainlimit)]) # reindex will leave rpc warm up "early"; Wait for it to finish self.wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)]) assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) # Exercise listsinceblock with the last two blocks coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) assert_equal(coinbase_tx_1["lastblock"], blocks[1]) assert_equal(len(coinbase_tx_1["transactions"]), 1) assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0) # ==Check that wallet prefers to use coins that don't exceed mempool limits ===== # Get all non-zero utxos together chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()] singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True) self.generate(self.nodes[0], 1, sync_fun=self.no_op) node0_balance = self.nodes[0].getbalance() # Split into two chains rawtx = self.nodes[0].createrawtransaction([{"txid": singletxid, "vout": 0}], {chain_addrs[0]: node0_balance / 2 - Decimal('0.01'), chain_addrs[1]: node0_balance / 2 - Decimal('0.01')}) signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx) singletxid = self.nodes[0].sendrawtransaction(hexstring=signedtx["hex"], maxfeerate=0) self.generate(self.nodes[0], 1, sync_fun=self.no_op) # Make a long chain of unconfirmed payments without hitting mempool limit # Each tx we make leaves only one output of change on a chain 1 longer # Since the amount to send is always much less than the outputs, we only ever need one output # So we should be able to generate exactly chainlimit txs for each original output sending_addr = self.nodes[1].getnewaddress() txid_list = [] for _ in range(chainlimit * 2): txid_list.append(self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))) assert_equal(self.nodes[0].getmempoolinfo()['size'], chainlimit * 2) assert_equal(len(txid_list), chainlimit * 2) # Without walletrejectlongchains, we will still generate a txid # The tx will be stored in the wallet but not accepted to the mempool extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001')) assert extra_txid not in self.nodes[0].getrawmempool() assert extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()] self.nodes[0].abandontransaction(extra_txid) total_txs = len(self.nodes[0].listtransactions("*", 99999)) # Try with walletrejectlongchains # Double chain limit but require combining inputs, so we pass AttemptSelection self.stop_node(0) extra_args = ["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)] self.start_node(0, extra_args=extra_args) # wait until the wallet has submitted all transactions to the mempool self.wait_until(lambda: len(self.nodes[0].getrawmempool()) == chainlimit * 2) # Prevent potential race condition when calling wallet RPCs right after restart self.nodes[0].syncwithvalidationinterfacequeue() node0_balance = self.nodes[0].getbalance() # With walletrejectlongchains we will not create the tx and store it in our wallet. assert_raises_rpc_error(-6, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01')) # Verify nothing new in wallet assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999))) # Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac") assert not address_info["ismine"] assert not address_info["iswatchonly"] assert not address_info["isscript"] assert not address_info["ischange"] assert_equal(address_info['use_txids'], []) # Test getaddressinfo 'txids' field txid = self.nodes[0].sendtoaddress("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ", 1) address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") assert_equal(address_info['use_txids'], [txid]) # Test getaddressinfo 'ischange' field on change address. self.generate(self.nodes[0], 1, sync_fun=self.no_op) destination = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(destination, 0.123) tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded'] output_addresses = [vout['scriptPubKey']['address'] for vout in tx["vout"]] assert len(output_addresses) > 1 for address in output_addresses: ischange = self.nodes[0].getaddressinfo(address)['ischange'] assert_equal(ischange, address != destination) if ischange: change = address self.nodes[0].setlabel(change, 'foobar') assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False) # Test gettransaction response with different arguments. self.log.info("Testing gettransaction response with different arguments...") self.nodes[0].setlabel(change, 'baz') baz = self.nodes[0].listtransactions(label="baz", count=1)[0] expected_receive_vout = {"label": "baz", "address": baz["address"], "amount": baz["amount"], "category": baz["category"], "vout": baz["vout"]} expected_fields = frozenset({ 'amount', 'bip125-replaceable', 'confirmations', 'details', 'fee', 'hex', 'in_mempool', 'lastprocessedblock', 'time', 'timereceived', 'trusted', 'txid', 'walletconflicts', 'wtxid', }) verbose_field = "decoded" expected_verbose_fields = expected_fields | {verbose_field} self.log.debug("Testing gettransaction response without verbose") tx = self.nodes[0].gettransaction(txid=txid) assert_equal(set([*tx]), expected_fields) assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout) self.log.debug("Testing gettransaction response with verbose set to False") tx = self.nodes[0].gettransaction(txid=txid, verbose=False) assert_equal(set([*tx]), expected_fields) assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout) self.log.debug("Testing gettransaction response with verbose set to True") tx = self.nodes[0].gettransaction(txid=txid, verbose=True) assert_equal(set([*tx]), expected_verbose_fields) assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout) assert_equal(tx[verbose_field], self.nodes[0].decoderawtransaction(tx["hex"])) self.log.info("Test send* RPCs with verbose=True") address = self.nodes[0].getnewaddress("test") txid_feeReason_one = self.nodes[2].sendtoaddress(address=address, amount=5, verbose=True) assert_equal(txid_feeReason_one["fee_reason"], "Fallback fee") txid_feeReason_two = self.nodes[2].sendmany(dummy='', amounts={address: 5}, verbose=True) assert_equal(txid_feeReason_two["fee_reason"], "Fallback fee") self.log.info("Test send* RPCs with verbose=False") txid_feeReason_three = self.nodes[2].sendtoaddress(address=address, amount=5, verbose=False) assert_equal(self.nodes[2].gettransaction(txid_feeReason_three)['txid'], txid_feeReason_three) txid_feeReason_four = self.nodes[2].sendmany(dummy='', amounts={address: 5}, verbose=False) assert_equal(self.nodes[2].gettransaction(txid_feeReason_four)['txid'], txid_feeReason_four)
def run_test(self): # Simple send, 0 to 1: txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, {"category": "send", "amount": Decimal("-0.1"), "confirmations": 0}) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, {"category": "receive", "amount": Decimal("0.1"), "confirmations": 0}) # mine a block, confirmations should change: self.nodes[0].generate(1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, {"category": "send", "amount": Decimal("-0.1"), "confirmations": 1}) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, {"category": "receive", "amount": Decimal("0.1"), "confirmations": 1}) # send-to-self: txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.2) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid, "category": "send"}, {"amount": Decimal("-0.2")}) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid, "category": "receive"}, {"amount": Decimal("0.2")}) # sendmany from node1: twice to self, twice to node2: send_to = {self.nodes[0].getnewaddress(): 0.11, self.nodes[1].getnewaddress(): 0.22, self.nodes[0].getnewaddress(): 0.33, self.nodes[1].getnewaddress(): 0.44} txid = self.nodes[1].sendmany("", send_to) self.sync_all() assert_array_result(self.nodes[1].listtransactions(), {"category":"send", "amount": Decimal("-0.11")}, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), {"category": "receive", "amount": Decimal("0.11")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-0.22")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "receive", "amount": Decimal("0.22")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-0.33")}, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), {"category": "receive", "amount": Decimal("0.33")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-0.44")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "receive", "amount": Decimal("0.44")}, {"txid": txid}) multisig = self.nodes[1].createmultisig(1, [self.nodes[1].getnewaddress()]) self.nodes[0].importaddress(multisig["redeemScript"], "watchonly", False, True) txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1) self.nodes[1].generate(1) self.sync_all() assert not [tx for tx in self.nodes[0].listtransactions("*", 100, 0, False) if "label" in tx and tx["label"] == "watchonly"] txs = [tx for tx in self.nodes[0].listtransactions("*", 100, 0, True) if "label" in tx and tx['label'] == 'watchonly'] assert_array_result(txs, {"category": "receive", "amount": Decimal("0.1")}, {"txid": txid})
def run_test(self): # Leave IBD self.generate(self.nodes[0], 1) # Simple send, 0 to 1: txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "amount": Decimal("-0.1"), "confirmations": 0 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "amount": Decimal("0.1"), "confirmations": 0 }) # mine a block, confirmations should change: self.generate(self.nodes[0], 1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "amount": Decimal("-0.1"), "confirmations": 1 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "amount": Decimal("0.1"), "confirmations": 1 }) # send-to-self: txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.2) assert_array_result(self.nodes[0].listtransactions(), { "txid": txid, "category": "send" }, {"amount": Decimal("-0.2")}) assert_array_result(self.nodes[0].listtransactions(), { "txid": txid, "category": "receive" }, {"amount": Decimal("0.2")}) # sendmany from node1: twice to self, twice to node2: send_to = { self.nodes[0].getnewaddress(): 0.11, self.nodes[1].getnewaddress(): 0.22, self.nodes[0].getnewaddress(): 0.33, self.nodes[1].getnewaddress(): 0.44 } txid = self.nodes[1].sendmany("", send_to) self.sync_all() assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.11") }, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), { "category": "receive", "amount": Decimal("0.11") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.22") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "receive", "amount": Decimal("0.22") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.33") }, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), { "category": "receive", "amount": Decimal("0.33") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.44") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "receive", "amount": Decimal("0.44") }, {"txid": txid}) pubkey_A = self.nodes[1].getaddressinfo( self.nodes[1].getnewaddress())['pubkey'] multisig_A = self.nodes[1].createmultisig(1, [pubkey_A]) self.nodes[0].importaddress(multisig_A["redeemScript"], "label_A_watchonly", False, True) pubkey_B = self.nodes[1].getaddressinfo( self.nodes[1].getnewaddress())['pubkey'] multisig_B = self.nodes[1].createmultisig(1, [pubkey_B]) self.nodes[0].importaddress(multisig_B["redeemScript"], "label_B_watchonly", False, True) plain_addr_C = self.nodes[1].getnewaddress() pubkey_C = self.nodes[1].getaddressinfo(plain_addr_C)['pubkey'] self.nodes[0].importpubkey(pubkey_C, "label_C", False) num_wildcard_label_results_before_txs = len( self.nodes[0].listtransactions(label="*", count=100, include_watchonly=True)) txid_A = self.nodes[1].sendtoaddress(multisig_A["address"], 0.01) txid_B = self.nodes[1].sendtoaddress(multisig_B["address"], 0.01) txid_C = self.nodes[1].sendtoaddress(plain_addr_C, 0.01) self.generate(self.nodes[1], 1) self.sync_all() # check label_A_watchonly results assert len( self.nodes[0].listtransactions(label="label_A_watchonly", count=100, include_watchonly=False)) == 0 assert len(self.nodes[0].listtransactions(label="label_A_watchonly", count=100, include_watchonly=True)) == 1 # check label_B_watchonly results assert len( self.nodes[0].listtransactions(label="label_B_watchonly", count=100, include_watchonly=False)) == 0 assert len(self.nodes[0].listtransactions(label="label_B_watchonly", count=100, include_watchonly=True)) == 1 # check label_C results assert len(self.nodes[0].listtransactions( label="label_C", count=100, include_watchonly=False)) == 0 assert len(self.nodes[0].listtransactions(label="label_C", count=100, include_watchonly=True)) == 1 # check no results returned for unknown label assert len(self.nodes[0].listtransactions(label="no_such_label", count=100, include_watchonly=True)) == 0 # wildcard labels : 3 new txs added (A, B & C) assert len(self.nodes[0].listtransactions( label='*', count=100, include_watchonly=True) ) - num_wildcard_label_results_before_txs == 3 # check wildcard returns all labeled txs assert_array_result(self.nodes[0].listtransactions( label="*", count=100, include_watchonly=True), { "category": "receive", "label": "label_A_watchonly", "amount": Decimal("0.01") }, { "txid": txid_A, "label": "label_A_watchonly" }, should_not_find=False) assert_array_result(self.nodes[0].listtransactions( label="*", count=100, include_watchonly=True), { "category": "receive", "label": "label_B_watchonly", "amount": Decimal("0.01") }, { "txid": txid_B, "label": "label_B_watchonly" }, should_not_find=False) assert_array_result(self.nodes[0].listtransactions( label="*", count=100, include_watchonly=True), { "category": "receive", "label": "label_C", "amount": Decimal("0.01") }, { "txid": txid_C, "label": "label_C" }, should_not_find=False) # check label A returns only label A, not B or C assert_array_result( self.nodes[0].listtransactions(label="label_A_watchonly", count=100, include_watchonly=True), { "category": "receive", "label": "label_A_watchonly", "amount": Decimal("0.01") }, { "txid": txid_A, "label": "label_A_watchonly" }) assert_array_result(self.nodes[0].listtransactions( label="label_A_watchonly", count=100, include_watchonly=True), { "category": "receive", "label": "label_B_watchonly", "amount": Decimal("0.01") }, {}, should_not_find=True) assert_array_result(self.nodes[0].listtransactions( label="label_A_watchonly", count=100, include_watchonly=True), { "category": "receive", "label": "label_C", "amount": Decimal("0.01") }, {}, should_not_find=True) # check label B returns only label B, not A or C assert_array_result( self.nodes[0].listtransactions(label="label_B_watchonly", count=100, include_watchonly=True), { "category": "receive", "label": "label_B_watchonly", "amount": Decimal("0.01") }, { "txid": txid_B, "label": "label_B_watchonly" }) assert_array_result(self.nodes[0].listtransactions( label="label_B_watchonly", count=100, include_watchonly=True), { "category": "receive", "label": "label_A_watchonly", "amount": Decimal("0.01") }, {}, should_not_find=True) assert_array_result(self.nodes[0].listtransactions( label="label_B_watchonly", count=100, include_watchonly=True), { "category": "receive", "label": "label_C", "amount": Decimal("0.01") }, {}, should_not_find=True) # check label C returns only label C, not A or B assert_array_result( self.nodes[0].listtransactions(label="label_C", count=100, include_watchonly=True), { "category": "receive", "label": "label_C", "amount": Decimal("0.01") }, { "txid": txid_C, "label": "label_C" }) assert_array_result(self.nodes[0].listtransactions( label="label_C", count=100, include_watchonly=True), { "category": "receive", "label": "label_A_watchonly", "amount": Decimal("0.01") }, {}, should_not_find=True) assert_array_result(self.nodes[0].listtransactions( label="label_C", count=100, include_watchonly=True), { "category": "receive", "label": "label_B_watchonly", "amount": Decimal("0.01") }, {}, should_not_find=True)
def run_test(self): # Check that there's no UTXO on none of the nodes assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("Mining blocks...") self.nodes[0].generate(1) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 50) assert_equal(walletinfo['balance'], 0) self.sync_all([self.nodes[0:3]]) self.nodes[1].generate(101) self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 50) assert_equal(self.nodes[1].getbalance(), 50) assert_equal(self.nodes[2].getbalance(), 0) # Check getbalance with different arguments assert_equal(self.nodes[0].getbalance("*"), 50) assert_equal(self.nodes[0].getbalance("*", 1), 50) assert_equal(self.nodes[0].getbalance("*", 1, True), 50) assert_equal(self.nodes[0].getbalance(minconf=1), 50) # first argument of getbalance must be excluded or set to "*" assert_raises_rpc_error(-32, "dummy first argument must be excluded or set to \"*\"", self.nodes[0].getbalance, "") # Check that only first and second nodes have UTXOs utxos = self.nodes[0].listunspent() assert_equal(len(utxos), 1) assert_equal(len(self.nodes[1].listunspent()), 1) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("test gettxout") confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"] # First, outputs that are unspent both in the chain and in the # mempool should appear with or without include_mempool txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=False) assert_equal(txout['value'], 50) txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=True) assert_equal(txout['value'], 50) # Send 21 TCS from 0 to 2 using sendtoaddress call. # Locked memory should use at least 32 bytes to sign each transaction self.log.info("test getmemoryinfo") memory_before = self.nodes[0].getmemoryinfo() self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) memory_after = self.nodes[0].getmemoryinfo() assert(memory_before['locked']['used'] + 64 <= memory_after['locked']['used']) self.log.info("test gettxout (second part)") # utxo spent in mempool should be visible if you exclude mempool # but invisible if you include mempool txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False) assert_equal(txout['value'], 50) txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True) assert txout is None # new utxo from mempool should be invisible if you exclude mempool # but visible if you include mempool txout = self.nodes[0].gettxout(mempool_txid, 0, False) assert txout is None txout1 = self.nodes[0].gettxout(mempool_txid, 0, True) txout2 = self.nodes[0].gettxout(mempool_txid, 1, True) # note the mempool tx will have randomly assigned indices # but 10 will go to node2 and the rest will go to node0 balance = self.nodes[0].getbalance() assert_equal(set([txout1['value'], txout2['value']]), set([10, balance])) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 0) # Have node0 mine a block, thus it will collect its own fee. self.nodes[0].generate(1) self.sync_all([self.nodes[0:3]]) # Exercise locking of unspent outputs unspent_0 = self.nodes[2].listunspent()[0] unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} assert_raises_rpc_error(-8, "Invalid parameter, expected locked output", self.nodes[2].lockunspent, True, [unspent_0]) self.nodes[2].lockunspent(False, [unspent_0]) assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0]) assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) assert_equal([unspent_0], self.nodes[2].listlockunspent()) self.nodes[2].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[2].listlockunspent()), 0) assert_raises_rpc_error(-8, "Invalid parameter, unknown transaction", self.nodes[2].lockunspent, False, [{"txid": "0000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "Invalid parameter, vout index out of bounds", self.nodes[2].lockunspent, False, [{"txid": unspent_0["txid"], "vout": 999}]) # An output should be unlocked when spent unspent_0 = self.nodes[1].listunspent()[0] self.nodes[1].lockunspent(False, [unspent_0]) tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 }) tx = self.nodes[1].fundrawtransaction(tx)['hex'] tx = self.nodes[1].signrawtransactionwithwallet(tx)["hex"] self.nodes[1].sendrawtransaction(tx) assert_equal(len(self.nodes[1].listlockunspent()), 0) # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) self.sync_all([self.nodes[0:3]]) # node0 should end up with 100 btc in block rewards plus fees, but # minus the 21 plus fees sent to node2 assert_equal(self.nodes[0].getbalance(), 100 - 21) assert_equal(self.nodes[2].getbalance(), 21) # Node0 should have two unspent outputs. # Create a couple of transactions to send them to node2, submit them through # node1, and make sure both node0 and node2 pick them up properly: node0utxos = self.nodes[0].listunspent(1) assert_equal(len(node0utxos), 2) # create both transactions txns_to_send = [] for utxo in node0utxos: inputs = [] outputs = {} inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) outputs[self.nodes[2].getnewaddress()] = utxo["amount"] - 3 raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) txns_to_send.append(self.nodes[0].signrawtransactionwithwallet(raw_tx)) # Have node 1 (miner) send the transactions self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], True) self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True) # Have node1 mine a block to confirm transactions: self.nodes[1].generate(1) self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 94) # Verify that a spent output cannot be locked anymore spent_0 = {"txid": node0utxos[0]["txid"], "vout": node0utxos[0]["vout"]} assert_raises_rpc_error(-8, "Invalid parameter, expected unspent output", self.nodes[0].lockunspent, False, [spent_0]) # Send 10 TCS normal address = self.nodes[0].getnewaddress("test") fee_per_byte = Decimal('0.001') / 1000 self.nodes[2].settxfee(fee_per_byte * 1000) txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid))) assert_equal(self.nodes[0].getbalance(), Decimal('10')) # Send 10 TCS with subtract fee from amount txid = self.nodes[2].sendtoaddress(address, 10, "", "", True) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid))) # Sendmany 10 TCS txid = self.nodes[2].sendmany('', {address: 10}, 0, "", []) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_0_bal += Decimal('10') node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid))) assert_equal(self.nodes[0].getbalance(), node_0_bal) # Sendmany 10 TCS with subtract fee from amount txid = self.nodes[2].sendmany('', {address: 10}, 0, "", [address]) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid))) # Test ResendWalletTransactions: # Create a couple of transactions, then start up a fourth # node (nodes[3]) and ask nodes[0] to rebroadcast. # EXPECT: nodes[3] should have those transactions in its mempool. txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) sync_mempools(self.nodes[0:2]) self.start_node(3) connect_nodes_bi(self.nodes, 0, 3) sync_blocks(self.nodes) relayed = self.nodes[0].resendwallettransactions() assert_equal(set(relayed), {txid1, txid2}) sync_mempools(self.nodes) assert(txid1 in self.nodes[3].getrawmempool()) # Exercise balance rpcs assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], 1) assert_equal(self.nodes[0].getunconfirmedbalance(), 1) # check if we can list zero value tx as available coins # 1. create raw_tx # 2. hex-changed one output to 0.0 # 3. sign and send # 4. check if recipient (node0) can list the zero value tx usp = self.nodes[1].listunspent(query_options={'minimumAmount': '49.998'})[0] inputs = [{"txid": usp['txid'], "vout": usp['vout']}] outputs = {self.nodes[1].getnewaddress(): 49.998, self.nodes[0].getnewaddress(): 11.11} raw_tx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") # replace 11.11 with 0.0 (int32) signed_raw_tx = self.nodes[1].signrawtransactionwithwallet(raw_tx) decoded_raw_tx = self.nodes[1].decoderawtransaction(signed_raw_tx['hex']) zero_value_txid = decoded_raw_tx['txid'] self.nodes[1].sendrawtransaction(signed_raw_tx['hex']) self.sync_all() self.nodes[1].generate(1) # mine a block self.sync_all() unspent_txs = self.nodes[0].listunspent() # zero value tx must be in listunspents output found = False for uTx in unspent_txs: if uTx['txid'] == zero_value_txid: found = True assert_equal(uTx['amount'], Decimal('0')) assert(found) # do some -walletbroadcast tests self.stop_nodes() self.start_node(0, ["-walletbroadcast=0"]) self.start_node(1, ["-walletbroadcast=0"]) self.start_node(2, ["-walletbroadcast=0"]) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) self.sync_all([self.nodes[0:3]]) txid_not_broadcast = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast) self.nodes[1].generate(1) # mine a block, tx should not be in there self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[2].getbalance(), node_2_bal) # should not be changed because tx was not broadcasted # now broadcast from another node, mine a block, sync, and check the balance self.nodes[1].sendrawtransaction(tx_obj_not_broadcast['hex']) self.nodes[1].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal += 2 tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast) assert_equal(self.nodes[2].getbalance(), node_2_bal) # create another tx self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) # restart the nodes with -walletbroadcast=1 self.stop_nodes() self.start_node(0) self.start_node(1) self.start_node(2) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) sync_blocks(self.nodes[0:3]) self.nodes[0].generate(1) sync_blocks(self.nodes[0:3]) node_2_bal += 2 # tx should be added to balance because after restarting the nodes tx should be broadcast assert_equal(self.nodes[2].getbalance(), node_2_bal) # send a tx with value in a string (PR#6380 +) txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-2')) txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-0.0001')) # check if JSON parser can handle scientific notation in strings txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1e-4") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-0.0001')) # This will raise an exception because the amount type is wrong assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4") # This will raise an exception since generate does not accept a string assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2") # Import address and private key to check correct behavior of spendable unspents # 1. Send some coins to generate new UTXO address_to_import = self.nodes[2].getnewaddress() txid = self.nodes[0].sendtoaddress(address_to_import, 1) self.nodes[0].generate(1) self.sync_all([self.nodes[0:3]]) # 2. Import address from node2 to node1 self.nodes[1].importaddress(address_to_import) # 3. Validate that the imported address is watch-only on node1 assert(self.nodes[1].getaddressinfo(address_to_import)["iswatchonly"]) # 4. Check that the unspents after import are not spendable assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": False}) # 5. Import private key of the previously imported address on node1 priv_key = self.nodes[2].dumpprivkey(address_to_import) self.nodes[1].importprivkey(priv_key) # 6. Check that the unspents are now spendable on node1 assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": True}) # Mine a block from node0 to an address from node1 coinbase_addr = self.nodes[1].getnewaddress() block_hash = self.nodes[0].generatetoaddress(1, coinbase_addr)[0] coinbase_txid = self.nodes[0].getblock(block_hash)['tx'][0] self.sync_all([self.nodes[0:3]]) # Check that the txid and balance is found by node1 self.nodes[1].gettransaction(coinbase_txid) # check if wallet or blockchain maintenance changes the balance self.sync_all([self.nodes[0:3]]) blocks = self.nodes[0].generate(2) self.sync_all([self.nodes[0:3]]) balance_nodes = [self.nodes[i].getbalance() for i in range(3)] block_count = self.nodes[0].getblockcount() # Check modes: # - True: unicode escaped as \u.... # - False: unicode directly as UTF-8 for mode in [True, False]: self.nodes[0].rpc.ensure_ascii = mode # unicode check: Basic Multilingual Plane, Supplementary Plane respectively for label in [u'ббаБаА', u'№ Ё']: addr = self.nodes[0].getnewaddress() self.nodes[0].setlabel(addr, label) assert_equal(self.nodes[0].getaddressinfo(addr)['label'], label) assert(label in self.nodes[0].listlabels()) self.nodes[0].rpc.ensure_ascii = True # restore to default # maintenance tests maintenance = [ '-rescan', '-reindex', '-zapwallettxes=1', '-zapwallettxes=2', # disabled until issue is fixed: https://github.com/testcoinsuper/testcoinsuper/issues/7463 # '-salvagewallet', ] chainlimit = 6 for m in maintenance: self.log.info("check " + m) self.stop_nodes() # set lower ancestor limit for later self.start_node(0, [m, "-limitancestorcount=" + str(chainlimit)]) self.start_node(1, [m, "-limitancestorcount=" + str(chainlimit)]) self.start_node(2, [m, "-limitancestorcount=" + str(chainlimit)]) if m == '-reindex': # reindex will leave rpc warm up "early"; Wait for it to finish wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)]) assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) # Exercise listsinceblock with the last two blocks coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) assert_equal(coinbase_tx_1["lastblock"], blocks[1]) assert_equal(len(coinbase_tx_1["transactions"]), 1) assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0) # ==Check that wallet prefers to use coins that don't exceed mempool limits ===== # Get all non-zero utxos together chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()] singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True) self.nodes[0].generate(1) node0_balance = self.nodes[0].getbalance() # Split into two chains rawtx = self.nodes[0].createrawtransaction([{"txid": singletxid, "vout": 0}], {chain_addrs[0]: node0_balance / 2 - Decimal('0.01'), chain_addrs[1]: node0_balance / 2 - Decimal('0.01')}) signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx) singletxid = self.nodes[0].sendrawtransaction(signedtx["hex"]) self.nodes[0].generate(1) # Make a long chain of unconfirmed payments without hitting mempool limit # Each tx we make leaves only one output of change on a chain 1 longer # Since the amount to send is always much less than the outputs, we only ever need one output # So we should be able to generate exactly chainlimit txs for each original output sending_addr = self.nodes[1].getnewaddress() txid_list = [] for i in range(chainlimit * 2): txid_list.append(self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))) assert_equal(self.nodes[0].getmempoolinfo()['size'], chainlimit * 2) assert_equal(len(txid_list), chainlimit * 2) # Without walletrejectlongchains, we will still generate a txid # The tx will be stored in the wallet but not accepted to the mempool extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001')) assert(extra_txid not in self.nodes[0].getrawmempool()) assert(extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()]) self.nodes[0].abandontransaction(extra_txid) total_txs = len(self.nodes[0].listtransactions("*", 99999)) # Try with walletrejectlongchains # Double chain limit but require combining inputs, so we pass SelectCoinsMinConf self.stop_node(0) self.start_node(0, extra_args=["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)]) # wait for loadmempool timeout = 10 while (timeout > 0 and len(self.nodes[0].getrawmempool()) < chainlimit * 2): time.sleep(0.5) timeout -= 0.5 assert_equal(len(self.nodes[0].getrawmempool()), chainlimit * 2) node0_balance = self.nodes[0].getbalance() # With walletrejectlongchains we will not create the tx and store it in our wallet. assert_raises_rpc_error(-4, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01')) # Verify nothing new in wallet assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999))) # Test getaddressinfo. Note that these addresses are taken from disablewallet.py assert_raises_rpc_error(-5, "Invalid address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac") assert not address_info["ismine"] assert not address_info["iswatchonly"] assert not address_info["isscript"]
def run_test(self): # Simple send, 0 to 1: txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1000) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, {"category": "send", "amount": Decimal("-1000"), "confirmations": 0}) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, {"category": "receive", "amount": Decimal("1000"), "confirmations": 0}) # mine a block, confirmations should change: self.nodes[0].generate(1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, {"category": "send", "amount": Decimal("-1000"), "confirmations": 1}) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, {"category": "receive", "amount": Decimal("1000"), "confirmations": 1}) # send-to-self: txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2000) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid, "category": "send"}, {"amount": Decimal("-2000")}) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid, "category": "receive"}, {"amount": Decimal("2000")}) # sendmany from node1: twice to self, twice to node2: send_to = {self.nodes[0].getnewaddress(): 1100, self.nodes[1].getnewaddress(): 2200, self.nodes[0].getnewaddress(): 3300, self.nodes[1].getnewaddress(): 4400} txid = self.nodes[1].sendmany("", send_to) self.sync_all() assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-1100")}, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), {"category": "receive", "amount": Decimal("1100")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-2200")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "receive", "amount": Decimal("2200")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-3300")}, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), {"category": "receive", "amount": Decimal("3300")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "send", "amount": Decimal("-4400")}, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), {"category": "receive", "amount": Decimal("4400")}, {"txid": txid}) pubkey = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['pubkey'] multisig = self.nodes[1].createmultisig(1, [pubkey]) self.nodes[0].importaddress(multisig["redeemScript"], "watchonly", False, True) txid = self.nodes[1].sendtoaddress(multisig["address"], 1000) self.nodes[1].generate(1) self.sync_all() assert not [tx for tx in self.nodes[0].listtransactions(dummy="*", count=100, skip=0, include_watchonly=False) if "label" in tx and tx["label"] == "watchonly"] txs = [tx for tx in self.nodes[0].listtransactions(dummy="*", count=100, skip=0, include_watchonly=True) if "label" in tx and tx['label'] == 'watchonly'] assert_array_result(txs, {"category": "receive", "amount": Decimal("1000")}, {"txid": txid}) self.run_rbf_opt_in_test()
def run_test(self): self.nodes[0].generate(1) # Get out of IBD self.sync_all() # Simple send, 0 to 1: txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "amount": Decimal("-0.1"), "confirmations": 0 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "amount": Decimal("0.1"), "confirmations": 0 }) # mine a block, confirmations should change: self.nodes[0].generate(1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "amount": Decimal("-0.1"), "confirmations": 1 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "amount": Decimal("0.1"), "confirmations": 1 }) # send-to-self: txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.2) assert_array_result(self.nodes[0].listtransactions(), { "txid": txid, "category": "send" }, {"amount": Decimal("-0.2")}) assert_array_result(self.nodes[0].listtransactions(), { "txid": txid, "category": "receive" }, {"amount": Decimal("0.2")}) # sendmany from node1: twice to self, twice to node2: send_to = { self.nodes[0].getnewaddress(): 0.11, self.nodes[1].getnewaddress(): 0.22, self.nodes[0].getnewaddress(): 0.33, self.nodes[1].getnewaddress(): 0.44 } txid = self.nodes[1].sendmany("", send_to) self.sync_all() assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.11") }, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), { "category": "receive", "amount": Decimal("0.11") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.22") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "receive", "amount": Decimal("0.22") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.33") }, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), { "category": "receive", "amount": Decimal("0.33") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.44") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "receive", "amount": Decimal("0.44") }, {"txid": txid}) pubkey = self.nodes[1].getaddressinfo( self.nodes[1].getnewaddress())['pubkey'] multisig = self.nodes[1].createmultisig(1, [pubkey]) self.nodes[0].importaddress(multisig["redeemScript"], "watchonly", False, True) txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1) self.nodes[1].generate(1) self.sync_all() assert len(self.nodes[0].listtransactions( label="watchonly", count=100, include_watchonly=False)) == 0 assert_array_result( self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=True), { "category": "receive", "amount": Decimal("0.1") }, { "txid": txid, "label": "watchonly" }) self.run_rbf_opt_in_test()
def run_test(self): # Check that there's no UTXO on none of the nodes assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("Mining blocks...") self.nodes[0].generate(1, self.signblockprivkey_wif) walletinfo = self.nodes[0].getwalletinfo() assert_equal(len(walletinfo['balance']), 1) assert_equal(walletinfo['balance']['TPC'], 50) self.sync_all([self.nodes[0:3]]) self.nodes[2].generate(1, self.signblockprivkey_wif) self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 50) assert_equal(self.nodes[1].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 50) # PART 1: using cp2pkh address # utxo = self.nodes[0].listunspent()[0] new_address = self.nodes[0].getnewaddress() pubkeyhash = hash160( hex_str_to_bytes( self.nodes[0].getaddressinfo(new_address)["pubkey"])) colorid1 = b'\xc1' + sha256(hex_str_to_bytes(utxo['scriptPubKey'])) cp2pkh_address = byte_to_base58(pubkeyhash, colorid1, 112) # create colored transaction 1 raw_tx_in_block = self.nodes[0].signrawtransactionwithwallet( self.nodes[0].createrawtransaction( inputs=[{ 'txid': utxo['txid'], 'vout': utxo['vout'] }], outputs=[{ self.nodes[1].getnewaddress(): 10 }, { self.nodes[0].getnewaddress(): 39 }, { cp2pkh_address: 100 }], ), [], "ALL", self.options.scheme)['hex'] txid_in_block = self.nodes[0].sendrawtransaction( hexstring=raw_tx_in_block, allowhighfees=True) self.sync_all([self.nodes[0:3]]) self.nodes[2].generate(1, self.signblockprivkey_wif) assert_equal(self.nodes[0].getbalance(), 39) assert_equal(self.nodes[1].getbalance(), 10) assert_equal(self.nodes[2].getbalance(), 101) walletinfo = self.nodes[0].getwalletinfo() assert_equal(len(walletinfo['balance']), 2) assert_equal(walletinfo['balance']['TPC'], 39) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 100) walletinfo = self.nodes[1].getwalletinfo() assert_equal(len(walletinfo['balance']), 2) assert_equal(walletinfo['balance']['TPC'], 10) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 0) walletinfo = self.nodes[2].getwalletinfo() assert_equal(len(walletinfo['balance']), 1) assert_equal(walletinfo['balance']['TPC'], 101) colorFromNode = self.nodes[0].getcolor(1, utxo['scriptPubKey']) assert_equal(hex_str_to_bytes(colorFromNode), colorid1) colorFromNode = self.nodes[0].getcolor(2, txid_in_block, 1) utxo_ser = sha256( reverse_bytes(hex_str_to_bytes(txid_in_block)) + (1).to_bytes(4, byteorder='little')) coloridexpected = 'c2' + encode(utxo_ser, 'hex_codec').decode('ascii') assert_equal(colorFromNode, coloridexpected) # PART 2: using cp2sh address utxo = self.nodes[0].listunspent()[0] pubkeyhash = hash160( hex_str_to_bytes(self.nodes[1].getaddressinfo( self.nodes[1].getnewaddress())["pubkey"])) scripthash = hash160( CScript( [OP_DUP, OP_HASH160, pubkeyhash, OP_EQUALVERIFY, OP_CHECKSIG])) colorid2 = b'\xc1' + sha256(hex_str_to_bytes(utxo['scriptPubKey'])) cp2sh_address = byte_to_base58(scripthash, colorid2, 197) # create colored transaction 2 raw_tx_in_block = self.nodes[0].signrawtransactionwithwallet( self.nodes[0].createrawtransaction( inputs=[{ 'txid': utxo['txid'], 'vout': utxo['vout'] }], outputs=[{ self.nodes[1].getnewaddress(): 10 }, { self.nodes[0].getnewaddress(): 28 }, { cp2sh_address: 100 }], ), [], "ALL", self.options.scheme)['hex'] txid_in_block = self.nodes[0].sendrawtransaction( hexstring=raw_tx_in_block, allowhighfees=True) self.sync_all([self.nodes[0:3]]) self.nodes[2].generate(1, self.signblockprivkey_wif) walletinfo = self.nodes[0].getwalletinfo() assert_equal(len(walletinfo['balance']), 3) assert_equal(walletinfo['balance']['TPC'], 28) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 100) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid2)], 0) walletinfo = self.nodes[1].getwalletinfo() assert_equal(len(walletinfo['balance']), 3) assert_equal(walletinfo['balance']['TPC'], 20) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 0) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid2)], 100) walletinfo = self.nodes[2].getwalletinfo() assert_equal(len(walletinfo['balance']), 1) assert_equal(walletinfo['balance']['TPC'], 152) colorFromNode = self.nodes[0].getcolor(1, utxo['scriptPubKey']) assert_equal(hex_str_to_bytes(colorFromNode), colorid2) colorFromNode = self.nodes[0].getcolor(2, txid_in_block, 1) utxo_ser = sha256( reverse_bytes(hex_str_to_bytes(txid_in_block)) + (1).to_bytes(4, byteorder='little')) coloridexpected = 'c2' + encode(utxo_ser, 'hex_codec').decode('ascii') assert_equal(colorFromNode, coloridexpected) # send colored coins (colorid1) from node0 to node1 using sendtoaddress: new_address = self.nodes[1].getnewaddress() pubkeyhash = hash160( hex_str_to_bytes( self.nodes[1].getaddressinfo(new_address)["pubkey"])) cp2pkh_address = byte_to_base58(pubkeyhash, colorid1, 112) self.log.debug("Testing sendtoaddress") txid = self.nodes[0].sendtoaddress(cp2pkh_address, 10) self.sync_all([self.nodes[0:3]]) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "token": bytes_to_hex_str(colorid1), "amount": -10, "confirmations": 0 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "token": bytes_to_hex_str(colorid1), "amount": 10, "confirmations": 0 }) #mine a block, confirmations should change: self.nodes[2].generate(1, self.signblockprivkey_wif) self.sync_all([self.nodes[0:3]]) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "token": bytes_to_hex_str(colorid1), "amount": -10, "confirmations": 1 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "token": bytes_to_hex_str(colorid1), "amount": 10, "confirmations": 1 }) walletinfo = self.nodes[0].getwalletinfo() assert_equal(len(walletinfo['balance']), 3) assert_equal(str(walletinfo['balance']['TPC']), '27.99990480') assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 90) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid2)], 0) walletinfo = self.nodes[1].getwalletinfo() assert_equal(len(walletinfo['balance']), 3) assert_equal(walletinfo['balance']['TPC'], 20) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 10) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid2)], 100) walletinfo = self.nodes[2].getwalletinfo() assert_equal(len(walletinfo['balance']), 1) assert_equal(str(walletinfo['balance']['TPC']), '202.00009520') # send colored coins (colorid2) from node1 to node0 using transfertoken: new_address = self.nodes[0].getnewaddress() pubkeyhash = hash160( hex_str_to_bytes( self.nodes[0].getaddressinfo(new_address)["pubkey"])) cp2pkh_address = byte_to_base58(pubkeyhash, colorid2, 112) self.log.debug("Testing transfertoken") txid_transfer = self.nodes[1].transfertoken(cp2pkh_address, 10) self.sync_all([self.nodes[0:3]]) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_transfer}, { "category": "send", "token": bytes_to_hex_str(colorid2), "amount": -10, "confirmations": 0 }) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_transfer}, { "category": "receive", "token": bytes_to_hex_str(colorid2), "amount": 10, "confirmations": 0 }) #mine a block, confirmations should change: self.nodes[2].generate(1, self.signblockprivkey_wif) self.sync_all([self.nodes[0:3]]) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_transfer}, { "category": "send", "token": bytes_to_hex_str(colorid2), "amount": -10, "confirmations": 1 }) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_transfer}, { "category": "receive", "token": bytes_to_hex_str(colorid2), "amount": 10, "confirmations": 1 }) walletinfo = self.nodes[0].getwalletinfo() assert_equal(len(walletinfo['balance']), 3) assert_equal(str(walletinfo['balance']['TPC']), '27.99990480') assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 90) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid2)], 10) walletinfo = self.nodes[1].getwalletinfo() assert_equal(len(walletinfo['balance']), 3) assert_equal(str(walletinfo['balance']['TPC']), '19.99992080') assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 10) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid2)], 90) walletinfo = self.nodes[2].getwalletinfo() assert_equal(len(walletinfo['balance']), 1) assert_equal(str(walletinfo['balance']['TPC']), '252.00017440') self.log.debug("Testing getcolor") node2_utxos = self.nodes[2].listunspent() colorFromNode = self.nodes[2].getcolor(2, node2_utxos[0]['txid'], node2_utxos[0]['vout']) utxo_ser = sha256( reverse_bytes(hex_str_to_bytes(node2_utxos[0]['txid'])) + (node2_utxos[0]['vout']).to_bytes(4, byteorder='little')) colorid3 = 'c2' + encode(utxo_ser, 'hex_codec').decode('ascii') assert_equal(colorFromNode, colorid3) colorFromNode = self.nodes[2].getcolor(3, node2_utxos[1]['txid'], node2_utxos[1]['vout']) utxo_ser = sha256( reverse_bytes(hex_str_to_bytes(node2_utxos[1]['txid'])) + (node2_utxos[0]['vout']).to_bytes(4, byteorder='little')) colorid4 = 'c3' + encode(utxo_ser, 'hex_codec').decode('ascii') assert_equal(colorFromNode, colorid4) self.log.debug("Testing issuetoken") res = self.nodes[2].issuetoken(2, 100, node2_utxos[0]['txid'], node2_utxos[0]['vout']) txid_issue = res['txid'] assert_equal(res['color'], colorid3) assert_array_result(self.nodes[2].listtransactions(), {"txid": txid_issue}, { "category": "receive", "token": colorid3, "amount": 100, "confirmations": 0 }) #mine a block, confirmations should change: self.nodes[2].generate(1, self.signblockprivkey_wif) self.sync_all([self.nodes[0:3]]) assert_array_result(self.nodes[2].listtransactions(), {"txid": txid_issue}, { "category": "receive", "token": colorid3, "amount": 100, "confirmations": 1 }) walletinfo = self.nodes[0].getwalletinfo() assert_equal(len(walletinfo['balance']), 3) assert_equal(str(walletinfo['balance']['TPC']), '27.99990480') assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 90) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid2)], 10) walletinfo = self.nodes[1].getwalletinfo() assert_equal(len(walletinfo['balance']), 3) assert_equal(str(walletinfo['balance']['TPC']), '19.99992080') assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 10) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid2)], 90) walletinfo = self.nodes[2].getwalletinfo() assert_equal(len(walletinfo['balance']), 2) assert_equal(str(walletinfo['balance']['TPC']), '302.00017440') assert_equal(walletinfo['balance'][colorid3], 100) self.log.debug("Testing burntoken") txid_burn = self.nodes[1].burntoken(bytes_to_hex_str(colorid2), 20) self.nodes[2].generate(1, self.signblockprivkey_wif) self.sync_all([self.nodes[0:3]]) walletinfo = self.nodes[0].getwalletinfo() assert_equal(len(walletinfo['balance']), 3) assert_equal(str(walletinfo['balance']['TPC']), '27.99990480') assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 90) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid2)], 10) walletinfo = self.nodes[1].getwalletinfo() assert_equal(len(walletinfo['balance']), 3) assert_equal(str(walletinfo['balance']['TPC']), '19.99983940') assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 10) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid2)], 70) walletinfo = self.nodes[2].getwalletinfo() assert_equal(len(walletinfo['balance']), 2) assert_equal(str(walletinfo['balance']['TPC']), '352.00017440') assert_equal(walletinfo['balance'][colorid3], 100) txid_burn = self.nodes[0].burntoken(bytes_to_hex_str(colorid1), 90) self.nodes[2].generate(1, self.signblockprivkey_wif) self.sync_all([self.nodes[0:3]]) walletinfo = self.nodes[0].getwalletinfo() assert_equal(len(walletinfo['balance']), 3) assert_equal(str(walletinfo['balance']['TPC']), '27.99983720') assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 0) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid2)], 10) walletinfo = self.nodes[1].getwalletinfo() assert_equal(len(walletinfo['balance']), 3) assert_equal(str(walletinfo['balance']['TPC']), '19.99983940') assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid1)], 10) assert_equal(walletinfo['balance'][bytes_to_hex_str(colorid2)], 70) walletinfo = self.nodes[2].getwalletinfo() assert_equal(len(walletinfo['balance']), 2) assert_equal(str(walletinfo['balance']['TPC']), '402.00025580') assert_equal(walletinfo['balance'][colorid3], 100)
def run_test(self): # save the number of coinbase reward addresses so far num_cb_reward_addresses = len(self.nodes[1].listreceivedbyaddress( minconf=0, include_empty=True, include_watchonly=True)) self.log.info("listreceivedbyaddress Test") # Send from node 0 to 1 addr = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # Check not listed in listreceivedbyaddress because has 0 confirmations assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": addr}, {}, True) # Bury Tx under 10 block so it will be returned by listreceivedbyaddress self.generate(self.nodes[1], 10) assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": addr}, { "address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [ txid, ] }) # With min confidence < 10 assert_array_result(self.nodes[1].listreceivedbyaddress(5), {"address": addr}, { "address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [ txid, ] }) # With min confidence > 10, should not find Tx assert_array_result(self.nodes[1].listreceivedbyaddress(11), {"address": addr}, {}, True) # Empty Tx empty_addr = self.nodes[1].getnewaddress() assert_array_result(self.nodes[1].listreceivedbyaddress(0, True), {"address": empty_addr}, { "address": empty_addr, "label": "", "amount": 0, "confirmations": 0, "txids": [] }) # Test Address filtering # Only on addr expected = { "address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [ txid, ] } res = self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True, address_filter=addr) assert_array_result(res, {"address": addr}, expected) assert_equal(len(res), 1) # Test for regression on CLI calls with address string (#14173) cli_res = self.nodes[1].cli.listreceivedbyaddress(0, True, True, addr) assert_array_result(cli_res, {"address": addr}, expected) assert_equal(len(cli_res), 1) # Error on invalid address assert_raises_rpc_error(-4, "address_filter parameter was invalid", self.nodes[1].listreceivedbyaddress, minconf=0, include_empty=True, include_watchonly=True, address_filter="bamboozling") # Another address receive money res = self.nodes[1].listreceivedbyaddress(0, True, True) assert_equal(len(res), 2 + num_cb_reward_addresses) # Right now 2 entries other_addr = self.nodes[1].getnewaddress() txid2 = self.nodes[0].sendtoaddress(other_addr, 0.1) self.generate(self.nodes[0], 1) # Same test as above should still pass expected = { "address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 11, "txids": [ txid, ] } res = self.nodes[1].listreceivedbyaddress(0, True, True, addr) assert_array_result(res, {"address": addr}, expected) assert_equal(len(res), 1) # Same test as above but with other_addr should still pass expected = { "address": other_addr, "label": "", "amount": Decimal("0.1"), "confirmations": 1, "txids": [ txid2, ] } res = self.nodes[1].listreceivedbyaddress(0, True, True, other_addr) assert_array_result(res, {"address": other_addr}, expected) assert_equal(len(res), 1) # Should be two entries though without filter res = self.nodes[1].listreceivedbyaddress(0, True, True) assert_equal(len(res), 3 + num_cb_reward_addresses) # Became 3 entries # Not on random addr other_addr = self.nodes[0].getnewaddress( ) # note on node[0]! just a random addr res = self.nodes[1].listreceivedbyaddress(0, True, True, other_addr) assert_equal(len(res), 0) self.log.info("getreceivedbyaddress Test") # Send from node 0 to 1 addr = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # Check balance is 0 because of 0 confirmations balance = self.nodes[1].getreceivedbyaddress(addr) assert_equal(balance, Decimal("0.0")) # Check balance is 0.1 balance = self.nodes[1].getreceivedbyaddress(addr, 0) assert_equal(balance, Decimal("0.1")) # Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress self.generate(self.nodes[1], 10) balance = self.nodes[1].getreceivedbyaddress(addr) assert_equal(balance, Decimal("0.1")) # Trying to getreceivedby for an address the wallet doesn't own should return an error assert_raises_rpc_error(-4, "Address not found in wallet", self.nodes[0].getreceivedbyaddress, addr) self.log.info("listreceivedbylabel + getreceivedbylabel Test") # set pre-state label = '' address = self.nodes[1].getnewaddress() test_address(self.nodes[1], address, labels=[label]) received_by_label_json = [ r for r in self.nodes[1].listreceivedbylabel() if r["label"] == label ][0] balance_by_label = self.nodes[1].getreceivedbylabel(label) txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # listreceivedbylabel should return received_by_label_json because of 0 confirmations assert_array_result(self.nodes[1].listreceivedbylabel(), {"label": label}, received_by_label_json) # getreceivedbyaddress should return same balance because of 0 confirmations balance = self.nodes[1].getreceivedbylabel(label) assert_equal(balance, balance_by_label) self.generate(self.nodes[1], 10) # listreceivedbylabel should return updated received list assert_array_result( self.nodes[1].listreceivedbylabel(), {"label": label}, { "label": received_by_label_json["label"], "amount": (received_by_label_json["amount"] + Decimal("0.1")) }) # getreceivedbylabel should return updated receive total balance = self.nodes[1].getreceivedbylabel(label) assert_equal(balance, balance_by_label + Decimal("0.1")) # Create a new label named "mynewlabel" that has a 0 balance address = self.nodes[1].getnewaddress() self.nodes[1].setlabel(address, "mynewlabel") received_by_label_json = [ r for r in self.nodes[1].listreceivedbylabel(0, True) if r["label"] == "mynewlabel" ][0] # Test includeempty of listreceivedbylabel assert_equal(received_by_label_json["amount"], Decimal("0.0")) # Test getreceivedbylabel for 0 amount labels balance = self.nodes[1].getreceivedbylabel("mynewlabel") assert_equal(balance, Decimal("0.0")) self.log.info("Tests for including coinbase outputs") # Generate block reward to address with label label = "label" address = self.nodes[0].getnewaddress(label) reward = Decimal("25") self.generatetoaddress(self.nodes[0], 1, address) hash = self.nodes[0].getbestblockhash() self.log.info("getreceivedbyaddress returns nothing with defaults") balance = self.nodes[0].getreceivedbyaddress(address) assert_equal(balance, 0) self.log.info( "getreceivedbyaddress returns block reward when including immature coinbase" ) balance = self.nodes[0].getreceivedbyaddress( address=address, include_immature_coinbase=True) assert_equal(balance, reward) self.log.info("getreceivedbylabel returns nothing with defaults") balance = self.nodes[0].getreceivedbylabel("label") assert_equal(balance, 0) self.log.info( "getreceivedbylabel returns block reward when including immature coinbase" ) balance = self.nodes[0].getreceivedbylabel( label="label", include_immature_coinbase=True) assert_equal(balance, reward) self.log.info( "listreceivedbyaddress does not include address with defaults") assert_array_result(self.nodes[0].listreceivedbyaddress(), {"address": address}, {}, True) self.log.info( "listreceivedbyaddress includes address when including immature coinbase" ) assert_array_result( self.nodes[0].listreceivedbyaddress( minconf=1, include_immature_coinbase=True), {"address": address}, { "address": address, "amount": reward }) self.log.info( "listreceivedbylabel does not include label with defaults") assert_array_result(self.nodes[0].listreceivedbylabel(), {"label": label}, {}, True) self.log.info( "listreceivedbylabel includes label when including immature coinbase" ) assert_array_result( self.nodes[0].listreceivedbylabel(minconf=1, include_immature_coinbase=True), {"label": label}, { "label": label, "amount": reward }) self.log.info("Generate 100 more blocks") self.generate(self.nodes[0], COINBASE_MATURITY) self.log.info("getreceivedbyaddress returns reward with defaults") balance = self.nodes[0].getreceivedbyaddress(address) assert_equal(balance, reward) self.log.info("getreceivedbylabel returns reward with defaults") balance = self.nodes[0].getreceivedbylabel("label") assert_equal(balance, reward) self.log.info("listreceivedbyaddress includes address with defaults") assert_array_result(self.nodes[0].listreceivedbyaddress(), {"address": address}, { "address": address, "amount": reward }) self.log.info("listreceivedbylabel includes label with defaults") assert_array_result(self.nodes[0].listreceivedbylabel(), {"label": label}, { "label": label, "amount": reward }) self.log.info("Invalidate block that paid to address") self.nodes[0].invalidateblock(hash) self.log.info( "getreceivedbyaddress does not include invalidated block when minconf is 0 when including immature coinbase" ) balance = self.nodes[0].getreceivedbyaddress( address=address, minconf=0, include_immature_coinbase=True) assert_equal(balance, 0) self.log.info( "getreceivedbylabel does not include invalidated block when minconf is 0 when including immature coinbase" ) balance = self.nodes[0].getreceivedbylabel( label="label", minconf=0, include_immature_coinbase=True) assert_equal(balance, 0) self.log.info( "listreceivedbyaddress does not include invalidated block when minconf is 0 when including immature coinbase" ) assert_array_result( self.nodes[0].listreceivedbyaddress( minconf=0, include_immature_coinbase=True), {"address": address}, {}, True) self.log.info( "listreceivedbylabel does not include invalidated block when minconf is 0 when including immature coinbase" ) assert_array_result( self.nodes[0].listreceivedbylabel(minconf=0, include_immature_coinbase=True), {"label": label}, {}, True) # Test exclude_coinbase address2 = self.nodes[1].getnewaddress(label) self.generatetoaddress(self.nodes[1], COINBASE_MATURITY + 1, address2, sync_fun=self.no_op) self.log.info( "getreceivedbyaddress returns nothing when excluding coinbase") balance = self.nodes[1].getreceivedbyaddress(address2) assert_equal(balance, 0) self.log.info( "getreceivedbylabel returns nothing when excluding coinbase") balance = self.nodes[1].getreceivedbylabel("label") assert_equal(balance, 0) self.log.info( "listreceivedbyaddress does not include address when excluding coinbase" ) assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": address2}, {}, True) self.log.info( "listreceivedbylabel does not include label when excluding coinbase" ) assert_array_result(self.nodes[1].listreceivedbylabel(), {"label": label}, {}, True) self.log.info( "getreceivedbyaddress throws when setting include_immature_coinbase with deprecated exclude_coinbase" ) assert_raises_rpc_error( -8, 'include_immature_coinbase is incompatible with deprecated exclude_coinbase', self.nodes[1].getreceivedbyaddress, address2, 1, True) self.log.info( "listreceivedbyaddress throws when setting include_immature_coinbase with deprecated exclude_coinbase" ) assert_raises_rpc_error( -8, 'include_immature_coinbase is incompatible with deprecated exclude_coinbase', self.nodes[1].listreceivedbyaddress, 1, False, False, "", True)
def test_sendRPC(self, rpcname): self.log.info("Testing %s" % rpcname) #pubkeyhash and script hash for colored addresses on node 1 new_address = self.nodes[1].getnewaddress() pubkeyhash = hash160( hex_str_to_bytes( self.nodes[1].getaddressinfo(new_address)["pubkey"])) scripthash = hash160( CScript( [OP_DUP, OP_HASH160, pubkeyhash, OP_EQUALVERIFY, OP_CHECKSIG])) cp2pkh_address1 = byte_to_base58(pubkeyhash, hex_str_to_bytes(self.colorids[1]), 112) cp2sh_address1 = byte_to_base58(scripthash, hex_str_to_bytes(self.colorids[1]), 197) cp2pkh_address2 = byte_to_base58(pubkeyhash, hex_str_to_bytes(self.colorids[2]), 112) cp2pkh_address3 = byte_to_base58(pubkeyhash, hex_str_to_bytes(self.colorids[3]), 112) cp2sh_address4 = byte_to_base58(scripthash, hex_str_to_bytes(self.colorids[4]), 197) cp2sh_address5 = byte_to_base58(scripthash, hex_str_to_bytes(self.colorids[5]), 197) sendrpc = getattr(self.nodes[0], rpcname, lambda x: print("no method %s" % x)) txid1 = sendrpc(cp2pkh_address1, 10) self.sync_all([self.nodes[0:3]]) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid1}, { "category": "send", "token": self.colorids[1], "amount": -10, "confirmations": 0 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid1}, { "category": "receive", "token": self.colorids[1], "amount": 10, "confirmations": 0 }) txid2 = sendrpc(cp2sh_address1, 10) self.sync_all([self.nodes[0:3]]) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid2}, { "category": "send", "token": self.colorids[1], "amount": -10, "confirmations": 0 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid2}, { "category": "receive", "token": self.colorids[1], "amount": 10, "confirmations": 0 }) txid3 = sendrpc(cp2pkh_address2, 10) self.sync_all([self.nodes[0:3]]) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid3}, { "category": "send", "token": self.colorids[2], "amount": -10, "confirmations": 0 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid3}, { "category": "receive", "token": self.colorids[2], "amount": 10, "confirmations": 0 }) #NFT can be transferred only once. so call it only the first time if (rpcname == "sendtoaddress"): txid4 = sendrpc(cp2pkh_address3, 1) self.sync_all([self.nodes[0:3]]) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid4}, { "category": "send", "token": self.colorids[3], "amount": -1, "confirmations": 0 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid4}, { "category": "receive", "token": self.colorids[3], "amount": 1, "confirmations": 0 }) txid5 = sendrpc(cp2sh_address4, 10) self.sync_all([self.nodes[0:3]]) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid5}, { "category": "send", "token": self.colorids[4], "amount": -10, "confirmations": 0 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid5}, { "category": "receive", "token": self.colorids[4], "amount": 10, "confirmations": 0 }) #NFT can be transferred only once. so call it only the first time if (rpcname == "sendtoaddress"): txid6 = sendrpc(cp2sh_address5, 1) self.sync_all([self.nodes[0:3]]) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid6}, { "category": "send", "token": self.colorids[5], "amount": -1, "confirmations": 0 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid6}, { "category": "receive", "token": self.colorids[5], "amount": 1, "confirmations": 0 }) #mine a block, confirmations should change: self.nodes[2].generate(1, self.signblockprivkey_wif) self.sync_all([self.nodes[0:3]]) unspent = self.nodes[0].listunspent() assert_array_result(unspent, { "txid": txid1, "token": self.colorids[1] }, { "amount": self.balance_expected[0][self.stage][3], "confirmations": 1 }) assert_array_result(unspent, { "txid": txid2, "token": self.colorids[1] }, { "amount": self.balance_expected[0][self.stage][3], "confirmations": 1 }) assert_array_result(unspent, { "txid": txid3, "token": self.colorids[2] }, { "amount": self.balance_expected[0][self.stage][5], "confirmations": 1 }) assert_array_result(unspent, { "txid": txid5, "token": self.colorids[4] }, { "amount": self.balance_expected[0][self.stage][5], "confirmations": 1 }) txlist = self.nodes[0].listtransactions() assert_array_result(txlist, {"txid": txid1}, {"confirmations": 1}) assert_array_result(txlist, {"txid": txid2}, {"confirmations": 1}) assert_array_result(txlist, {"txid": txid3}, {"confirmations": 1}) assert_array_result(txlist, {"txid": txid5}, {"confirmations": 1}) if (rpcname == "sendtoaddress"): assert_array_result(txlist, {"txid": txid4}, {"confirmations": 1}) assert_array_result(txlist, {"txid": txid6}, {"confirmations": 1}) unspent = self.nodes[1].listunspent() assert_array_result(unspent, { "txid": txid4, "token": self.colorids[3] }, { "amount": 1, "confirmations": 1 }) assert_array_result(unspent, { "txid": txid6, "token": self.colorids[5] }, { "amount": 1, "confirmations": 1 }) self.test_nodeBalances() #negative if not self.options.usecli: assert_raises_rpc_error(-3, "Invalid amount", sendrpc, cp2pkh_address1, 'foo') assert_raises_rpc_error(-3, "Invalid amount", sendrpc, cp2pkh_address1, '66ae') assert_raises_rpc_error(-3, "Invalid amount", sendrpc, cp2pkh_address1, 66.99)
def run_test(self): # Check that there's no UTXO on none of the nodes assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("Mining blocks...") self.nodes[0].generate(1) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 50) assert_equal(walletinfo['balance'], 0) self.sync_all(self.nodes[0:3]) self.nodes[1].generate(101) self.sync_all(self.nodes[0:3]) assert_equal(self.nodes[0].getbalance(), 50) assert_equal(self.nodes[1].getbalance(), 50) assert_equal(self.nodes[2].getbalance(), 0) # Check that only first and second nodes have UTXOs utxos = self.nodes[0].listunspent() assert_equal(len(utxos), 1) assert_equal(len(self.nodes[1].listunspent()), 1) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("test gettxout") confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"] # First, outputs that are unspent both in the chain and in the # mempool should appear with or without include_mempool txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=False) assert_equal(txout['value'], 50) txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=True) assert_equal(txout['value'], 50) # Send 21 BTC from 0 to 2 using sendtoaddress call. self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) self.log.info("test gettxout (second part)") # utxo spent in mempool should be visible if you exclude mempool # but invisible if you include mempool txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False) assert_equal(txout['value'], 50) txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True) assert txout is None # new utxo from mempool should be invisible if you exclude mempool # but visible if you include mempool txout = self.nodes[0].gettxout(mempool_txid, 0, False) assert txout is None txout1 = self.nodes[0].gettxout(mempool_txid, 0, True) txout2 = self.nodes[0].gettxout(mempool_txid, 1, True) # note the mempool tx will have randomly assigned indices # but 10 will go to node2 and the rest will go to node0 balance = self.nodes[0].getbalance() assert_equal(set([txout1['value'], txout2['value']]), set([10, balance])) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 0) # Have node0 mine a block, thus it will collect its own fee. self.nodes[0].generate(1) self.sync_all(self.nodes[0:3]) # Exercise locking of unspent outputs unspent_0 = self.nodes[2].listunspent()[0] unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} assert_raises_rpc_error(-8, "Invalid parameter, expected locked output", self.nodes[2].lockunspent, True, [unspent_0]) self.nodes[2].lockunspent(False, [unspent_0]) assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0]) assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) assert_equal([unspent_0], self.nodes[2].listlockunspent()) self.nodes[2].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[2].listlockunspent()), 0) assert_raises_rpc_error(-8, "txid must be of length 64 (not 34, for '0000000000000000000000000000000000')", self.nodes[2].lockunspent, False, [{"txid": "0000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[2].lockunspent, False, [{"txid": "ZZZ0000000000000000000000000000000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "Invalid parameter, unknown transaction", self.nodes[2].lockunspent, False, [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "Invalid parameter, vout index out of bounds", self.nodes[2].lockunspent, False, [{"txid": unspent_0["txid"], "vout": 999}]) # An output should be unlocked when spent unspent_0 = self.nodes[1].listunspent()[0] self.nodes[1].lockunspent(False, [unspent_0]) tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 }) tx = self.nodes[1].fundrawtransaction(tx)['hex'] tx = self.nodes[1].signrawtransactionwithwallet(tx)["hex"] self.nodes[1].sendrawtransaction(tx) assert_equal(len(self.nodes[1].listlockunspent()), 0) # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) self.sync_all(self.nodes[0:3]) # node0 should end up with 100 btc in block rewards plus fees, but # minus the 21 plus fees sent to node2 assert_equal(self.nodes[0].getbalance(), 100 - 21) assert_equal(self.nodes[2].getbalance(), 21) # Node0 should have two unspent outputs. # Create a couple of transactions to send them to node2, submit them through # node1, and make sure both node0 and node2 pick them up properly: node0utxos = self.nodes[0].listunspent(1) assert_equal(len(node0utxos), 2) # create both transactions txns_to_send = [] for utxo in node0utxos: inputs = [] outputs = {} inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) outputs[self.nodes[2].getnewaddress()] = utxo["amount"] - 3 raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) txns_to_send.append(self.nodes[0].signrawtransactionwithwallet(raw_tx)) # Have node 1 (miner) send the transactions self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], 0) self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], 0) # Have node1 mine a block to confirm transactions: self.nodes[1].generate(1) self.sync_all(self.nodes[0:3]) assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 94) # Verify that a spent output cannot be locked anymore spent_0 = {"txid": node0utxos[0]["txid"], "vout": node0utxos[0]["vout"]} assert_raises_rpc_error(-8, "Invalid parameter, expected unspent output", self.nodes[0].lockunspent, False, [spent_0]) # Send 10 BTC normal address = self.nodes[0].getnewaddress("test") fee_per_byte = Decimal('0.001') / 1000 self.nodes[2].settxfee(fee_per_byte * 1000) txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(self.nodes[0].getbalance(), Decimal('10')) # Send 10 BTC with subtract fee from amount txid = self.nodes[2].sendtoaddress(address, 10, "", "", True) self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) # Sendmany 10 BTC txid = self.nodes[2].sendmany('', {address: 10}, 0, "", []) self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) node_0_bal += Decimal('10') node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) assert_equal(self.nodes[0].getbalance(), node_0_bal) # Sendmany 10 BTC with subtract fee from amount txid = self.nodes[2].sendmany('', {address: 10}, 0, "", [address]) self.nodes[2].generate(1) self.sync_all(self.nodes[0:3]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) self.start_node(3) connect_nodes_bi(self.nodes, 0, 3) self.sync_all() # check if we can list zero value tx as available coins # 1. create raw_tx # 2. hex-changed one output to 0.0 # 3. sign and send # 4. check if recipient (node0) can list the zero value tx usp = self.nodes[1].listunspent(query_options={'minimumAmount': '49.998'})[0] inputs = [{"txid": usp['txid'], "vout": usp['vout']}] outputs = {self.nodes[1].getnewaddress(): 49.998, self.nodes[0].getnewaddress(): 11.11} raw_tx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") # replace 11.11 with 0.0 (int32) signed_raw_tx = self.nodes[1].signrawtransactionwithwallet(raw_tx) decoded_raw_tx = self.nodes[1].decoderawtransaction(signed_raw_tx['hex']) zero_value_txid = decoded_raw_tx['txid'] self.nodes[1].sendrawtransaction(signed_raw_tx['hex']) self.sync_all() self.nodes[1].generate(1) # mine a block self.sync_all() unspent_txs = self.nodes[0].listunspent() # zero value tx must be in listunspents output found = False for uTx in unspent_txs: if uTx['txid'] == zero_value_txid: found = True assert_equal(uTx['amount'], Decimal('0')) assert found # do some -walletbroadcast tests self.stop_nodes() self.start_node(0, ["-walletbroadcast=0"]) self.start_node(1, ["-walletbroadcast=0"]) self.start_node(2, ["-walletbroadcast=0"]) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) self.sync_all(self.nodes[0:3]) txid_not_broadcast = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast) self.nodes[1].generate(1) # mine a block, tx should not be in there self.sync_all(self.nodes[0:3]) assert_equal(self.nodes[2].getbalance(), node_2_bal) # should not be changed because tx was not broadcasted # now broadcast from another node, mine a block, sync, and check the balance self.nodes[1].sendrawtransaction(tx_obj_not_broadcast['hex']) self.nodes[1].generate(1) self.sync_all(self.nodes[0:3]) node_2_bal += 2 tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast) assert_equal(self.nodes[2].getbalance(), node_2_bal) # create another tx self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) # restart the nodes with -walletbroadcast=1 self.stop_nodes() self.start_node(0) self.start_node(1) self.start_node(2) connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 1, 2) connect_nodes_bi(self.nodes, 0, 2) self.sync_blocks(self.nodes[0:3]) self.nodes[0].generate(1) self.sync_blocks(self.nodes[0:3]) node_2_bal += 2 # tx should be added to balance because after restarting the nodes tx should be broadcast assert_equal(self.nodes[2].getbalance(), node_2_bal) # send a tx with value in a string (PR#6380 +) txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-2')) txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-0.0001')) # check if JSON parser can handle scientific notation in strings txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1e-4") tx_obj = self.nodes[0].gettransaction(txid) assert_equal(tx_obj['amount'], Decimal('-0.0001')) # General checks for errors from incorrect inputs # This will raise an exception because the amount type is wrong assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4") # This will raise an exception since generate does not accept a string assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2") # This will raise an exception for the invalid private key format assert_raises_rpc_error(-5, "Invalid private key encoding", self.nodes[0].importprivkey, "invalid") # This will raise an exception for importing an address with the PS2H flag temp_address = self.nodes[1].getnewaddress() assert_raises_rpc_error(-5, "Cannot use the p2sh flag with an address - use a script instead", self.nodes[0].importaddress, temp_address, "label", False, True) # This will raise an exception for attempting to dump the private key of an address you do not own assert_raises_rpc_error(-4, "Private key for address", self.nodes[0].dumpprivkey, temp_address) # This will raise an exception for attempting to get the private key of an invalid Bitcoin address assert_raises_rpc_error(-5, "Invalid Namecoin address", self.nodes[0].dumpprivkey, "invalid") # This will raise an exception for attempting to set a label for an invalid Bitcoin address assert_raises_rpc_error(-5, "Invalid Namecoin address", self.nodes[0].setlabel, "invalid address", "label") # This will raise an exception for importing an invalid address assert_raises_rpc_error(-5, "Invalid Namecoin address or script", self.nodes[0].importaddress, "invalid") # This will raise an exception for attempting to import a pubkey that isn't in hex assert_raises_rpc_error(-5, "Pubkey must be a hex string", self.nodes[0].importpubkey, "not hex") # This will raise an exception for importing an invalid pubkey assert_raises_rpc_error(-5, "Pubkey is not a valid public key", self.nodes[0].importpubkey, "5361746f736869204e616b616d6f746f") # Import address and private key to check correct behavior of spendable unspents # 1. Send some coins to generate new UTXO address_to_import = self.nodes[2].getnewaddress() txid = self.nodes[0].sendtoaddress(address_to_import, 1) self.nodes[0].generate(1) self.sync_all(self.nodes[0:3]) # 2. Import address from node2 to node1 self.nodes[1].importaddress(address_to_import) # 3. Validate that the imported address is watch-only on node1 assert self.nodes[1].getaddressinfo(address_to_import)["iswatchonly"] # 4. Check that the unspents after import are not spendable assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": False}) # 5. Import private key of the previously imported address on node1 priv_key = self.nodes[2].dumpprivkey(address_to_import) self.nodes[1].importprivkey(priv_key) # 6. Check that the unspents are now spendable on node1 assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": True}) # Mine a block from node0 to an address from node1 coinbase_addr = self.nodes[1].getnewaddress() block_hash = self.nodes[0].generatetoaddress(1, coinbase_addr)[0] coinbase_txid = self.nodes[0].getblock(block_hash)['tx'][0] self.sync_all(self.nodes[0:3]) # Check that the txid and balance is found by node1 self.nodes[1].gettransaction(coinbase_txid) # check if wallet or blockchain maintenance changes the balance self.sync_all(self.nodes[0:3]) blocks = self.nodes[0].generate(2) self.sync_all(self.nodes[0:3]) balance_nodes = [self.nodes[i].getbalance() for i in range(3)] block_count = self.nodes[0].getblockcount() # Check modes: # - True: unicode escaped as \u.... # - False: unicode directly as UTF-8 for mode in [True, False]: self.nodes[0].rpc.ensure_ascii = mode # unicode check: Basic Multilingual Plane, Supplementary Plane respectively for label in [u'ббаБаА', u'№ Ё']: addr = self.nodes[0].getnewaddress() self.nodes[0].setlabel(addr, label) assert_equal(self.nodes[0].getaddressinfo(addr)['label'], label) assert label in self.nodes[0].listlabels() self.nodes[0].rpc.ensure_ascii = True # restore to default # maintenance tests maintenance = [ '-rescan', '-reindex', '-zapwallettxes=1', '-zapwallettxes=2', # disabled until issue is fixed: https://github.com/bitcoin/bitcoin/issues/7463 # '-salvagewallet', ] chainlimit = 6 for m in maintenance: self.log.info("check " + m) self.stop_nodes() # set lower ancestor limit for later self.start_node(0, [m, "-limitancestorcount=" + str(chainlimit)]) self.start_node(1, [m, "-limitancestorcount=" + str(chainlimit)]) self.start_node(2, [m, "-limitancestorcount=" + str(chainlimit)]) if m == '-reindex': # reindex will leave rpc warm up "early"; Wait for it to finish wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)]) assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) # Exercise listsinceblock with the last two blocks coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) assert_equal(coinbase_tx_1["lastblock"], blocks[1]) assert_equal(len(coinbase_tx_1["transactions"]), 1) assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0) # ==Check that wallet prefers to use coins that don't exceed mempool limits ===== # Get all non-zero utxos together chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()] singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True) self.nodes[0].generate(1) node0_balance = self.nodes[0].getbalance() # Split into two chains rawtx = self.nodes[0].createrawtransaction([{"txid": singletxid, "vout": 0}], {chain_addrs[0]: node0_balance / 2 - Decimal('0.01'), chain_addrs[1]: node0_balance / 2 - Decimal('0.01')}) signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx) singletxid = self.nodes[0].sendrawtransaction(signedtx["hex"]) self.nodes[0].generate(1) # Make a long chain of unconfirmed payments without hitting mempool limit # Each tx we make leaves only one output of change on a chain 1 longer # Since the amount to send is always much less than the outputs, we only ever need one output # So we should be able to generate exactly chainlimit txs for each original output sending_addr = self.nodes[1].getnewaddress() txid_list = [] for i in range(chainlimit * 2): txid_list.append(self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))) assert_equal(self.nodes[0].getmempoolinfo()['size'], chainlimit * 2) assert_equal(len(txid_list), chainlimit * 2) # Without walletrejectlongchains, we will still generate a txid # The tx will be stored in the wallet but not accepted to the mempool extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001')) assert extra_txid not in self.nodes[0].getrawmempool() assert extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()] self.nodes[0].abandontransaction(extra_txid) total_txs = len(self.nodes[0].listtransactions("*", 99999)) # Try with walletrejectlongchains # Double chain limit but require combining inputs, so we pass SelectCoinsMinConf self.stop_node(0) self.start_node(0, extra_args=["-walletrejectlongchains", "-limitancestorcount=" + str(2 * chainlimit)]) # wait for loadmempool timeout = 10 while (timeout > 0 and len(self.nodes[0].getrawmempool()) < chainlimit * 2): time.sleep(0.5) timeout -= 0.5 assert_equal(len(self.nodes[0].getrawmempool()), chainlimit * 2) node0_balance = self.nodes[0].getbalance() # With walletrejectlongchains we will not create the tx and store it in our wallet. assert_raises_rpc_error(-4, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01')) # Verify nothing new in wallet assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999))) # Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py assert_raises_rpc_error(-5, "Invalid address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac") assert not address_info["ismine"] assert not address_info["iswatchonly"] assert not address_info["isscript"] assert not address_info["ischange"] # Test getaddressinfo 'ischange' field on change address. self.nodes[0].generate(1) destination = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(destination, 0.123) tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex']) output_addresses = [vout['scriptPubKey']['addresses'][0] for vout in tx["vout"]] assert len(output_addresses) > 1 for address in output_addresses: ischange = self.nodes[0].getaddressinfo(address)['ischange'] assert_equal(ischange, address != destination) if ischange: change = address self.nodes[0].setlabel(change, 'foobar') assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False)
def run_test(self): # Check that there's no UTXO on none of the nodes assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("Mining blocks...") self.nodes[0].generate(1) wallet_info = self.nodes[0].getwalletinfo() assert_equal(wallet_info['immature_balance'], 5000) assert_equal(wallet_info['balance'], 0) self.sync_all([self.nodes[0:3]]) self.nodes[1].generate(101) self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 5000) assert_equal(self.nodes[1].getbalance(), 5000) assert_equal(self.nodes[2].getbalance(), 0) # Check that only first and second nodes have UTXOs utxos = self.nodes[0].listunspent() assert_equal(len(utxos), 1) assert_equal(len(self.nodes[1].listunspent()), 1) assert_equal(len(self.nodes[2].listunspent()), 0) self.log.info("test gettxout") confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"] # First, outputs that are unspent both in the chain and in the # mempool should appear with or without include_mempool txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=False) assert_equal(txout['value'], 5000) txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=True) assert_equal(txout['value'], 5000) # Send 21 FOXD from 0 to 2 using sendtoaddress call. # Locked memory should use at least 32 bytes to sign each transaction self.log.info("test getmemoryinfo") memory_before = self.nodes[0].getmemoryinfo() self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) memory_after = self.nodes[0].getmemoryinfo() assert(memory_before['locked']['used'] + 64 <= memory_after['locked']['used']) self.log.info("test gettxout (second part)") # utxo spent in mempool should be visible if you exclude mempool # but invisible if you include mempool txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False) assert_equal(txout['value'], 5000) txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True) assert txout is None # new utxo from mempool should be invisible if you exclude mempool # but visible if you include mempool txout = self.nodes[0].gettxout(mempool_txid, 0, False) assert txout is None txout1 = self.nodes[0].gettxout(mempool_txid, 0, True) txout2 = self.nodes[0].gettxout(mempool_txid, 1, True) # note the mempool tx will have randomly assigned indices # but 10 will go to node2 and the rest will go to node0 balance = self.nodes[0].getbalance() assert_equal({txout1['value'], txout2['value']}, {10, balance}) wallet_info = self.nodes[0].getwalletinfo() assert_equal(wallet_info['immature_balance'], 0) # Have node0 mine a block, thus it will collect its own fee. self.nodes[0].generate(1) self.sync_all([self.nodes[0:3]]) # Exercise locking of unspent outputs unspent_0 = self.nodes[2].listunspent()[0] unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} self.nodes[2].lockunspent(False, [unspent_0]) assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) assert_equal([unspent_0], self.nodes[2].listlockunspent()) self.nodes[2].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[2].listlockunspent()), 0) # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) self.sync_all([self.nodes[0:3]]) # node0 should end up with 100 btc in block rewards plus fees, but # minus the 21 plus fees sent to node2 assert_equal(self.nodes[0].getbalance(), 10000-21) assert_equal(self.nodes[2].getbalance(), 21) # Node0 should have two unspent outputs. # Create a couple of transactions to send them to node2, submit them through # node1, and make sure both node0 and node2 pick them up properly: node0utxos = self.nodes[0].listunspent(1) assert_equal(len(node0utxos), 2) # create both transactions txns_to_send = [] for utxo in node0utxos: inputs = [] outputs = {} inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]}) outputs[self.nodes[2].getnewaddress("from1")] = utxo["amount"] - 3 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) # Have node1 mine a block to confirm transactions: self.nodes[1].generate(1) self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 9994) assert_equal(self.nodes[2].getbalance("from1"), 9994-21) # Send 10 FOXD normal address = self.nodes[0].getnewaddress("test") fee_per_byte = Decimal('0.001') / 1000 self.nodes[2].settxfee(fee_per_byte * 1000) txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('9984'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) assert_equal(self.nodes[0].getbalance(), Decimal('10')) # Send 10 FOXD with subtract fee from amount txid = self.nodes[2].sendtoaddress(address, 10, "", "", True) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) # Sendmany 10 FOXD txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", []) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_0_bal += Decimal('10') node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) assert_equal(self.nodes[0].getbalance(), node_0_bal) # Sendmany 10 FOXD with subtract fee from amount txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", [address]) self.nodes[2].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) # Test ResendWalletTransactions: # Create a couple of transactions, then start up a fourth # node (nodes[3]) and ask nodes[0] to rebroadcast. # EXPECT: nodes[3] should have those transactions in its mempool. txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) sync_mempools(self.nodes[0:2]) self.start_node(3) connect_nodes_bi(self.nodes, 0, 3) sync_blocks(self.nodes) relayed = self.nodes[0].resendwallettransactions() assert_equal(set(relayed), {txid1, txid2}) sync_mempools(self.nodes) assert(txid1 in self.nodes[3].getrawmempool()) # Exercise balance rpcs assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], 1) assert_equal(self.nodes[0].getunconfirmedbalance(), 1) #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(): 4999.998, self.nodes[0].getnewaddress(): 1111.11} raw_tx = self.nodes[1].createrawtransaction(inputs, outputs) raw_tx = raw_tx.replace("c04fbbde19", "0000000000") #replace 1111.11 with 0.0 (int32) self.nodes[1].decoderawtransaction(raw_tx) signed_raw_tx = self.nodes[1].signrawtransaction(raw_tx) dec_raw_tx = self.nodes[1].decoderawtransaction(signed_raw_tx['hex']) zero_value_txid = dec_raw_tx['txid'] self.nodes[1].sendrawtransaction(signed_raw_tx['hex']) self.sync_all() self.nodes[1].generate(1) #mine a block self.sync_all() unspent_txs = self.nodes[0].listunspent() #zero value tx must be in listunspents output found = False for uTx in unspent_txs: if uTx['txid'] == zero_value_txid: found = True assert_equal(uTx['amount'], Decimal('0')) assert found #do some -walletbroadcast tests self.stop_nodes() self.start_node(0, ["-walletbroadcast=0"]) self.start_node(1, ["-walletbroadcast=0"]) self.start_node(2, ["-walletbroadcast=0"]) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) self.sync_all([self.nodes[0:3]]) tx_id_not_broadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) tx_obj_not_broadcasted = self.nodes[0].gettransaction(tx_id_not_broadcasted) self.nodes[1].generate(1) #mine a block, tx should not be in there self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[2].getbalance(), node_2_bal) #should not be changed because tx was not broadcasted #now broadcast from another node, mine a block, sync, and check the balance self.nodes[1].sendrawtransaction(tx_obj_not_broadcasted['hex']) self.nodes[1].generate(1) self.sync_all([self.nodes[0:3]]) node_2_bal += 2 self.nodes[0].gettransaction(tx_id_not_broadcasted) assert_equal(self.nodes[2].getbalance(), node_2_bal) #create another tx self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) #restart the nodes with -walletbroadcast=1 self.stop_nodes() self.start_node(0) self.start_node(1) self.start_node(2) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) sync_blocks(self.nodes[0:3]) self.nodes[0].generate(1) sync_blocks(self.nodes[0:3]) node_2_bal += 2 #tx should be added to balance because after restarting the nodes tx should be broadcasted assert_equal(self.nodes[2].getbalance(), node_2_bal) #send a tx with value in a string (PR#6380 +) tx_id = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2") tx_obj = self.nodes[0].gettransaction(tx_id) assert_equal(tx_obj['amount'], Decimal('-2')) tx_id = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001") tx_obj = self.nodes[0].gettransaction(tx_id) assert_equal(tx_obj['amount'], Decimal('-0.0001')) #check if JSON parser can handle scientific notation in strings tx_id = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1e-4") tx_obj = self.nodes[0].gettransaction(tx_id) assert_equal(tx_obj['amount'], Decimal('-0.0001')) # This will raise an exception because the amount type is wrong assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4") # This will raise an exception since generate does not accept a string assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2") # Import address and private key to check correct behavior of spendable unspents # 1. Send some coins to generate new UTXO address_to_import = self.nodes[2].getnewaddress() self.nodes[0].sendtoaddress(address_to_import, 1) self.nodes[0].generate(1) self.sync_all([self.nodes[0:3]]) # 2. Import address from node2 to node1 self.nodes[1].importaddress(address_to_import) # 3. Validate that the imported address is watch-only on node1 assert(self.nodes[1].validateaddress(address_to_import)["iswatchonly"]) # 4. Check that the unspents after import are not spendable assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": False}) # 5. Import private key of the previously imported address on node1 priv_key = self.nodes[2].dumpprivkey(address_to_import) self.nodes[1].importprivkey(priv_key) # 6. Check that the unspents are now spendable on node1 assert_array_result(self.nodes[1].listunspent(), {"address": address_to_import}, {"spendable": True}) # Mine a block from node0 to an address from node1 cb_address = self.nodes[1].getnewaddress() block_hash = self.nodes[0].generatetoaddress(1, cb_address)[0] cb_tx_id = self.nodes[0].getblock(block_hash)['tx'][0] self.sync_all([self.nodes[0:3]]) # Check that the txid and balance is found by node1 self.nodes[1].gettransaction(cb_tx_id) # check if wallet or blockchain maintenance changes the balance self.sync_all([self.nodes[0:3]]) blocks = self.nodes[0].generate(2) self.sync_all([self.nodes[0:3]]) balance_nodes = [self.nodes[i].getbalance() for i in range(3)] self.nodes[0].getblockcount() # Check modes: # - True: unicode escaped as \u.... # - False: unicode directly as UTF-8 for mode in [True, False]: self.nodes[0].ensure_ascii = mode # unicode check: Basic Multilingual Plane, Supplementary Plane respectively for s in [u'ббаБаА', u'№ Ё']: addr = self.nodes[0].getaccountaddress(s) label = self.nodes[0].getaccount(addr) assert_equal(label, s) assert(s in self.nodes[0].listaccounts().keys()) self.nodes[0].ensure_ascii = True # restore to default # maintenance tests maintenance = "-rescan -reindex -zapwallettxes=1 -zapwallettxes=2" chain_limit = 6 self.log.info("check " + maintenance) self.stop_nodes() # set lower ancestor limit for later self.start_node(0, [maintenance, "-limitancestorcount="+str(chain_limit)]) self.start_node(1, [maintenance, "-limitancestorcount="+str(chain_limit)]) self.start_node(2, [maintenance, "-limitancestorcount="+str(chain_limit)]) assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) # Exercise listsinceblock with the last two blocks coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) assert_equal(coinbase_tx_1["lastblock"], blocks[1]) assert_equal(len(coinbase_tx_1["transactions"]), 1) assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0) # Check that wallet prefers to use coins that don't exceed mempool limits ===== # Get all non-zero utxos together chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()] single_tx_id = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True) self.nodes[0].generate(1) node0_balance = self.nodes[0].getbalance() # Split into two chains rawtx = self.nodes[0].createrawtransaction([{"txid":single_tx_id, "vout":0}], {chain_addrs[0]:node0_balance/2-Decimal('0.01'), chain_addrs[1]:node0_balance/2-Decimal('0.01')}) signedtx = self.nodes[0].signrawtransaction(rawtx) self.nodes[0].sendrawtransaction(signedtx["hex"]) self.nodes[0].generate(1) # Make a long chain of unconfirmed payments without hitting mempool limit # Each tx we make leaves only one output of change on a chain 1 longer # Since the amount to send is always much less than the outputs, we only ever need one output # So we should be able to generate exactly chainlimit txs for each original output sending_addr = self.nodes[1].getnewaddress() txid_list = [] for _ in range(chain_limit*2): txid_list.append(self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))) assert_equal(self.nodes[0].getmempoolinfo()['size'], chain_limit*2) assert_equal(len(txid_list), chain_limit*2) # Without walletrejectlongchains, we will still generate a txid # The tx will be stored in the wallet but not accepted to the mempool assert_raises_rpc_error(-4, "Error: The transaction was rejected! Reason given: too-long-mempool-chain", self.nodes[0].sendtoaddress, sending_addr, Decimal('0.0001')) # Get the last transaction and verify it is not in the mempool trans_count = len(self.nodes[0].listtransactions("*",99999)) extra_txid = (self.nodes[0].listtransactions("*",1, trans_count-1))[0]['txid'] assert(extra_txid not in self.nodes[0].getrawmempool()) total_txs = len(self.nodes[0].listtransactions("*",99999)) # Try with walletrejectlongchains # Double chain limit but require combining inputs, so we pass SelectCoinsMinConf self.stop_node(0) self.start_node(0, extra_args=["-walletrejectlongchains", "-limitancestorcount="+str(2*chain_limit)]) # wait for loadmempool timeout = 10 while timeout > 0 and len(self.nodes[0].getrawmempool()) < chain_limit*2: time.sleep(0.5) timeout -= 0.5 assert_equal(len(self.nodes[0].getrawmempool()), chain_limit*2) node0_balance = self.nodes[0].getbalance() # With walletrejectlongchains we will not create the tx and store it in our wallet. assert_raises_rpc_error(-4, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01')) # Verify nothing new in wallet assert_equal(total_txs, len(self.nodes[0].listtransactions("*",99999)))
def run_rbf_opt_in_test(self): # Check whether a transaction signals opt-in RBF itself def is_opt_in(node, txid): rawtx = node.getrawtransaction(txid, 1) for x in rawtx["vin"]: if x["sequence"] < 0xfffffffe: return True return False # Find an unconfirmed output matching a certain txid def get_unconfirmed_utxo_entry(node, txid_to_match): utxo = node.listunspent(0, 0) for i in utxo: if i["txid"] == txid_to_match: return i return None # 1. Chain a few transactions that don't opt-in. txid_1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) assert not is_opt_in(self.nodes[0], txid_1) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_1}, {"bip125-replaceable": "no"}) sync_mempools(self.nodes) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_1}, {"bip125-replaceable": "no"}) # Tx2 will build off txid_1, still not opting in to RBF. utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[0], txid_1) assert_equal(utxo_to_use["safe"], True) utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1) utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1) assert_equal(utxo_to_use["safe"], False) # Create tx2 using createrawtransaction inputs = [{"txid": utxo_to_use["txid"], "vout": utxo_to_use["vout"]}] outputs = {self.nodes[0].getnewaddress(): 0.999} tx2 = self.nodes[1].createrawtransaction(inputs, outputs) tx2_signed = self.nodes[1].signrawtransactionwithwallet(tx2)["hex"] txid_2 = self.nodes[1].sendrawtransaction(tx2_signed) # ...and check the result assert not is_opt_in(self.nodes[1], txid_2) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_2}, {"bip125-replaceable": "no"}) sync_mempools(self.nodes) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_2}, {"bip125-replaceable": "no"}) # Tx3 will opt-in to RBF utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[0], txid_2) inputs = [{"txid": txid_2, "vout": utxo_to_use["vout"]}] outputs = {self.nodes[1].getnewaddress(): 0.998} tx3 = self.nodes[0].createrawtransaction(inputs, outputs) tx3_modified = tx_from_hex(tx3) tx3_modified.vin[0].nSequence = 0 tx3 = tx3_modified.serialize().hex() tx3_signed = self.nodes[0].signrawtransactionwithwallet(tx3)['hex'] txid_3 = self.nodes[0].sendrawtransaction(tx3_signed) assert is_opt_in(self.nodes[0], txid_3) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_3}, {"bip125-replaceable": "yes"}) sync_mempools(self.nodes) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_3}, {"bip125-replaceable": "yes"}) # Tx4 will chain off tx3. Doesn't signal itself, but depends on one # that does. utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_3) inputs = [{"txid": txid_3, "vout": utxo_to_use["vout"]}] outputs = {self.nodes[0].getnewaddress(): 0.997} tx4 = self.nodes[1].createrawtransaction(inputs, outputs) tx4_signed = self.nodes[1].signrawtransactionwithwallet(tx4)["hex"] txid_4 = self.nodes[1].sendrawtransaction(tx4_signed) assert not is_opt_in(self.nodes[1], txid_4) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "yes"}) sync_mempools(self.nodes) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "yes"}) # Replace tx3, and check that tx4 becomes unknown tx3_b = tx3_modified tx3_b.vout[0].nValue -= int(Decimal("0.004") * COIN) # bump the fee tx3_b = tx3_b.serialize().hex() tx3_b_signed = self.nodes[0].signrawtransactionwithwallet(tx3_b)['hex'] txid_3b = self.nodes[0].sendrawtransaction(tx3_b_signed, True) assert is_opt_in(self.nodes[0], txid_3b) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "unknown"}) sync_mempools(self.nodes) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "unknown"}) # Check gettransaction as well: for n in self.nodes[0:2]: assert_equal(n.gettransaction(txid_1)["bip125-replaceable"], "no") assert_equal(n.gettransaction(txid_2)["bip125-replaceable"], "no") assert_equal(n.gettransaction(txid_3)["bip125-replaceable"], "yes") assert_equal(n.gettransaction(txid_3b)["bip125-replaceable"], "yes") assert_equal(n.gettransaction(txid_4)["bip125-replaceable"], "unknown") # After mining a transaction, it's no longer BIP125-replaceable self.nodes[0].generate(1) assert txid_3b not in self.nodes[0].getrawmempool() assert_equal(self.nodes[0].gettransaction(txid_3b)["bip125-replaceable"], "no") assert_equal(self.nodes[0].gettransaction(txid_4)["bip125-replaceable"], "unknown")
def run_test(self): self.nodes[0].generate(1) # Get out of IBD self.sync_all() # Simple send, 0 to 1: txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "amount": Decimal("-0.1"), "confirmations": 0 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "amount": Decimal("0.1"), "confirmations": 0 }) # mine a block, confirmations should change: blockhash = self.nodes[0].generate(1)[0] blockheight = self.nodes[0].getblockheader(blockhash)['height'] self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "amount": Decimal("-0.1"), "confirmations": 1, "blockhash": blockhash, "blockheight": blockheight }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "amount": Decimal("0.1"), "confirmations": 1, "blockhash": blockhash, "blockheight": blockheight }) # send-to-self: txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.2) assert_array_result(self.nodes[0].listtransactions(), { "txid": txid, "category": "send" }, {"amount": Decimal("-0.2")}) assert_array_result(self.nodes[0].listtransactions(), { "txid": txid, "category": "receive" }, {"amount": Decimal("0.2")}) # sendmany from node1: twice to self, twice to node2: send_to = { self.nodes[0].getnewaddress(): 0.11, self.nodes[1].getnewaddress(): 0.22, self.nodes[0].getnewaddress(): 0.33, self.nodes[1].getnewaddress(): 0.44 } txid = self.nodes[1].sendmany("", send_to) self.sync_all() assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.11") }, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), { "category": "receive", "amount": Decimal("0.11") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.22") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "receive", "amount": Decimal("0.22") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.33") }, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), { "category": "receive", "amount": Decimal("0.33") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.44") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "receive", "amount": Decimal("0.44") }, {"txid": txid}) if not self.options.descriptors: # include_watchonly is a legacy wallet feature, so don't test it for descriptor wallets pubkey = self.nodes[1].getaddressinfo( self.nodes[1].getnewaddress())['pubkey'] multisig = self.nodes[1].createmultisig(1, [pubkey]) self.nodes[0].importaddress(multisig["redeemScript"], "watchonly", False, True) txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1) self.nodes[1].generate(1) self.sync_all() assert_equal( len(self.nodes[0].listtransactions(label="watchonly", include_watchonly=True)), 1) assert_equal( len(self.nodes[0].listtransactions(dummy="watchonly", include_watchonly=True)), 1) assert len(self.nodes[0].listtransactions( label="watchonly", count=100, include_watchonly=False)) == 0 assert_array_result( self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=True), { "category": "receive", "amount": Decimal("0.1") }, { "txid": txid, "label": "watchonly" }) self.run_rbf_opt_in_test()
def run_test(self): # Generate block to get out of IBD self.nodes[0].generate(1) sync_blocks(self.nodes) self.log.info("listreceivedbyaddress Test") # Send from node 0 to 1 addr = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # Check not listed in listreceivedbyaddress because has 0 confirmations assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": addr}, {}, True) # Bury Tx under 10 block so it will be returned by listreceivedbyaddress self.nodes[1].generate(10) self.sync_all() assert_array_result(self.nodes[1].listreceivedbyaddress(), {"address": addr}, {"address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]}) # With min confidence < 10 assert_array_result(self.nodes[1].listreceivedbyaddress(5), {"address": addr}, {"address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]}) # With min confidence > 10, should not find Tx assert_array_result(self.nodes[1].listreceivedbyaddress(11), {"address": addr}, {}, True) # Empty Tx empty_addr = self.nodes[1].getnewaddress() assert_array_result(self.nodes[1].listreceivedbyaddress(0, True), {"address": empty_addr}, {"address": empty_addr, "label": "", "amount": 0, "confirmations": 0, "txids": []}) # Test Address filtering # Only on addr expected = {"address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]} res = self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True, address_filter=addr) assert_array_result(res, {"address": addr}, expected) assert_equal(len(res), 1) # Test for regression on CLI calls with address string (#14173) cli_res = self.nodes[1].cli.listreceivedbyaddress(0, True, True, addr) assert_array_result(cli_res, {"address": addr}, expected) assert_equal(len(cli_res), 1) # Error on invalid address assert_raises_rpc_error(-4, "address_filter parameter was invalid", self.nodes[1].listreceivedbyaddress, minconf=0, include_empty=True, include_watchonly=True, address_filter="bamboozling") # Another address receive money res = self.nodes[1].listreceivedbyaddress(0, True, True) assert_equal(len(res), 2 + self.num_cb_reward_addresses) # Right now 2 entries other_addr = self.nodes[1].getnewaddress() txid2 = self.nodes[0].sendtoaddress(other_addr, 0.1) self.nodes[0].generate(1) self.sync_all() # Same test as above should still pass expected = {"address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 11, "txids": [txid, ]} res = self.nodes[1].listreceivedbyaddress(0, True, True, addr) assert_array_result(res, {"address": addr}, expected) assert_equal(len(res), 1) # Same test as above but with other_addr should still pass expected = {"address": other_addr, "label": "", "amount": Decimal("0.1"), "confirmations": 1, "txids": [txid2, ]} res = self.nodes[1].listreceivedbyaddress(0, True, True, other_addr) assert_array_result(res, {"address": other_addr}, expected) assert_equal(len(res), 1) # Should be two entries though without filter res = self.nodes[1].listreceivedbyaddress(0, True, True) assert_equal(len(res), 3 + self.num_cb_reward_addresses) # Became 3 entries # Not on random addr other_addr = self.nodes[0].getnewaddress() # note on node[0]! just a random addr res = self.nodes[1].listreceivedbyaddress(0, True, True, other_addr) assert_equal(len(res), 0) self.log.info("getreceivedbyaddress Test") # Send from node 0 to 1 addr = self.nodes[1].getnewaddress() txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # Check balance is 0 because of 0 confirmations balance = self.nodes[1].getreceivedbyaddress(addr) assert_equal(balance, Decimal("0.0")) # Check balance is 0.1 balance = self.nodes[1].getreceivedbyaddress(addr, 0) assert_equal(balance, Decimal("0.1")) # Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress self.nodes[1].generate(10) self.sync_all() balance = self.nodes[1].getreceivedbyaddress(addr) assert_equal(balance, Decimal("0.1")) # Trying to getreceivedby for an address the wallet doesn't own should return an error assert_raises_rpc_error(-4, "Address not found in wallet", self.nodes[0].getreceivedbyaddress, addr) self.log.info("listreceivedbylabel + getreceivedbylabel Test") # set pre-state label = '' address = self.nodes[1].getnewaddress() assert_equal(self.nodes[1].getaddressinfo(address)['label'], label) received_by_label_json = [r for r in self.nodes[1].listreceivedbylabel() if r["label"] == label][0] balance_by_label = self.nodes[1].getreceivedbylabel(label) txid = self.nodes[0].sendtoaddress(addr, 0.1) self.sync_all() # listreceivedbylabel should return received_by_label_json because of 0 confirmations assert_array_result(self.nodes[1].listreceivedbylabel(), {"label": label}, received_by_label_json) # getreceivedbyaddress should return same balance because of 0 confirmations balance = self.nodes[1].getreceivedbylabel(label) assert_equal(balance, balance_by_label) self.nodes[1].generate(10) self.sync_all() # listreceivedbylabel should return updated received list assert_array_result(self.nodes[1].listreceivedbylabel(), {"label": label}, {"label": received_by_label_json["label"], "amount": (received_by_label_json["amount"] + Decimal("0.1"))}) # getreceivedbylabel should return updated receive total balance = self.nodes[1].getreceivedbylabel(label) assert_equal(balance, balance_by_label + Decimal("0.1")) # Create a new label named "mynewlabel" that has a 0 balance address = self.nodes[1].getnewaddress() self.nodes[1].setlabel(address, "mynewlabel") received_by_label_json = [r for r in self.nodes[1].listreceivedbylabel(0, True) if r["label"] == "mynewlabel"][0] # Test includeempty of listreceivedbylabel assert_equal(received_by_label_json["amount"], Decimal("0.0")) # Test getreceivedbylabel for 0 amount labels balance = self.nodes[1].getreceivedbylabel("mynewlabel") assert_equal(balance, Decimal("0.0"))
def run_rbf_opt_in_test(self): """Test the opt-in-rbf flag for sent and received transactions.""" def is_opt_in(node, txid): """Check whether a transaction signals opt-in RBF itself.""" rawtx = node.getrawtransaction(txid, 1) for x in rawtx["vin"]: if x["sequence"] < 0xfffffffe: return True return False def get_unconfirmed_utxo_entry(node, txid_to_match): """Find an unconfirmed output matching a certain txid.""" utxo = node.listunspent(0, 0) for i in utxo: if i["txid"] == txid_to_match: return i return None self.log.info("Test txs w/o opt-in RBF (bip125-replaceable=no)") # Chain a few transactions that don't opt in. txid_1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) assert not is_opt_in(self.nodes[0], txid_1) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_1}, {"bip125-replaceable": "no"}) self.sync_mempools() assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_1}, {"bip125-replaceable": "no"}) # Tx2 will build off tx1, still not opting in to RBF. utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[0], txid_1) assert_equal(utxo_to_use["safe"], True) utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1) assert_equal(utxo_to_use["safe"], False) # Create tx2 using createrawtransaction inputs = [{"txid": utxo_to_use["txid"], "vout": utxo_to_use["vout"]}] outputs = {self.nodes[0].getnewaddress(): 0.999} tx2 = self.nodes[1].createrawtransaction(inputs, outputs) tx2_signed = self.nodes[1].signrawtransactionwithwallet(tx2)["hex"] txid_2 = self.nodes[1].sendrawtransaction(tx2_signed) # ...and check the result assert not is_opt_in(self.nodes[1], txid_2) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_2}, {"bip125-replaceable": "no"}) self.sync_mempools() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_2}, {"bip125-replaceable": "no"}) self.log.info("Test txs with opt-in RBF (bip125-replaceable=yes)") # Tx3 will opt-in to RBF utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[0], txid_2) inputs = [{"txid": txid_2, "vout": utxo_to_use["vout"]}] outputs = {self.nodes[1].getnewaddress(): 0.998} tx3 = self.nodes[0].createrawtransaction(inputs, outputs) tx3_modified = tx_from_hex(tx3) tx3_modified.vin[0].nSequence = 0 tx3 = tx3_modified.serialize().hex() tx3_signed = self.nodes[0].signrawtransactionwithwallet(tx3)['hex'] txid_3 = self.nodes[0].sendrawtransaction(tx3_signed) assert is_opt_in(self.nodes[0], txid_3) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_3}, {"bip125-replaceable": "yes"}) self.sync_mempools() assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_3}, {"bip125-replaceable": "yes"}) # Tx4 will chain off tx3. Doesn't signal itself, but depends on one # that does. utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_3) inputs = [{"txid": txid_3, "vout": utxo_to_use["vout"]}] outputs = {self.nodes[0].getnewaddress(): 0.997} tx4 = self.nodes[1].createrawtransaction(inputs, outputs) tx4_signed = self.nodes[1].signrawtransactionwithwallet(tx4)["hex"] txid_4 = self.nodes[1].sendrawtransaction(tx4_signed) assert not is_opt_in(self.nodes[1], txid_4) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "yes"}) self.sync_mempools() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "yes"}) self.log.info( "Test tx with unknown RBF state (bip125-replaceable=unknown)") # Replace tx3, and check that tx4 becomes unknown tx3_b = tx3_modified tx3_b.vout[0].nValue -= int(Decimal("0.004") * COIN) # bump the fee tx3_b = tx3_b.serialize().hex() tx3_b_signed = self.nodes[0].signrawtransactionwithwallet(tx3_b)['hex'] txid_3b = self.nodes[0].sendrawtransaction(tx3_b_signed, 0) assert is_opt_in(self.nodes[0], txid_3b) assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "unknown"}) self.sync_mempools() assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "unknown"}) self.log.info("Test bip125-replaceable status with gettransaction RPC") for n in self.nodes[0:2]: assert_equal(n.gettransaction(txid_1)["bip125-replaceable"], "no") assert_equal(n.gettransaction(txid_2)["bip125-replaceable"], "no") assert_equal(n.gettransaction(txid_3)["bip125-replaceable"], "yes") assert_equal( n.gettransaction(txid_3b)["bip125-replaceable"], "yes") assert_equal( n.gettransaction(txid_4)["bip125-replaceable"], "unknown") self.log.info("Test bip125-replaceable status with listsinceblock") for n in self.nodes[0:2]: txs = { tx['txid']: tx['bip125-replaceable'] for tx in n.listsinceblock()['transactions'] } assert_equal(txs[txid_1], "no") assert_equal(txs[txid_2], "no") assert_equal(txs[txid_3], "yes") assert_equal(txs[txid_3b], "yes") assert_equal(txs[txid_4], "unknown") self.log.info( "Test mined transactions are no longer bip125-replaceable") self.generate(self.nodes[0], 1, sync_fun=self.no_op) assert txid_3b not in self.nodes[0].getrawmempool() assert_equal( self.nodes[0].gettransaction(txid_3b)["bip125-replaceable"], "no") assert_equal( self.nodes[0].gettransaction(txid_4)["bip125-replaceable"], "unknown")
def run_test(self): self.log.info("Test simple send from node0 to node1") txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "amount": Decimal("-0.1"), "confirmations": 0, "trusted": True }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "amount": Decimal("0.1"), "confirmations": 0, "trusted": False }) self.log.info("Test confirmations change after mining a block") blockhash = self.generate(self.nodes[0], 1)[0] blockheight = self.nodes[0].getblockheader(blockhash)['height'] assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "amount": Decimal("-0.1"), "confirmations": 1, "blockhash": blockhash, "blockheight": blockheight }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "amount": Decimal("0.1"), "confirmations": 1, "blockhash": blockhash, "blockheight": blockheight }) self.log.info("Test send-to-self on node0") txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.2) assert_array_result(self.nodes[0].listtransactions(), { "txid": txid, "category": "send" }, {"amount": Decimal("-0.2")}) assert_array_result(self.nodes[0].listtransactions(), { "txid": txid, "category": "receive" }, {"amount": Decimal("0.2")}) self.log.info( "Test sendmany from node1: twice to self, twice to node0") send_to = { self.nodes[0].getnewaddress(): 0.11, self.nodes[1].getnewaddress(): 0.22, self.nodes[0].getnewaddress(): 0.33, self.nodes[1].getnewaddress(): 0.44 } txid = self.nodes[1].sendmany("", send_to) self.sync_all() assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.11") }, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), { "category": "receive", "amount": Decimal("0.11") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.22") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "receive", "amount": Decimal("0.22") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.33") }, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), { "category": "receive", "amount": Decimal("0.33") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.44") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "receive", "amount": Decimal("0.44") }, {"txid": txid}) if not self.options.descriptors: # include_watchonly is a legacy wallet feature, so don't test it for descriptor wallets self.log.info("Test 'include_watchonly' feature (legacy wallet)") pubkey = self.nodes[1].getaddressinfo( self.nodes[1].getnewaddress())['pubkey'] # SYSCOIN multisig = self.nodes[1].createmultisig(1, [pubkey], 'legacy') self.nodes[0].importaddress(multisig["redeemScript"], "watchonly", False, True) txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1) self.generate(self.nodes[1], 1) assert_equal( len(self.nodes[0].listtransactions(label="watchonly", include_watchonly=True)), 1) assert_equal( len(self.nodes[0].listtransactions(dummy="watchonly", include_watchonly=True)), 1) assert len(self.nodes[0].listtransactions( label="watchonly", count=100, include_watchonly=False)) == 0 assert_array_result( self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=True), { "category": "receive", "amount": Decimal("0.1") }, { "txid": txid, "label": "watchonly" }) self.run_rbf_opt_in_test()
def run_test(self): addr0 = self.nodes[0].getnewaddress("") addr1 = self.nodes[0].getnewaddress("") addr2 = self.nodes[0].getnewaddress("") ''' generate some test coin ''' self.nodes[0].generatetoaddress(101, addr0) # burn 3 BCH self.nodes[0].whc_burnbchgetwhc(6) self.nodes[0].generatetoaddress(1, addr0) self.nodes[0].sendtoaddress(addr1, 3) self.nodes[0].sendtoaddress(addr2, 3) self.nodes[0].generatetoaddress(1, addr0) self.nodes[0].whc_send(addr0, addr1, 1, "300") self.nodes[0].whc_send(addr0, addr2, 1, "300") self.nodes[0].generatetoaddress(1, addr0) # check initial value assert_array_result(self.nodes[0].whc_getallbalancesforaddress(addr1), {"propertyid": 1}, { "balance": "300.00000000", "reserved": "0.00000000" }) deadline = int(time.mktime( datetime.datetime.now().timetuple())) + 86400 tx = self.nodes[0].whc_sendissuancecrowdsale( addr1, 1, 3, 0, "reg crowdsale test", "crowdsale test", "reqcrowd", "http://www.google.ca", "crowdsale test data", 1, "100000000", deadline, 10, 0, "10000000000") self.nodes[0].generatetoaddress(1, addr1) # check valid transaction ret = self.nodes[0].whc_gettransaction(tx) assert ret["valid"] is True assert_array_result(self.nodes[0].whc_getallbalancesforaddress(addr1), {"propertyid": 1}, { "balance": "299.00000000", "reserved": "0.00000000" }) ret = self.nodes[0].whc_gettransaction(tx) ppid = ret["propertyid"] # check data ret = self.nodes[0].whc_getcrowdsale(ppid) assert ret["issuer"] == addr1 and \ ret["tokensperunit"] == "100000000.00000000"\ and ret["earlybonus"] == 10 and\ ret["tokensissued"] == "10000000000.000" # test participate crowdsale assert_array_result(self.nodes[0].whc_getallbalancesforaddress(addr1), {"propertyid": 1}, { "balance": "299.00000000", "reserved": "0.00000000" }) assert_array_result(self.nodes[0].whc_getallbalancesforaddress(addr2), {"propertyid": 1}, { "balance": "300.00000000", "reserved": "0.00000000" }) tx = self.nodes[0].whc_particrowsale(addr2, addr1, "31.12") self.nodes[0].generatetoaddress(1, addr1) assert_array_result(self.nodes[0].whc_getallbalancesforaddress(addr1), {"propertyid": 1}, { "balance": "330.12000000", "reserved": "0.00000000" }) assert_array_result(self.nodes[0].whc_getallbalancesforaddress(addr2), {"propertyid": 1}, { "balance": "268.88000000", "reserved": "0.00000000" })