Skip to content

Commit

Permalink
[QA][Bug] Shorter wallet_basic.py functional test
Browse files Browse the repository at this point in the history
  • Loading branch information
random-zebra committed Apr 28, 2020
1 parent 7fb724f commit df9fc17
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 111 deletions.
4 changes: 2 additions & 2 deletions test/functional/test_framework/util.py
Expand Up @@ -28,10 +28,10 @@ def assert_fee_amount(fee, tx_size, fee_per_kB):
"""Assert the fee was in range"""
target_fee = round(tx_size * fee_per_kB / 1000, 8)
if fee < target_fee:
raise AssertionError("Fee of %s BTC too low! (Should be %s BTC)" % (str(fee), str(target_fee)))
raise AssertionError("Fee of %s PIV too low! (Should be %s PIV)" % (str(fee), str(target_fee)))
# allow the wallet's estimation to be at most 2 bytes off
if fee > (tx_size + 20) * fee_per_kB / 1000:
raise AssertionError("Fee of %s BTC too high! (Should be %s BTC)" % (str(fee), str(target_fee)))
raise AssertionError("Fee of %s PIV too high! (Should be %s PIV)" % (str(fee), str(target_fee)))

def assert_equal(thing1, thing2, *args):
if thing1 != thing2 or any(thing1 != arg for arg in args):
Expand Down
4 changes: 2 additions & 2 deletions test/functional/test_runner.py
Expand Up @@ -56,10 +56,11 @@
# Scripts that are run by the travis build process.

# Longest test should go first, to favor running tests in parallel
'wallet_basic.py', # ~ 833 sec
'wallet_basic.py', # ~ 498 sec
'wallet_backup.py', # ~ 477 sec

# vv Tests less than 5m vv
'wallet_zapwallettxes.py', # ~ 300 sec
'p2p_time_offset.py', # ~ 267 sec
'mining_pos_coldStaking.py', # ~ 215 sec
'mining_pos_reorg.py', # ~ 212 sec
Expand All @@ -68,7 +69,6 @@
'wallet_zerocoin_publicspends.py', # ~ 202 sec
'feature_logging.py', # ~ 200 sec
'rpc_rawtransaction.py', # ~ 193 sec
'wallet_zapwallettxes.py', # ~ 180 sec
'wallet_keypool_topup.py', # ~ 174 sec
'wallet_txn_doublespend.py --mineblock', # ~ 157 sec
'wallet_txn_clone.py --mineblock', # ~ 157 sec
Expand Down
126 changes: 28 additions & 98 deletions test/functional/wallet_basic.py
Expand Up @@ -11,8 +11,6 @@
assert_raises_rpc_error,
connect_nodes,
Decimal,
sync_blocks,
sync_mempools,
wait_until,
)

Expand All @@ -31,14 +29,6 @@ def setup_network(self):
connect_nodes(self.nodes[0], 2)
self.sync_all([self.nodes[0:3]])

def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size):
"""Return curr_balance after asserting the fee was in range"""
fee = balance_with_fee - curr_balance
fee2 = round(tx_size * fee_per_byte / 1000, 8)
self.log.info("current: %s, withfee: %s, perByte: %s, size: %s, fee: %s" % (str(curr_balance), str(balance_with_fee), str(fee_per_byte), str(tx_size), str(fee2)))
assert_fee_amount(fee, tx_size, fee_per_byte * 1000)
return curr_balance

def get_vsize(self, txn):
return self.nodes[0].decoderawtransaction(txn)['size']

Expand Down Expand Up @@ -70,49 +60,37 @@ def run_test(self):
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 = self.nodes[1].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.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 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
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("from1")] = float(utxo["amount"])
outputs[self.nodes[2].getnewaddress("from1")] = 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))

Expand All @@ -125,85 +103,41 @@ def run_test(self):
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)
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)
assert_equal(self.nodes[2].getbalance("from1"), node_2_expected_bal)

# 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))
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_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'))
assert_equal(node_0_bal, Decimal('10'))

# Sendmany 10 PIV
txid = self.nodes[2].sendmany('from1', {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')
#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)))
node_2_bal -= (Decimal('10') - fee)
assert_equal(self.nodes[2].getbalance(), node_2_bal)
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'])
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()
txid = self.nodes[0].sendtoaddress(address_to_import, 1)
self.nodes[0].sendtoaddress(address_to_import, 1)
self.nodes[0].generate(1)
self.sync_all([self.nodes[0:3]])

Expand Down Expand Up @@ -238,18 +172,14 @@ def run_test(self):
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)])
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)])
Expand Down
30 changes: 21 additions & 9 deletions test/functional/wallet_zapwallettxes.py
Expand Up @@ -18,7 +18,7 @@
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
wait_until,
sync_mempools,
)

class ZapWalletTXesTest (PivxTestFramework):
Expand All @@ -40,31 +40,43 @@ def run_test(self):
self.sync_all()
self.nodes[0].generate(1)
self.sync_all()
balance_nodes = [self.nodes[i].getbalance() for i in range(self.num_nodes)]

# This transaction will not be confirmed
txid2 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 20)
sync_mempools(self.nodes, wait=.1)

# Confirmed and unconfirmed transactions are now in the wallet.
assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1)
assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2)

# Exercise balance rpcs
assert_equal(self.nodes[1].getwalletinfo()["unconfirmed_balance"], 20)
assert_equal(self.nodes[1].getunconfirmedbalance(), 20)

# Stop-start node0. Both confirmed and unconfirmed transactions remain in the wallet.
self.stop_node(0)
self.start_node(0)

assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1)
assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2)

# Stop node0 and restart with zapwallettxes and persistmempool. The unconfirmed
# Stop nodes and restart with zapwallettxes and persistmempool. The unconfirmed
# transaction is zapped from the wallet, but is re-added when the mempool is reloaded.
self.stop_node(0)
self.start_node(0, ["-zapwallettxes=2"])
# original balances are restored
for i in range(1, 3):
self.log.info("Restarting with --zapwallettxes=%d" % i)
self.stop_nodes()
self.start_node(0, ["-zapwallettxes=%d" % i])
self.start_node(1, ["-zapwallettxes=%d" % i])

# tx1 is still be available because it was confirmed
assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1)
# tx1 is still be available because it was confirmed
assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1)

# This will raise an exception because the unconfirmed transaction has been zapped
assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', self.nodes[0].gettransaction, txid2)

# This will raise an exception because the unconfirmed transaction has been zapped
assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', self.nodes[0].gettransaction, txid2)
# Check (confirmed) balances
assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(self.num_nodes)])

if __name__ == '__main__':
ZapWalletTXesTest().main()

0 comments on commit df9fc17

Please sign in to comment.