Repair some RPC tests.
Signed-off-by: Daira Emma Hopwood <daira@jacaranda.org>
This commit is contained in:
parent
3b255b8941
commit
eb74c8e8b0
|
@ -17,6 +17,7 @@ from test_framework.util import (
|
||||||
sync_mempools,
|
sync_mempools,
|
||||||
)
|
)
|
||||||
from test_framework.mininode import COIN
|
from test_framework.mininode import COIN
|
||||||
|
from test_framework.zip317 import conventional_fee
|
||||||
|
|
||||||
def satoshi_round(amount):
|
def satoshi_round(amount):
|
||||||
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
|
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
|
||||||
|
@ -61,7 +62,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
|
||||||
vout = utxo[0]['vout']
|
vout = utxo[0]['vout']
|
||||||
value = utxo[0]['amount']
|
value = utxo[0]['amount']
|
||||||
|
|
||||||
fee = Decimal("0.00005")
|
fee = conventional_fee(2)
|
||||||
# 100 transactions off a confirmed tx should be fine
|
# 100 transactions off a confirmed tx should be fine
|
||||||
chain = []
|
chain = []
|
||||||
for i in range(100):
|
for i in range(100):
|
||||||
|
|
|
@ -9,8 +9,9 @@
|
||||||
|
|
||||||
from test_framework.authproxy import JSONRPCException
|
from test_framework.authproxy import JSONRPCException
|
||||||
from test_framework.util import assert_equal, connect_nodes_bi, fail, \
|
from test_framework.util import assert_equal, connect_nodes_bi, fail, \
|
||||||
initialize_chain_clean, start_node, sync_blocks, sync_mempools, \
|
initialize_chain_clean, start_node, \
|
||||||
wait_and_assert_operationid_status, DEFAULT_FEE
|
wait_and_assert_operationid_status, DEFAULT_FEE
|
||||||
|
from test_framework.zip317 import conventional_fee
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
|
@ -28,14 +29,10 @@ def assert_mergetoaddress_exception(expected_error_msg, merge_to_address_lambda)
|
||||||
|
|
||||||
class MergeToAddressHelper:
|
class MergeToAddressHelper:
|
||||||
|
|
||||||
def __init__(self, addr_type, any_zaddr, utxos_to_generate, utxos_in_tx1, utxos_in_tx2):
|
def __init__(self, addr_type, any_zaddr):
|
||||||
self.addr_type = addr_type
|
self.addr_type = addr_type
|
||||||
self.any_zaddr = [any_zaddr]
|
self.any_zaddr = [any_zaddr]
|
||||||
self.any_zaddr_or_utxo = [any_zaddr, "ANY_TADDR"]
|
self.any_zaddr_or_utxo = [any_zaddr, "ANY_TADDR"]
|
||||||
# utxos_to_generate, utxos_in_tx1, utxos_in_tx2 have to do with testing transaction size limits
|
|
||||||
self.utxos_to_generate = utxos_to_generate
|
|
||||||
self.utxos_in_tx1 = utxos_in_tx1
|
|
||||||
self.utxos_in_tx2 = utxos_in_tx2
|
|
||||||
|
|
||||||
def setup_chain(self, test):
|
def setup_chain(self, test):
|
||||||
print("Initializing test directory "+test.options.tmpdir)
|
print("Initializing test directory "+test.options.tmpdir)
|
||||||
|
@ -45,7 +42,6 @@ class MergeToAddressHelper:
|
||||||
args = [
|
args = [
|
||||||
'-minrelaytxfee=0',
|
'-minrelaytxfee=0',
|
||||||
'-debug=zrpcunsafe',
|
'-debug=zrpcunsafe',
|
||||||
'-limitancestorcount=%d' % self.utxos_to_generate,
|
|
||||||
'-allowdeprecated=getnewaddress',
|
'-allowdeprecated=getnewaddress',
|
||||||
'-allowdeprecated=z_getnewaddress',
|
'-allowdeprecated=z_getnewaddress',
|
||||||
'-allowdeprecated=z_getbalance',
|
'-allowdeprecated=z_getbalance',
|
||||||
|
@ -230,6 +226,7 @@ class MergeToAddressHelper:
|
||||||
test.sync_all()
|
test.sync_all()
|
||||||
test.nodes[1].generate(1)
|
test.nodes[1].generate(1)
|
||||||
test.sync_all()
|
test.sync_all()
|
||||||
|
assert_equal(0, len(test.nodes[0].z_listunspent(0)))
|
||||||
|
|
||||||
assert_equal(test.nodes[0].getbalance(), 0)
|
assert_equal(test.nodes[0].getbalance(), 0)
|
||||||
assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), 0)
|
assert_equal(test.nodes[0].z_getbalance(do_not_shield_taddr), 0)
|
||||||
|
@ -239,57 +236,27 @@ class MergeToAddressHelper:
|
||||||
assert_equal(test.nodes[1].z_getbalance(n1taddr), Decimal('80.0') - DEFAULT_FEE)
|
assert_equal(test.nodes[1].z_getbalance(n1taddr), Decimal('80.0') - DEFAULT_FEE)
|
||||||
assert_equal(test.nodes[2].getbalance(), 0)
|
assert_equal(test.nodes[2].getbalance(), 0)
|
||||||
|
|
||||||
# Generate self.utxos_to_generate regular UTXOs on node 0, and 20 regular UTXOs on node 2
|
# Generate 5 regular UTXOs on node 0, and 20 regular UTXOs on node 2.
|
||||||
mytaddr = test.nodes[0].getnewaddress()
|
mytaddr = test.nodes[0].getnewaddress()
|
||||||
n2taddr = test.nodes[2].getnewaddress()
|
n2taddr = test.nodes[2].getnewaddress()
|
||||||
test.nodes[1].generate(1000)
|
test.nodes[1].generate(20)
|
||||||
test.sync_all()
|
test.sync_all()
|
||||||
for i in range(self.utxos_to_generate):
|
for i in range(5):
|
||||||
test.nodes[1].sendtoaddress(mytaddr, 1)
|
test.nodes[1].sendtoaddress(mytaddr, 1)
|
||||||
for i in range(20):
|
for i in range(20):
|
||||||
test.nodes[1].sendtoaddress(n2taddr, 1)
|
test.nodes[1].sendtoaddress(n2taddr, 1)
|
||||||
test.nodes[1].generate(1)
|
test.nodes[1].generate(1)
|
||||||
test.sync_all()
|
test.sync_all()
|
||||||
|
|
||||||
# Merging the UTXOs will conditionally occur over two transactions, since max tx size is 100,000 bytes before Sapling and 2,000,000 after.
|
# This z_mergetoaddress and the one below result in two notes in myzaddr.
|
||||||
# We don't verify mergingTransparentValue as UTXOs are not selected in any specific order, so value can change on each test run.
|
result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, DEFAULT_FEE)
|
||||||
# We set an unrealistically high limit parameter of 99999, to verify that max tx size will constrain the number of UTXOs.
|
assert_equal(result["mergingUTXOs"], 5)
|
||||||
result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, 0, 99999)
|
assert_equal(result["remainingUTXOs"], 0)
|
||||||
assert_equal(result["mergingUTXOs"], self.utxos_in_tx1)
|
assert_equal(result["mergingNotes"], 0)
|
||||||
assert_equal(result["remainingUTXOs"], self.utxos_in_tx2)
|
assert_equal(result["remainingNotes"], 0)
|
||||||
assert_equal(result["mergingNotes"], Decimal('0'))
|
|
||||||
assert_equal(result["mergingShieldedValue"], Decimal('0'))
|
|
||||||
assert_equal(result["remainingNotes"], Decimal('0'))
|
|
||||||
assert_equal(result["remainingShieldedValue"], Decimal('0'))
|
|
||||||
remainingTransparentValue = result["remainingTransparentValue"]
|
|
||||||
wait_and_assert_operationid_status(test.nodes[0], result['opid'])
|
wait_and_assert_operationid_status(test.nodes[0], result['opid'])
|
||||||
|
|
||||||
# For sapling we do not check that this occurs over two transactions because of the time that it would take
|
# Verify maximum number of UTXOs is not limited when the limit parameter is set to 0.
|
||||||
if self.utxos_in_tx2 > 0:
|
|
||||||
# Verify that UTXOs are locked (not available for selection) by queuing up another merging operation
|
|
||||||
result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, 0, 0)
|
|
||||||
assert_equal(result["mergingUTXOs"], self.utxos_in_tx2)
|
|
||||||
assert_equal(result["mergingTransparentValue"], Decimal(remainingTransparentValue))
|
|
||||||
assert_equal(result["remainingUTXOs"], Decimal('0'))
|
|
||||||
assert_equal(result["remainingTransparentValue"], Decimal('0'))
|
|
||||||
assert_equal(result["mergingNotes"], Decimal('0'))
|
|
||||||
assert_equal(result["mergingShieldedValue"], Decimal('0'))
|
|
||||||
assert_equal(result["remainingNotes"], Decimal('0'))
|
|
||||||
assert_equal(result["remainingShieldedValue"], Decimal('0'))
|
|
||||||
wait_and_assert_operationid_status(test.nodes[0], result['opid'])
|
|
||||||
|
|
||||||
# sync_all() invokes sync_mempool() but node 2's mempool limit will cause tx1 and tx2 to be rejected.
|
|
||||||
# So instead, we sync on blocks and mempool for node 0 and node 1, and after a new block is generated
|
|
||||||
# which mines tx1 and tx2, all nodes will have an empty mempool which can then be synced.
|
|
||||||
sync_blocks(test.nodes[:2])
|
|
||||||
sync_mempools(test.nodes[:2])
|
|
||||||
# Generate enough blocks to ensure all transactions are mined
|
|
||||||
while test.nodes[1].getmempoolinfo()['size'] > 0:
|
|
||||||
test.nodes[1].generate(1)
|
|
||||||
test.sync_all()
|
|
||||||
|
|
||||||
# Verify maximum number of UTXOs which node 2 can shield is not limited
|
|
||||||
# when the limit parameter is set to 0.
|
|
||||||
expected_to_merge = 20
|
expected_to_merge = 20
|
||||||
expected_remaining = 0
|
expected_remaining = 0
|
||||||
|
|
||||||
|
@ -302,6 +269,7 @@ class MergeToAddressHelper:
|
||||||
test.sync_all()
|
test.sync_all()
|
||||||
test.nodes[1].generate(1)
|
test.nodes[1].generate(1)
|
||||||
test.sync_all()
|
test.sync_all()
|
||||||
|
assert_equal(2, len(test.nodes[0].z_listunspent()))
|
||||||
|
|
||||||
# Verify maximum number of UTXOs which node 0 can shield is set by default limit parameter of 50
|
# Verify maximum number of UTXOs which node 0 can shield is set by default limit parameter of 50
|
||||||
mytaddr = test.nodes[0].getnewaddress()
|
mytaddr = test.nodes[0].getnewaddress()
|
||||||
|
@ -309,7 +277,7 @@ class MergeToAddressHelper:
|
||||||
test.nodes[1].sendtoaddress(mytaddr, 1)
|
test.nodes[1].sendtoaddress(mytaddr, 1)
|
||||||
test.nodes[1].generate(1)
|
test.nodes[1].generate(1)
|
||||||
test.sync_all()
|
test.sync_all()
|
||||||
result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, DEFAULT_FEE)
|
result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, conventional_fee(52))
|
||||||
assert_equal(result["mergingUTXOs"], Decimal('50'))
|
assert_equal(result["mergingUTXOs"], Decimal('50'))
|
||||||
assert_equal(result["remainingUTXOs"], Decimal('50'))
|
assert_equal(result["remainingUTXOs"], Decimal('50'))
|
||||||
assert_equal(result["mergingNotes"], Decimal('0'))
|
assert_equal(result["mergingNotes"], Decimal('0'))
|
||||||
|
@ -317,40 +285,38 @@ class MergeToAddressHelper:
|
||||||
assert_equal(result["remainingNotes"], Decimal('0'))
|
assert_equal(result["remainingNotes"], Decimal('0'))
|
||||||
wait_and_assert_operationid_status(test.nodes[0], result['opid'])
|
wait_and_assert_operationid_status(test.nodes[0], result['opid'])
|
||||||
|
|
||||||
|
assert_equal(2, len(test.nodes[0].z_listunspent()))
|
||||||
|
assert_equal(3, len(test.nodes[0].z_listunspent(0)))
|
||||||
|
|
||||||
# Verify maximum number of UTXOs which node 0 can shield can be set by the limit parameter
|
# Verify maximum number of UTXOs which node 0 can shield can be set by the limit parameter
|
||||||
result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, DEFAULT_FEE, 33)
|
result = test.nodes[0].z_mergetoaddress([mytaddr], myzaddr, conventional_fee(35), 33)
|
||||||
assert_equal(result["mergingUTXOs"], Decimal('33'))
|
assert_equal(result["mergingUTXOs"], Decimal('33'))
|
||||||
assert_equal(result["remainingUTXOs"], Decimal('17'))
|
assert_equal(result["remainingUTXOs"], Decimal('17'))
|
||||||
assert_equal(result["mergingNotes"], Decimal('0'))
|
assert_equal(result["mergingNotes"], Decimal('0'))
|
||||||
# Remaining notes are only counted if we are trying to merge any notes
|
# Remaining notes are only counted if we are trying to merge any notes
|
||||||
assert_equal(result["remainingNotes"], Decimal('0'))
|
assert_equal(result["remainingNotes"], Decimal('0'))
|
||||||
wait_and_assert_operationid_status(test.nodes[0], result['opid'])
|
wait_and_assert_operationid_status(test.nodes[0], result['opid'])
|
||||||
# Don't sync node 2 which rejects the tx due to its mempooltxinputlimit
|
test.sync_all()
|
||||||
sync_blocks(test.nodes[:2])
|
|
||||||
sync_mempools(test.nodes[:2])
|
|
||||||
test.nodes[1].generate(1)
|
test.nodes[1].generate(1)
|
||||||
test.sync_all()
|
test.sync_all()
|
||||||
|
assert_equal(4, len(test.nodes[0].z_listunspent()))
|
||||||
|
|
||||||
# Verify maximum number of notes which node 0 can shield can be set by the limit parameter
|
|
||||||
# Also check that we can set off a second merge before the first one is complete
|
# Also check that we can set off a second merge before the first one is complete
|
||||||
|
|
||||||
# myzaddr will have 5 notes if testing before to Sapling activation and 4 otherwise
|
|
||||||
num_notes = len(test.nodes[0].z_listunspent(0))
|
|
||||||
result1 = test.nodes[0].z_mergetoaddress([myzaddr], myzaddr, DEFAULT_FEE, 50, 2)
|
result1 = test.nodes[0].z_mergetoaddress([myzaddr], myzaddr, DEFAULT_FEE, 50, 2)
|
||||||
result2 = test.nodes[0].z_mergetoaddress([myzaddr], myzaddr, DEFAULT_FEE, 50, 2)
|
|
||||||
|
|
||||||
# First merge should select from all notes
|
# First merge should select from all notes
|
||||||
assert_equal(result1["mergingUTXOs"], Decimal('0'))
|
assert_equal(result1["mergingUTXOs"], Decimal('0'))
|
||||||
# Remaining UTXOs are only counted if we are trying to merge any UTXOs
|
# Remaining UTXOs are only counted if we are trying to merge any UTXOs
|
||||||
assert_equal(result1["remainingUTXOs"], Decimal('0'))
|
assert_equal(result1["remainingUTXOs"], Decimal('0'))
|
||||||
assert_equal(result1["mergingNotes"], Decimal('2'))
|
assert_equal(result1["mergingNotes"], Decimal('2'))
|
||||||
assert_equal(result1["remainingNotes"], num_notes - 2)
|
assert_equal(result1["remainingNotes"], 2)
|
||||||
|
|
||||||
# Second merge should ignore locked notes
|
# Second merge should ignore locked notes
|
||||||
|
result2 = test.nodes[0].z_mergetoaddress([myzaddr], myzaddr, DEFAULT_FEE, 50, 2)
|
||||||
assert_equal(result2["mergingUTXOs"], Decimal('0'))
|
assert_equal(result2["mergingUTXOs"], Decimal('0'))
|
||||||
assert_equal(result2["remainingUTXOs"], Decimal('0'))
|
assert_equal(result2["remainingUTXOs"], Decimal('0'))
|
||||||
assert_equal(result2["mergingNotes"], Decimal('2'))
|
assert_equal(result2["mergingNotes"], Decimal('2'))
|
||||||
assert_equal(result2["remainingNotes"], num_notes - 4)
|
assert_equal(result2["remainingNotes"], 0)
|
||||||
wait_and_assert_operationid_status(test.nodes[0], result1['opid'])
|
wait_and_assert_operationid_status(test.nodes[0], result1['opid'])
|
||||||
wait_and_assert_operationid_status(test.nodes[0], result2['opid'])
|
wait_and_assert_operationid_status(test.nodes[0], result2['opid'])
|
||||||
|
|
||||||
|
@ -359,11 +325,11 @@ class MergeToAddressHelper:
|
||||||
test.sync_all()
|
test.sync_all()
|
||||||
|
|
||||||
# Shield both UTXOs and notes to a z-addr
|
# Shield both UTXOs and notes to a z-addr
|
||||||
result = test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, 0, 10, 2)
|
result = test.nodes[0].z_mergetoaddress(self.any_zaddr_or_utxo, myzaddr, DEFAULT_FEE, 10, 2)
|
||||||
assert_equal(result["mergingUTXOs"], Decimal('10'))
|
assert_equal(result["mergingUTXOs"], Decimal('10'))
|
||||||
assert_equal(result["remainingUTXOs"], Decimal('7'))
|
assert_equal(result["remainingUTXOs"], Decimal('7'))
|
||||||
assert_equal(result["mergingNotes"], Decimal('2'))
|
assert_equal(result["mergingNotes"], Decimal('2'))
|
||||||
assert_equal(result["remainingNotes"], num_notes - 4)
|
assert_equal(result["remainingNotes"], 0)
|
||||||
wait_and_assert_operationid_status(test.nodes[0], result['opid'])
|
wait_and_assert_operationid_status(test.nodes[0], result['opid'])
|
||||||
test.sync_all()
|
test.sync_all()
|
||||||
test.nodes[1].generate(1)
|
test.nodes[1].generate(1)
|
||||||
|
|
|
@ -8,9 +8,7 @@ from mergetoaddress_helper import MergeToAddressHelper
|
||||||
|
|
||||||
|
|
||||||
class MergeToAddressSapling (BitcoinTestFramework):
|
class MergeToAddressSapling (BitcoinTestFramework):
|
||||||
# 13505 would be the maximum number of utxos based on the transaction size limits for Sapling
|
helper = MergeToAddressHelper('sapling', 'ANY_SAPLING')
|
||||||
# but testing this causes the test to take an indeterminately long time to run.
|
|
||||||
helper = MergeToAddressHelper('sapling', 'ANY_SAPLING', 800, 800, 0)
|
|
||||||
|
|
||||||
def setup_chain(self):
|
def setup_chain(self):
|
||||||
self.helper.setup_chain(self)
|
self.helper.setup_chain(self)
|
||||||
|
|
|
@ -4,139 +4,118 @@
|
||||||
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import (
|
from test_framework.util import assert_equal, start_nodes
|
||||||
assert_equal,
|
from test_framework.mininode import COIN
|
||||||
connect_nodes,
|
from test_framework.zip317 import BLOCK_UNPAID_ACTION_LIMIT, MARGINAL_FEE, ZIP_317_FEE
|
||||||
initialize_chain_clean,
|
|
||||||
start_node,
|
|
||||||
sync_blocks,
|
|
||||||
sync_mempools,
|
|
||||||
)
|
|
||||||
from test_framework.zip317 import conventional_fee_zats
|
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
|
||||||
class PrioritiseTransactionTest (BitcoinTestFramework):
|
class PrioritiseTransactionTest(BitcoinTestFramework):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.cache_behavior = 'clean'
|
||||||
|
|
||||||
def setup_chain(self):
|
def setup_nodes(self):
|
||||||
print("Initializing test directory "+self.options.tmpdir)
|
return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
|
||||||
initialize_chain_clean(self.options.tmpdir, 4)
|
'-paytxfee=0.000001',
|
||||||
|
'-printpriority=1',
|
||||||
|
'-allowdeprecated=getnewaddress',
|
||||||
|
]] * self.num_nodes)
|
||||||
|
|
||||||
def setup_network(self, split=False):
|
def run_test(self):
|
||||||
self.nodes = []
|
def in_template(block_template, txid):
|
||||||
# Start nodes with tiny block size of 11kb
|
return any([tx['hash'] == txid for tx in block_template['transactions']])
|
||||||
args = [
|
|
||||||
"-blockmaxsize=11000",
|
def eventually_in_template(node, txid):
|
||||||
"-maxorphantx=1000",
|
for tries in range(2):
|
||||||
"-printpriority=1",
|
time.sleep(11)
|
||||||
"-limitancestorcount=900",
|
block_template = node.getblocktemplate()
|
||||||
"-allowdeprecated=getnewaddress",
|
if in_template(block_template, txid): return True
|
||||||
]
|
return False
|
||||||
self.nodes.append(start_node(0, self.options.tmpdir, args))
|
|
||||||
self.nodes.append(start_node(1, self.options.tmpdir, args))
|
# Make sure we have enough mature funds on node 0.
|
||||||
connect_nodes(self.nodes[1], 0)
|
# Slow start is switched off for regtest, and we're before Blossom,
|
||||||
self.is_network_split=False
|
# so each utxo will be 10 ZEC.
|
||||||
|
miner_subsidy = Decimal("10")
|
||||||
|
self.nodes[0].generate(100 + BLOCK_UNPAID_ACTION_LIMIT + 2)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
def run_test (self):
|
# Create a tx that will not be mined unless prioritised.
|
||||||
print("Mining 11kb blocks...")
|
# We spend BLOCK_UNPAID_ACTION_LIMIT mining rewards, ensuring that
|
||||||
self.nodes[0].generate(501)
|
# tx has exactly (BLOCK_UNPAID_ACTION_LIMIT + 1) logical actions,
|
||||||
|
# because one extra input will be needed to pay the fee.
|
||||||
|
# Since we've set -paytxfee to pay only the relay fee rate, the fee
|
||||||
|
# will be less than the marginal fee, so these are all unpaid actions.
|
||||||
|
amount = miner_subsidy * BLOCK_UNPAID_ACTION_LIMIT
|
||||||
|
tx = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), amount)
|
||||||
|
|
||||||
# 11 kb blocks will only hold about 50 txs, so this will fill mempool with older txs
|
mempool = self.nodes[0].getrawmempool(True)
|
||||||
taddr = self.nodes[1].getnewaddress()
|
assert(tx in mempool)
|
||||||
for _ in range(900):
|
fee_zats = int(mempool[tx]['fee'] * COIN)
|
||||||
self.nodes[0].sendtoaddress(taddr, 0.1)
|
assert(fee_zats < MARGINAL_FEE)
|
||||||
self.nodes[0].generate(1)
|
tx_verbose = self.nodes[0].getrawtransaction(tx, 1)
|
||||||
sync_blocks(self.nodes)
|
assert_equal(BLOCK_UNPAID_ACTION_LIMIT + 1, len(tx_verbose['vin']))
|
||||||
# With a rate of either 7tx/s or 14tx/s per peer (depending on whether
|
|
||||||
# the connection is inbound or outbound), syncing this many transactions
|
|
||||||
# could take up to 128s. So use a higher timeout on the mempool sync.
|
|
||||||
sync_mempools(self.nodes, timeout=200)
|
|
||||||
|
|
||||||
# Create tx to be prioritised on node 0
|
# Check that tx is not in a new block template prior to prioritisation.
|
||||||
# This tx will not be mined without prioritisation.
|
|
||||||
priority_tx_0 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)
|
|
||||||
|
|
||||||
# Check that priority_tx_0 is not in block_template() prior to prioritisation
|
|
||||||
block_template = self.nodes[0].getblocktemplate()
|
block_template = self.nodes[0].getblocktemplate()
|
||||||
in_block_template = False
|
assert_equal(in_template(block_template, tx), False)
|
||||||
for tx in block_template['transactions']:
|
|
||||||
if tx['hash'] == priority_tx_0:
|
|
||||||
in_block_template = True
|
|
||||||
break
|
|
||||||
|
|
||||||
# TODO: this doesn't work reliably now, but as part of #6403 it can be made
|
def send_fully_paid_transaction():
|
||||||
# to work reliably by using a transaction that has unpaid actions over the
|
# Sending a new transaction will make getblocktemplate refresh within 5s.
|
||||||
# block_unpaid_action_limit before prioritisation.
|
# We use z_sendmany so that it will pay the conventional fee (ignoring -paytxfee)
|
||||||
print("in_block_template =", in_block_template)
|
# and not take up an unpaid action.
|
||||||
#assert_equal(in_block_template, False)
|
recipients = [{'address': self.nodes[2].getnewaddress(), 'amount': Decimal("1")}]
|
||||||
|
self.nodes[0].z_sendmany('ANY_TADDR', recipients, 0, ZIP_317_FEE, 'AllowFullyTransparent')
|
||||||
|
|
||||||
priority_success = self.nodes[0].prioritisetransaction(priority_tx_0, 0, conventional_fee_zats(2))
|
# Prioritising it on node 1 has no effect on node 0.
|
||||||
|
self.sync_all()
|
||||||
|
priority_success = self.nodes[1].prioritisetransaction(tx, 0, MARGINAL_FEE)
|
||||||
assert(priority_success)
|
assert(priority_success)
|
||||||
|
mempool = self.nodes[1].getrawmempool(True)
|
||||||
|
assert_equal(fee_zats + MARGINAL_FEE, mempool[tx]['modifiedfee'] * COIN)
|
||||||
|
self.sync_all()
|
||||||
|
send_fully_paid_transaction()
|
||||||
|
assert_equal(eventually_in_template(self.nodes[0], tx), False)
|
||||||
|
|
||||||
# Check that prioritised transaction is not in getblocktemplate()
|
# Now prioritise it on node 0, but short by one zatoshi.
|
||||||
# (not updated because no new txns)
|
priority_success = self.nodes[0].prioritisetransaction(tx, 0, MARGINAL_FEE - fee_zats - 1)
|
||||||
in_block_template = False
|
assert(priority_success)
|
||||||
|
mempool = self.nodes[0].getrawmempool(True)
|
||||||
|
assert_equal(MARGINAL_FEE - 1, mempool[tx]['modifiedfee'] * COIN)
|
||||||
|
send_fully_paid_transaction()
|
||||||
|
assert_equal(eventually_in_template(self.nodes[0], tx), False)
|
||||||
|
|
||||||
|
# Finally, prioritise it on node 0 by the one extra zatoshi (this also checks
|
||||||
|
# that prioritisation is cumulative).
|
||||||
|
priority_success = self.nodes[0].prioritisetransaction(tx, 0, 1)
|
||||||
|
assert(priority_success)
|
||||||
|
mempool = self.nodes[0].getrawmempool(True)
|
||||||
|
assert_equal(MARGINAL_FEE, mempool[tx]['modifiedfee'] * COIN)
|
||||||
|
|
||||||
|
# The block template will refresh after 1 minute, or after 5 seconds if a new
|
||||||
|
# transaction is added to the mempool. As long as there is less than a minute
|
||||||
|
# between the getblocktemplate() calls, it should not have been updated yet.
|
||||||
block_template = self.nodes[0].getblocktemplate()
|
block_template = self.nodes[0].getblocktemplate()
|
||||||
for tx in block_template['transactions']:
|
assert_equal(in_template(block_template, tx), False)
|
||||||
if tx['hash'] == priority_tx_0:
|
|
||||||
in_block_template = True
|
|
||||||
break
|
|
||||||
|
|
||||||
# See TODO above.
|
# Check that the prioritised transaction eventually gets into a new block template.
|
||||||
print("in_block_template =", in_block_template)
|
send_fully_paid_transaction()
|
||||||
#assert_equal(in_block_template, False)
|
assert_equal(eventually_in_template(self.nodes[0], tx), True)
|
||||||
|
|
||||||
# Sending a new transaction will make getblocktemplate refresh within 10s
|
# Mine a block on node 0.
|
||||||
self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)
|
|
||||||
|
|
||||||
# Check that prioritised transaction is in getblocktemplate()
|
|
||||||
# getblocktemplate() will refresh after 1 min, or after 10 sec if new transaction is added to mempool
|
|
||||||
# Mempool is probed every 10 seconds. We'll give getblocktemplate() a maximum of 30 seconds to refresh
|
|
||||||
block_template = self.nodes[0].getblocktemplate()
|
|
||||||
start = time.time();
|
|
||||||
in_block_template = False
|
|
||||||
while in_block_template == False:
|
|
||||||
for tx in block_template['transactions']:
|
|
||||||
if tx['hash'] == priority_tx_0:
|
|
||||||
in_block_template = True
|
|
||||||
break
|
|
||||||
if time.time() - start > 30:
|
|
||||||
raise AssertionError("Test timed out because prioritised transaction was not returned by getblocktemplate within 30 seconds.")
|
|
||||||
time.sleep(1)
|
|
||||||
block_template = self.nodes[0].getblocktemplate()
|
|
||||||
|
|
||||||
assert(in_block_template)
|
|
||||||
|
|
||||||
# Node 1 doesn't get the next block, so this *shouldn't* be mined despite being prioritised on node 1
|
|
||||||
priority_tx_1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.1)
|
|
||||||
self.nodes[1].prioritisetransaction(priority_tx_1, 0, conventional_fee_zats(2))
|
|
||||||
|
|
||||||
# Mine block on node 0
|
|
||||||
blk_hash = self.nodes[0].generate(1)
|
blk_hash = self.nodes[0].generate(1)
|
||||||
block = self.nodes[0].getblock(blk_hash[0])
|
block = self.nodes[0].getblock(blk_hash[0])
|
||||||
|
assert_equal(tx in block['tx'], True)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
# Check that priority_tx_0 was mined
|
# Check that tx was mined and that node 1 received the funds.
|
||||||
mempool = self.nodes[0].getrawmempool()
|
mempool = self.nodes[0].getrawmempool()
|
||||||
assert_equal(priority_tx_0 in block['tx'], True)
|
assert_equal(mempool, [])
|
||||||
assert_equal(priority_tx_0 in mempool, False)
|
assert_equal(self.nodes[1].getbalance(), amount)
|
||||||
|
# Check that all of the fully paid transactions were mined.
|
||||||
# Check that priority_tx_1 was not mined
|
assert_equal(self.nodes[2].getbalance(), Decimal("3"))
|
||||||
assert_equal(priority_tx_1 in mempool, True)
|
|
||||||
# TODO: again this is potentially unreliable.
|
|
||||||
#assert_equal(priority_tx_1 in block['tx'], False)
|
|
||||||
|
|
||||||
# Mine a block on node 1 and sync
|
|
||||||
blk_hash_1 = self.nodes[1].generate(1)
|
|
||||||
block_1 = self.nodes[1].getblock(blk_hash_1[0])
|
|
||||||
self.sync_all()
|
|
||||||
|
|
||||||
# Check to see if priority_tx_1 is now mined
|
|
||||||
mempool_1 = self.nodes[1].getrawmempool()
|
|
||||||
assert_equal(priority_tx_1 in mempool_1, False)
|
|
||||||
assert_equal(priority_tx_1 in block_1['tx'], True)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
PrioritiseTransactionTest().main()
|
PrioritiseTransactionTest().main()
|
||||||
|
|
|
@ -24,6 +24,10 @@ GRACE_ACTIONS = 2
|
||||||
# https://zips.z.cash/zip-0317#recommended-algorithm-for-block-template-construction
|
# https://zips.z.cash/zip-0317#recommended-algorithm-for-block-template-construction
|
||||||
WEIGHT_RATIO_CAP = 4
|
WEIGHT_RATIO_CAP = 4
|
||||||
|
|
||||||
|
# Limits the number of unpaid actions in a block. See
|
||||||
|
# https://zips.z.cash/zip-0317#recommended-algorithm-for-block-template-construction
|
||||||
|
BLOCK_UNPAID_ACTION_LIMIT = 50
|
||||||
|
|
||||||
# The zcashd RPC sentinel value to indicate the conventional_fee when a positional argument is
|
# The zcashd RPC sentinel value to indicate the conventional_fee when a positional argument is
|
||||||
# required.
|
# required.
|
||||||
ZIP_317_FEE = None
|
ZIP_317_FEE = None
|
||||||
|
|
|
@ -8,6 +8,7 @@ from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.authproxy import JSONRPCException
|
from test_framework.authproxy import JSONRPCException
|
||||||
from test_framework.util import assert_equal, start_nodes, start_node, \
|
from test_framework.util import assert_equal, start_nodes, start_node, \
|
||||||
connect_nodes_bi, sync_blocks, sync_mempools
|
connect_nodes_bi, sync_blocks, sync_mempools
|
||||||
|
from test_framework.zip317 import conventional_fee
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
|
@ -101,7 +102,9 @@ class WalletTest (BitcoinTestFramework):
|
||||||
|
|
||||||
# Catch an attempt to send a transaction with an absurdly high fee.
|
# Catch an attempt to send a transaction with an absurdly high fee.
|
||||||
# Send 1.0 ZEC from an utxo of value 10.0 ZEC but don't specify a change output, so then
|
# Send 1.0 ZEC from an utxo of value 10.0 ZEC but don't specify a change output, so then
|
||||||
# the change of 9.0 ZEC becomes the fee, which is greater than estimated fee of 0.0021 ZEC.
|
# the change of 9.0 ZEC becomes the fee, which is considered to be absurdly high because
|
||||||
|
# the fee is more than 4 times the conventional fee.
|
||||||
|
assert(Decimal("9.0") > 4*conventional_fee(1))
|
||||||
inputs = []
|
inputs = []
|
||||||
outputs = {}
|
outputs = {}
|
||||||
for utxo in node2utxos:
|
for utxo in node2utxos:
|
||||||
|
|
|
@ -127,6 +127,7 @@ class WalletShieldingCoinbaseTest (BitcoinTestFramework):
|
||||||
self.nodes[3].z_importviewingkey(myviewingkey, "no")
|
self.nodes[3].z_importviewingkey(myviewingkey, "no")
|
||||||
|
|
||||||
# This send will succeed. We send two coinbase utxos totalling 20.0 less a default fee, with no change.
|
# This send will succeed. We send two coinbase utxos totalling 20.0 less a default fee, with no change.
|
||||||
|
# (This tx fits within the block unpaid action limit.)
|
||||||
shieldvalue = Decimal('20.0') - DEFAULT_FEE
|
shieldvalue = Decimal('20.0') - DEFAULT_FEE
|
||||||
recipients = []
|
recipients = []
|
||||||
recipients.append({"address":myzaddr, "amount": shieldvalue})
|
recipients.append({"address":myzaddr, "amount": shieldvalue})
|
||||||
|
@ -181,16 +182,17 @@ class WalletShieldingCoinbaseTest (BitcoinTestFramework):
|
||||||
# check balances (the z_sendmany consumes 3 coinbase utxos)
|
# check balances (the z_sendmany consumes 3 coinbase utxos)
|
||||||
resp = self.nodes[0].z_gettotalbalance()
|
resp = self.nodes[0].z_gettotalbalance()
|
||||||
assert_equal(Decimal(resp["transparent"]), Decimal('20.0'))
|
assert_equal(Decimal(resp["transparent"]), Decimal('20.0'))
|
||||||
assert_equal(Decimal(resp["private"]), Decimal('20.0') - DEFAULT_FEE)
|
assert_equal(Decimal(resp["private"]), shieldvalue)
|
||||||
assert_equal(Decimal(resp["total"]), Decimal('40.0') - DEFAULT_FEE)
|
assert_equal(Decimal(resp["total"]), Decimal('20.0') + shieldvalue)
|
||||||
|
|
||||||
# The Sprout value pool should reflect the send
|
# The Sapling value pool should reflect the send
|
||||||
saplingvalue = shieldvalue
|
saplingvalue = shieldvalue
|
||||||
check_value_pool(self.nodes[0], 'sapling', saplingvalue)
|
check_value_pool(self.nodes[0], 'sapling', saplingvalue)
|
||||||
|
|
||||||
# A custom fee of 0 is okay. Here the node will send the note value back to itself.
|
# A custom fee of 0 is okay. Here the node will send the note value back to itself.
|
||||||
|
# (This tx fits within the block unpaid action limit.)
|
||||||
recipients = []
|
recipients = []
|
||||||
recipients.append({"address":myzaddr, "amount": Decimal('20.0') - conventional_fee(2)})
|
recipients.append({"address":myzaddr, "amount": saplingvalue})
|
||||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, 1, Decimal('0.0'))
|
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, 1, Decimal('0.0'))
|
||||||
mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
|
mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
@ -198,8 +200,8 @@ class WalletShieldingCoinbaseTest (BitcoinTestFramework):
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
resp = self.nodes[0].z_gettotalbalance()
|
resp = self.nodes[0].z_gettotalbalance()
|
||||||
assert_equal(Decimal(resp["transparent"]), Decimal('20.0'))
|
assert_equal(Decimal(resp["transparent"]), Decimal('20.0'))
|
||||||
assert_equal(Decimal(resp["private"]), Decimal('20.0') - DEFAULT_FEE)
|
assert_equal(Decimal(resp["private"]), saplingvalue)
|
||||||
assert_equal(Decimal(resp["total"]), Decimal('40.0') - DEFAULT_FEE)
|
assert_equal(Decimal(resp["total"]), Decimal('20.0') + saplingvalue)
|
||||||
|
|
||||||
# The Sapling value pool should be unchanged
|
# The Sapling value pool should be unchanged
|
||||||
check_value_pool(self.nodes[0], 'sapling', saplingvalue)
|
check_value_pool(self.nodes[0], 'sapling', saplingvalue)
|
||||||
|
@ -220,8 +222,8 @@ class WalletShieldingCoinbaseTest (BitcoinTestFramework):
|
||||||
saplingvalue -= unshieldvalue + DEFAULT_FEE
|
saplingvalue -= unshieldvalue + DEFAULT_FEE
|
||||||
resp = self.nodes[0].z_gettotalbalance()
|
resp = self.nodes[0].z_gettotalbalance()
|
||||||
assert_equal(Decimal(resp["transparent"]), Decimal('30.0'))
|
assert_equal(Decimal(resp["transparent"]), Decimal('30.0'))
|
||||||
assert_equal(Decimal(resp["private"]), Decimal('10.0') - 2*DEFAULT_FEE)
|
assert_equal(Decimal(resp["private"]), saplingvalue)
|
||||||
assert_equal(Decimal(resp["total"]), Decimal('40.0') - 2*DEFAULT_FEE)
|
assert_equal(Decimal(resp["total"]), Decimal('30.0') + saplingvalue)
|
||||||
check_value_pool(self.nodes[0], 'sapling', saplingvalue)
|
check_value_pool(self.nodes[0], 'sapling', saplingvalue)
|
||||||
|
|
||||||
# z_sendmany will return an error if there is transparent change output considered dust.
|
# z_sendmany will return an error if there is transparent change output considered dust.
|
||||||
|
@ -256,14 +258,11 @@ class WalletShieldingCoinbaseTest (BitcoinTestFramework):
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Insufficient funds, coinbase funds can only be spent after they have been sent to a zaddr" in errorString, True)
|
assert_equal("Insufficient funds, coinbase funds can only be spent after they have been sent to a zaddr" in errorString, True)
|
||||||
|
|
||||||
# Verify that mempools accept tx with joinsplits which have at least the default z_sendmany fee.
|
# Verify that mempools accept tx with shielded outputs and that pay at least the conventional fee.
|
||||||
# If this test passes, it confirms that issue #1851 has been resolved, where sending from
|
|
||||||
# a zaddr to 1385 taddr recipients fails because the default fee was considered too low
|
|
||||||
# given the tx size, resulting in mempool rejection.
|
|
||||||
errorString = ''
|
errorString = ''
|
||||||
recipients = []
|
recipients = []
|
||||||
num_t_recipients = 1998 # stay just under the absurdly-high-fee error
|
num_t_recipients = 1998 # stay just under the absurdly-high-fee error
|
||||||
amount_per_recipient = Decimal('0.00000546') # dust threshold
|
amount_per_recipient = Decimal('0.00000054') # dust threshold
|
||||||
# Note that regtest chainparams does not require standard tx, so setting the amount to be
|
# Note that regtest chainparams does not require standard tx, so setting the amount to be
|
||||||
# less than the dust threshold, e.g. 0.00000001 will not result in mempool rejection.
|
# less than the dust threshold, e.g. 0.00000001 will not result in mempool rejection.
|
||||||
start_time = timeit.default_timer()
|
start_time = timeit.default_timer()
|
||||||
|
|
Loading…
Reference in New Issue