qa: port 12 wallet/mining tests to python3 and fix three framework blockers
Ports qa/rpc-tests from 6 python3 files to 18. Ran every ported test against
the freshly built v1.3.0 dragonxd. Results, honestly:
PASS (1) getblocktemplate_proposals.py
NOT APPLICABLE (7) wallet.py, walletbackup.py, wallet_protectcoinbase.py,
wallet_listnotes.py, wallet_mergetoaddress.py,
getblocktemplate.py, wallet_shieldcoinbase.py
BLOCKED (4) wallet_sapling, wallet_nullifiers, wallet_persistence,
wallet_treestate
The "not applicable" seven are inherited Zcash/Hush-era tests that exercise
features DragonX deliberately removed. They assume transparent t->t value
transfer, but ASSETCHAINS_PRIVATE=1 (hush_utils.h:1826) makes sendtoaddress
and sendmany consensus-refuse; they assume Sprout joinsplits, which are gone
from the RPC layer entirely; and they hardcode Bitcoin economics (10 coin/block,
100-block maturity) against DragonX's 3 DRGX and COINBASE_MATURITY=1. They are
ported and left in place rather than deleted, but they cannot pass on this chain
without being rewritten around z_shieldcoinbase/autoshield.
Three framework fixes in test_framework/util.py, each of which broke every
multi-node test:
- initialize_chain() passed -connect=0, and init.cpp soft-sets -listen=0 when
-connect is present, so cache node0 never opened its p2p port and nodes 1-3
could never sync to it -- initialize_chain() hung forever in sync_blocks().
Now passes -listen=1 -bind=127.0.0.1 -dnsseed=0 explicitly (an explicit arg
beats SoftSetBoolArg) while keeping the cache nodes off the public network.
- cache cleanup removed files from <datadir> when dragonxd writes them one
level deeper into the net-specific <datadir>/regtest.
- set_node_times() did print("..." + t) with t an int -> TypeError.
- default binary paths corrected to src/dragonxd and src/dragonx-cli.
The four BLOCKED tests are blocked by a daemon assert, not by the port; see the
follow-up commit/report on BLOCK_VALID_CONTEXT.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FU87LdsJZiZkfq1eXubpeo
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2016-2024 The Hush developers
|
||||
# Copyright (c) 2016 The Zcash developers
|
||||
# Distributed under the GPLv3 software license, see the accompanying
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.authproxy import JSONRPCException
|
||||
from test_framework.mininode import COIN
|
||||
from test_framework.util import assert_equal, initialize_chain_clean, \
|
||||
start_nodes, connect_nodes_bi, wait_and_assert_operationid_status
|
||||
|
||||
@@ -14,6 +13,20 @@ import sys
|
||||
import timeit
|
||||
from decimal import Decimal
|
||||
|
||||
# Upstream imported this from test_framework.mininode, which is still python2 and
|
||||
# fails to even parse under python3 (0x100000000L literals). mininode is a p2p
|
||||
# serialisation module this test does not otherwise use, so rather than drag a
|
||||
# large unrelated port into test_framework/ the one constant needed is inlined.
|
||||
# Same value as test_framework/mininode.py:52.
|
||||
COIN = 100000000 # 1 DRGX in puposhis
|
||||
|
||||
# DragonX has no Sprout pool: getblockchaininfo/getblock only ever emit a
|
||||
# "sapling" entry in valuePools (see rpc/blockchain.cpp), and z_getnewaddress
|
||||
# only makes Sapling addresses. The shielded value this test moves therefore
|
||||
# lands in the Sapling pool, so every check that upstream made against 'sprout'
|
||||
# is made against 'sapling' here. The assertion itself is unchanged.
|
||||
SHIELDED_POOL = 'sapling'
|
||||
|
||||
def check_value_pool(node, name, total):
|
||||
value_pools = node.getblockchaininfo()['valuePools']
|
||||
found = False
|
||||
@@ -42,7 +55,7 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
self.sync_all()
|
||||
|
||||
def run_test (self):
|
||||
print "Mining blocks..."
|
||||
print("Mining blocks...")
|
||||
|
||||
self.nodes[0].generate(4)
|
||||
|
||||
@@ -59,17 +72,17 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
assert_equal(self.nodes[2].getbalance(), 0)
|
||||
assert_equal(self.nodes[3].getbalance(), 0)
|
||||
|
||||
check_value_pool(self.nodes[0], 'sprout', 0)
|
||||
check_value_pool(self.nodes[1], 'sprout', 0)
|
||||
check_value_pool(self.nodes[2], 'sprout', 0)
|
||||
check_value_pool(self.nodes[3], 'sprout', 0)
|
||||
check_value_pool(self.nodes[0], SHIELDED_POOL, 0)
|
||||
check_value_pool(self.nodes[1], SHIELDED_POOL, 0)
|
||||
check_value_pool(self.nodes[2], SHIELDED_POOL, 0)
|
||||
check_value_pool(self.nodes[3], SHIELDED_POOL, 0)
|
||||
|
||||
# Send will fail because we are enforcing the consensus rule that
|
||||
# coinbase utxos can only be sent to a zaddr.
|
||||
errorString = ""
|
||||
try:
|
||||
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Coinbase funds can only be sent to a zaddr" in errorString, True)
|
||||
|
||||
@@ -88,18 +101,18 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
# as it's currently not possible to specify a change address in z_sendmany.
|
||||
recipients = []
|
||||
recipients.append({"address":myzaddr, "amount":Decimal('1.23456789')})
|
||||
|
||||
|
||||
myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
|
||||
error_result = wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "wallet does not allow any change", 10)
|
||||
|
||||
# Test that the returned status object contains a params field with the operation's input parameters
|
||||
assert_equal(error_result["method"], "z_sendmany")
|
||||
params = error_result["params"]
|
||||
assert_equal(params["fee"], Decimal('0.0001')) # default
|
||||
assert_equal(params["minconf"], Decimal('1')) # default
|
||||
assert_equal(Decimal(params["fee"]), Decimal('0.0001')) # default
|
||||
assert_equal(Decimal(params["minconf"]), Decimal('1')) # default
|
||||
assert_equal(params["fromaddress"], mytaddr)
|
||||
assert_equal(params["amounts"][0]["address"], myzaddr)
|
||||
assert_equal(params["amounts"][0]["amount"], Decimal('1.23456789'))
|
||||
assert_equal(Decimal(params["amounts"][0]["amount"]), Decimal('1.23456789'))
|
||||
|
||||
# Add viewing key for myzaddr to Node 3
|
||||
myviewingkey = self.nodes[0].z_exportviewingkey(myzaddr)
|
||||
@@ -169,14 +182,17 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
assert_equal(Decimal(resp["private"]), Decimal('19.9999'))
|
||||
assert_equal(Decimal(resp["total"]), Decimal('39.9999'))
|
||||
|
||||
# The Sprout value pool should reflect the send
|
||||
sproutvalue = shieldvalue
|
||||
check_value_pool(self.nodes[0], 'sprout', sproutvalue)
|
||||
# The shielded value pool should reflect the send
|
||||
shieldedvalue = shieldvalue
|
||||
check_value_pool(self.nodes[0], SHIELDED_POOL, shieldedvalue)
|
||||
|
||||
# A custom fee of 0 is okay. Here the node will send the note value back to itself.
|
||||
recipients = []
|
||||
recipients.append({"address":myzaddr, "amount": Decimal('19.9999')})
|
||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, 1, Decimal('0.0'))
|
||||
# NB: the fee is passed as a JSON number, not a Decimal. authproxy serialises
|
||||
# Decimal as a JSON *string* and z_sendmany reads the fee with params[3].get_real(),
|
||||
# which only accepts VNUM -- see port notes. The value is unchanged.
|
||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, 1, 0.0)
|
||||
mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
|
||||
self.sync_all()
|
||||
self.nodes[1].generate(1)
|
||||
@@ -186,8 +202,8 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
assert_equal(Decimal(resp["private"]), Decimal('19.9999'))
|
||||
assert_equal(Decimal(resp["total"]), Decimal('39.9999'))
|
||||
|
||||
# The Sprout value pool should be unchanged
|
||||
check_value_pool(self.nodes[0], 'sprout', sproutvalue)
|
||||
# The shielded value pool should be unchanged
|
||||
check_value_pool(self.nodes[0], SHIELDED_POOL, shieldedvalue)
|
||||
|
||||
# convert note to transparent funds
|
||||
unshieldvalue = Decimal('10.0')
|
||||
@@ -206,12 +222,12 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
self.sync_all()
|
||||
|
||||
# check balances
|
||||
sproutvalue -= unshieldvalue + Decimal('0.0001')
|
||||
shieldedvalue -= unshieldvalue + Decimal('0.0001')
|
||||
resp = self.nodes[0].z_gettotalbalance()
|
||||
assert_equal(Decimal(resp["transparent"]), Decimal('30.0'))
|
||||
assert_equal(Decimal(resp["private"]), Decimal('9.9998'))
|
||||
assert_equal(Decimal(resp["total"]), Decimal('39.9998'))
|
||||
check_value_pool(self.nodes[0], 'sprout', sproutvalue)
|
||||
check_value_pool(self.nodes[0], SHIELDED_POOL, shieldedvalue)
|
||||
|
||||
# z_sendmany will return an error if there is transparent change output considered dust.
|
||||
# UTXO selection in z_sendmany sorts in ascending order, so smallest utxos are consumed first.
|
||||
@@ -226,7 +242,7 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
errorString = ""
|
||||
try:
|
||||
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 99999)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Insufficient funds" in errorString, True)
|
||||
|
||||
@@ -241,7 +257,7 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
# Send will fail because of insufficient funds unless sender uses coinbase utxos
|
||||
try:
|
||||
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 21)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
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)
|
||||
|
||||
@@ -256,7 +272,7 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
# 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.
|
||||
start_time = timeit.default_timer()
|
||||
for i in xrange(0,num_t_recipients):
|
||||
for i in range(0,num_t_recipients):
|
||||
newtaddr = self.nodes[2].getnewaddress()
|
||||
recipients.append({"address":newtaddr, "amount":amount_per_recipient})
|
||||
elapsed = timeit.default_timer() - start_time
|
||||
@@ -287,28 +303,30 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
|
||||
# check balance
|
||||
node2balance = amount_per_recipient * num_t_recipients
|
||||
sproutvalue -= node2balance + Decimal('0.0001')
|
||||
shieldedvalue -= node2balance + Decimal('0.0001')
|
||||
assert_equal(self.nodes[2].getbalance(), node2balance)
|
||||
check_value_pool(self.nodes[0], 'sprout', sproutvalue)
|
||||
check_value_pool(self.nodes[0], SHIELDED_POOL, shieldedvalue)
|
||||
|
||||
# Send will fail because fee is negative
|
||||
try:
|
||||
self.nodes[0].z_sendmany(myzaddr, recipients, 1, -1)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Amount out of range" in errorString, True)
|
||||
|
||||
# Send will fail because fee is larger than MAX_MONEY
|
||||
errorString = ""
|
||||
try:
|
||||
self.nodes[0].z_sendmany(myzaddr, recipients, 1, Decimal('21000000.00000001'))
|
||||
except JSONRPCException,e:
|
||||
self.nodes[0].z_sendmany(myzaddr, recipients, 1, float(Decimal('21000000.00000001')))
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Amount out of range" in errorString, True)
|
||||
|
||||
# Send will fail because fee is larger than sum of outputs
|
||||
errorString = ""
|
||||
try:
|
||||
self.nodes[0].z_sendmany(myzaddr, recipients, 1, (amount_per_recipient * num_t_recipients) + Decimal('0.00000001'))
|
||||
except JSONRPCException,e:
|
||||
self.nodes[0].z_sendmany(myzaddr, recipients, 1, float((amount_per_recipient * num_t_recipients) + Decimal('0.00000001')))
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("is greater than the sum of outputs" in errorString, True)
|
||||
|
||||
@@ -334,10 +352,10 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
send_amount = num_recipients * amount_per_recipient
|
||||
custom_fee = Decimal('0.00012345')
|
||||
zbalance = self.nodes[0].z_getbalance(myzaddr)
|
||||
for i in xrange(0,num_recipients):
|
||||
for i in range(0,num_recipients):
|
||||
newzaddr = self.nodes[2].z_getnewaddress()
|
||||
recipients.append({"address":newzaddr, "amount":amount_per_recipient})
|
||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, custom_fee)
|
||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, float(custom_fee))
|
||||
wait_and_assert_operationid_status(self.nodes[0], myopid)
|
||||
self.sync_all()
|
||||
self.nodes[1].generate(1)
|
||||
@@ -353,8 +371,8 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
|
||||
resp = self.nodes[0].z_getbalance(myzaddr)
|
||||
assert_equal(Decimal(resp), zbalance - custom_fee - send_amount)
|
||||
sproutvalue -= custom_fee
|
||||
check_value_pool(self.nodes[0], 'sprout', sproutvalue)
|
||||
shieldedvalue -= custom_fee
|
||||
check_value_pool(self.nodes[0], SHIELDED_POOL, shieldedvalue)
|
||||
|
||||
notes = self.nodes[0].z_listunspent(1, 99999, False, [myzaddr])
|
||||
sum_of_notes = sum([note["amount"] for note in notes])
|
||||
|
||||
Reference in New Issue
Block a user