mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32:48 +01:00
b07a7b810c
* Merge #11796: [tests] Functional test naming convention5fecd84
[tests] Remove redundant import in blocktools.py test (Anthony Towns)9b20bb4
[tests] Check tests conform to naming convention (Anthony Towns)7250b4e
[tests] README.md nit fixes (Anthony Towns)82b2712
[tests] move witness util functions to blocktools.py (John Newbery)1e10854
[tests] [docs] update README for new test naming scheme (John Newbery) Pull request description: Splitting #11774 into two parts -- this part updates the README with the proposed naming convention, and adds some checks to test_runner.py that the number of tests violating the naming convention doesn't increase too much. Idea is this part of the change should not introduce merge conflicts or require much rebasing, so reviews of the complicated bits won't become invalidated too often; while the second part will just be file renames, which will require regular rebasing and will introduce merge conflicts with pending PRs, but can be merged later, and should also be much easier to review, since it will only include relatively trivial changes. Tree-SHA512: b96557d41714addbbfe2aed62fb5a48639eaeb1eb3aba30ac1b3a86bb3cb8d796c6247f9c414c4695c4bf54c0ec9968ac88e2f88fb62483bc1a2f89368f7fc80 * update violation count Signed-off-by: pasta <pasta@dashboost.org> * Merge #11774: [tests] Rename functional tests6f881cc880
[tests] Remove EXPECTED_VIOLATION_COUNT (Anthony Towns)3150b3fea7
[tests] Rename misc functional tests. (Anthony Towns)81b79f2c39
[tests] Rename rpc_* functional tests. (Anthony Towns)61b8f7f273
[tests] Rename p2p_* functional tests. (Anthony Towns)90600bc7db
[tests] Rename wallet_* functional tests. (Anthony Towns)ca6523d0c8
[tests] Rename feature_* functional tests. (Anthony Towns) Pull request description: This PR changes the functional tests to have a consistent naming scheme: tests for individual RPC methods are named rpc_... tests for interfaces (REST, ZMQ, RPC features) are named interface_... tests that explicitly test the p2p interface are named p2p_... tests for wallet features are named wallet_... tests for mining features are named mining_... tests for mempool behaviour are named mempool_... tests for full features that aren't wallet/mining/mempool are named feature_... Rationale: it's sometimes difficult for new contributors to know what's already covered by existing tests and where new tests should be added. Naming in a consistent fashion makes it easier to see what's already covered at a glance. Tree-SHA512: 4246790552d42bbd95f6d5bdf67702b81b3b2c583ce7eaf1fe6d8e254721279b47315973c6e9ae82dad6e4c747f12188160764bf2624c0f8f3b4d39330ec8b16 * rename tests and edit associated strings to align test-suite with test name standards Signed-off-by: pasta <pasta@dashboost.org> * fix grammar in test/functional/test_runner.py Co-authored-by: dustinface <35775977+xdustinface@users.noreply.github.com> * ci: Fix excluded test names * rename feature_privatesend.py to rpc_privatesend.py Signed-off-by: pasta <pasta@dashboost.org> Co-authored-by: Wladimir J. van der Laan <laanwj@gmail.com> Co-authored-by: MarcoFalke <falke.marco@gmail.com> Co-authored-by: dustinface <35775977+xdustinface@users.noreply.github.com> Co-authored-by: xdustinface <xdustinfacex@gmail.com>
456 lines
22 KiB
Python
Executable File
456 lines
22 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
"""Test the wallet."""
|
|
import sys
|
|
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
from test_framework.util import *
|
|
|
|
class WalletTest(BitcoinTestFramework):
|
|
def set_test_params(self):
|
|
self.num_nodes = 4
|
|
self.setup_clean_chain = True
|
|
self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)]
|
|
|
|
def setup_network(self):
|
|
self.add_nodes(4, self.extra_args, stderr=sys.stdout)
|
|
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_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
|
|
assert_fee_amount(fee, tx_size, fee_per_byte * 1000)
|
|
return curr_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'], 500)
|
|
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(), 500)
|
|
assert_equal(self.nodes[1].getbalance(), 500)
|
|
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'], 500)
|
|
txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=True)
|
|
assert_equal(txout['value'], 500)
|
|
|
|
# Send 210 DASH 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(), 110)
|
|
mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 100)
|
|
|
|
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'], 500)
|
|
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([100, 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(), 200)
|
|
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].signrawtransaction(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 1000 DASH in block rewards plus fees, but
|
|
# minus the 210 plus fees sent to node2
|
|
assert_equal(self.nodes[0].getbalance(), 1000-210)
|
|
assert_equal(self.nodes[2].getbalance(), 210)
|
|
|
|
# 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)
|
|
|
|
fee_per_input = Decimal('0.00001')
|
|
totalfee = 0
|
|
# create both transactions
|
|
txns_to_send = []
|
|
for utxo in node0utxos:
|
|
inputs = []
|
|
outputs = {}
|
|
inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]})
|
|
outputs[self.nodes[2].getnewaddress("from1")] = utxo["amount"] - fee_per_input
|
|
raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
|
|
txns_to_send.append(self.nodes[0].signrawtransaction(raw_tx))
|
|
totalfee += fee_per_input
|
|
|
|
# Have node 1 (miner) send the transactions
|
|
self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"])
|
|
self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"])
|
|
|
|
# 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(), 1000 - totalfee)
|
|
assert_equal(self.nodes[2].getbalance("from1"), 1000 - 210 - totalfee)
|
|
|
|
# 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 100 DASH normal
|
|
address = self.nodes[0].getnewaddress("test")
|
|
fee_per_byte = Decimal('0.00001') / 1000
|
|
self.nodes[2].settxfee(fee_per_byte * 1000)
|
|
txid = self.nodes[2].sendtoaddress(address, 100, "", "", 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('900') - totalfee, fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid)))
|
|
assert_equal(self.nodes[0].getbalance(), Decimal('100'))
|
|
|
|
# Send 100 DASH with subtract fee from amount
|
|
txid = self.nodes[2].sendtoaddress(address, 100, "", "", True)
|
|
self.nodes[2].generate(1)
|
|
self.sync_all(self.nodes[0:3])
|
|
node_2_bal -= Decimal('100')
|
|
assert_equal(self.nodes[2].getbalance(), node_2_bal)
|
|
node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('200'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid)))
|
|
|
|
# Sendmany 100 DASH
|
|
txid = self.nodes[2].sendmany('from1', {address: 100}, 0, False, "", [])
|
|
self.nodes[2].generate(1)
|
|
self.sync_all(self.nodes[0:3])
|
|
node_0_bal += Decimal('100')
|
|
node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('100'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid)))
|
|
assert_equal(self.nodes[0].getbalance(), node_0_bal)
|
|
|
|
# Sendmany 100 DASH with subtract fee from amount
|
|
txid = self.nodes[2].sendmany('from1', {address: 100}, 0, False, "", [address])
|
|
self.nodes[2].generate(1)
|
|
self.sync_all(self.nodes[0:3])
|
|
node_2_bal -= Decimal('100')
|
|
assert_equal(self.nodes[2].getbalance(), node_2_bal)
|
|
node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('100'), 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)
|
|
self.sync_mempools(self.nodes[0:2])
|
|
|
|
self.start_node(3)
|
|
connect_nodes_bi(self.nodes, 0, 3)
|
|
self.sync_blocks()
|
|
|
|
relayed = self.nodes[0].resendwallettransactions()
|
|
assert_equal(set(relayed), {txid1, txid2})
|
|
self.sync_mempools()
|
|
|
|
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(query_options={'minimumAmount': '499.998'})[0]
|
|
inputs = [{"txid":usp['txid'], "vout":usp['vout']}]
|
|
outputs = {self.nodes[1].getnewaddress(): 499.998, self.nodes[0].getnewaddress(): 11.11}
|
|
|
|
rawTx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") #replace 11.11 with 0.0 (int32)
|
|
decRawTx = self.nodes[1].decoderawtransaction(rawTx)
|
|
signedRawTx = self.nodes[1].signrawtransaction(rawTx)
|
|
decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex'])
|
|
zeroValueTxid= decRawTx['txid']
|
|
self.nodes[1].sendrawtransaction(signedRawTx['hex'])
|
|
|
|
self.sync_all()
|
|
self.nodes[1].generate(1) #mine a block
|
|
self.sync_all()
|
|
|
|
unspentTxs = self.nodes[0].listunspent() #zero value tx must be in listunspents output
|
|
found = False
|
|
for uTx in unspentTxs:
|
|
if uTx['txid'] == zeroValueTxid:
|
|
found = True
|
|
assert_equal(uTx['amount'], Decimal('0'))
|
|
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])
|
|
|
|
txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2)
|
|
txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
|
|
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(txObjNotBroadcasted['hex'])
|
|
self.nodes[1].generate(1)
|
|
self.sync_all(self.nodes[0:3])
|
|
node_2_bal += 2
|
|
txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
|
|
assert_equal(self.nodes[2].getbalance(), node_2_bal)
|
|
|
|
#create another tx
|
|
txIdNotBroadcasted = 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")
|
|
txObj = self.nodes[0].gettransaction(txId)
|
|
assert_equal(txObj['amount'], Decimal('-2'))
|
|
|
|
txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001")
|
|
txObj = self.nodes[0].gettransaction(txId)
|
|
assert_equal(txObj['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")
|
|
txObj = self.nodes[0].gettransaction(txId)
|
|
assert_equal(txObj['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].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
|
|
cbAddr = self.nodes[1].getnewaddress()
|
|
blkHash = self.nodes[0].generatetoaddress(1, cbAddr)[0]
|
|
cbTxId = self.nodes[0].getblock(blkHash)['tx'][0]
|
|
self.sync_all(self.nodes[0:3])
|
|
|
|
# Check that the txid and balance is found by node1
|
|
self.nodes[1].gettransaction(cbTxId)
|
|
|
|
# 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].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',
|
|
# 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].signrawtransaction(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)))
|
|
|
|
if __name__ == '__main__':
|
|
WalletTest().main()
|