Compare commits
3 Commits
af7d9e2300
...
6d282db216
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d282db216 | |||
| c5fde12485 | |||
| e2e10f6ef8 |
@@ -3,7 +3,7 @@
|
|||||||
.SH NAME
|
.SH NAME
|
||||||
dragonx-cli \- manual page for dragonx-cli v1.3.0
|
dragonx-cli \- manual page for dragonx-cli v1.3.0
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
DragonX RPC client version v1.3.0
|
DragonX RPC client version v1.3.0\-af7d9e230
|
||||||
.PP
|
.PP
|
||||||
In order to ensure you are adequately protecting your privacy when using
|
In order to ensure you are adequately protecting your privacy when using
|
||||||
DragonX, please see <https://dragonx.is/security/>.
|
DragonX, please see <https://dragonx.is/security/>.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
.SH NAME
|
.SH NAME
|
||||||
dragonx-tx \- manual page for dragonx-tx v1.3.0
|
dragonx-tx \- manual page for dragonx-tx v1.3.0
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
hush\-tx utility version v1.3.0
|
hush\-tx utility version v1.3.0\-af7d9e230
|
||||||
.SS "Usage:"
|
.SS "Usage:"
|
||||||
.TP
|
.TP
|
||||||
hush\-tx [options] <hex\-tx> [commands]
|
hush\-tx [options] <hex\-tx> [commands]
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
.SH NAME
|
.SH NAME
|
||||||
dragonxd \- manual page for dragonxd v1.3.0
|
dragonxd \- manual page for dragonxd v1.3.0
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
DragonX Daemon version v1.3.0
|
DragonX Daemon version v1.3.0\-af7d9e230
|
||||||
.PP
|
.PP
|
||||||
In order to ensure you are adequately protecting your privacy when using
|
In order to ensure you are adequately protecting your privacy when using
|
||||||
DragonX, please see <https://dragonx.is/security/>.
|
DragonX, please see <https://dragonx.is/security/>.
|
||||||
@@ -452,6 +452,13 @@ or create a wallet z\-address). Must be spendable by this wallet.
|
|||||||
Fee in puposhis for automatic coinbase\-shielding transactions (default:
|
Fee in puposhis for automatic coinbase\-shielding transactions (default:
|
||||||
10000)
|
10000)
|
||||||
.HP
|
.HP
|
||||||
|
\fB\-sietch\-min\-zouts=\fR<n>
|
||||||
|
.IP
|
||||||
|
Minimum number of shielded (Sapling) outputs Sietch adds to each
|
||||||
|
z_sendmany transaction as decoys, strengthening
|
||||||
|
amount/linkability privacy. Higher values add privacy at the cost
|
||||||
|
of larger transactions (default: 7, clamped to the range 3\-50)
|
||||||
|
.HP
|
||||||
\fB\-autoshieldminutxos\fR
|
\fB\-autoshieldminutxos\fR
|
||||||
.IP
|
.IP
|
||||||
Only auto\-shield once at least this many matured coinbase UTXOs exist
|
Only auto\-shield once at least this many matured coinbase UTXOs exist
|
||||||
@@ -710,6 +717,11 @@ Stratum server options:
|
|||||||
.IP
|
.IP
|
||||||
Enable stratum server (default: off)
|
Enable stratum server (default: off)
|
||||||
.HP
|
.HP
|
||||||
|
\fB\-stratumtarget=\fR<hex>
|
||||||
|
.IP
|
||||||
|
Pool share target (64\-hex, big\-endian; larger = easier). Default is the
|
||||||
|
diff\-1 target. Useful for solo/low\-difficulty mining.
|
||||||
|
.HP
|
||||||
\fB\-stratumaddress=\fR<address>
|
\fB\-stratumaddress=\fR<address>
|
||||||
.IP
|
.IP
|
||||||
Mining address to use when special address of 'x' is sent by miner
|
Mining address to use when special address of 'x' is sent by miner
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2016-2024 The Hush developers
|
# Copyright (c) 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2016 The Zcash developers
|
# Copyright (c) 2016 The Zcash developers
|
||||||
# Distributed under the GPLv3 software license, see the accompanying
|
# Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2016-2024 The Hush developers
|
# Copyright (c) 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2014 The Bitcoin Core developers
|
# Copyright (c) 2014 The Bitcoin Core developers
|
||||||
# Distributed under the GPLv3 software license, see the accompanying
|
# Distributed under the GPLv3 software license, see the accompanying
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.authproxy import JSONRPCException
|
from test_framework.authproxy import JSONRPCException
|
||||||
|
from test_framework.util import initialize_chain_clean, start_node
|
||||||
|
|
||||||
from binascii import a2b_hex, b2a_hex
|
from binascii import a2b_hex, b2a_hex
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
@@ -69,14 +70,43 @@ def genmrklroot(leaflist):
|
|||||||
cur = n
|
cur = n
|
||||||
return cur[0]
|
return cur[0]
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Sapling v4 transaction layout.
|
||||||
|
#
|
||||||
|
# This test was written against the pre-Overwinter serialization, where a tx
|
||||||
|
# began with a 4-byte nVersion immediately followed by the vin count, so the
|
||||||
|
# first input's prevout hash lived at offset 4+1. DragonX transactions are
|
||||||
|
# Sapling v4: 4-byte header (nVersion | fOverwintered) + 4-byte nVersionGroupId
|
||||||
|
# + vin count, so the prevout hash starts 4 bytes further in. Poking the old
|
||||||
|
# offset corrupts nVersionGroupId and every proposal below just comes back
|
||||||
|
# "Block decode failed" instead of exercising any consensus rule.
|
||||||
|
CB_PREVOUT_OFF = 4+4+1
|
||||||
|
# Likewise the tx no longer ends at nLockTime: nExpiryHeight (4), valueBalance
|
||||||
|
# (8) and the empty vShieldedSpend/vShieldedOutput/vJoinSplit counts (1 each)
|
||||||
|
# trail it, so nLockTime is the 4 bytes at [-19:-15].
|
||||||
|
TX_TAIL_AFTER_LOCKTIME = 4+8+1+1+1
|
||||||
|
|
||||||
|
def tx_seq_off(tx):
|
||||||
|
"""Offset of the first input's nSequence in a Sapling v4 tx."""
|
||||||
|
scriptlen_off = CB_PREVOUT_OFF + 32 + 4 # after prevout hash + prevout.n
|
||||||
|
return scriptlen_off + 1 + tx[scriptlen_off]
|
||||||
|
|
||||||
|
def tx_vout0_value_off(tx):
|
||||||
|
"""Offset of the first output's 8-byte value in a Sapling v4 tx."""
|
||||||
|
return tx_seq_off(tx) + 4 + 1 # after nSequence + vout count
|
||||||
|
|
||||||
def template_to_bytes(tmpl, txlist):
|
def template_to_bytes(tmpl, txlist):
|
||||||
blkver = pack('<L', tmpl['version'])
|
blkver = pack('<L', tmpl['version'])
|
||||||
mrklroot = genmrklroot(list(dblsha(a) for a in txlist))
|
mrklroot = genmrklroot(list(dblsha(a) for a in txlist))
|
||||||
reserved = b'\0'*32
|
# hashFinalSaplingRoot. The all-zeroes placeholder this test used predates
|
||||||
|
# Sapling; a header carrying the wrong root is rejected with
|
||||||
|
# 'bad-sapling-root-in-block', which would sink even Test 11 (valid block).
|
||||||
|
reserved = a2b_hex(tmpl['finalsaplingroothash'])[::-1]
|
||||||
timestamp = pack('<L', tmpl['curtime'])
|
timestamp = pack('<L', tmpl['curtime'])
|
||||||
nonce = b'\0'*32
|
nonce = b'\0'*32
|
||||||
soln = b'\0'
|
soln = b'\0'
|
||||||
blk = blkver + a2b_hex(tmpl['previousblockhash'])[::-1] + mrklroot + reserved + timestamp + a2b_hex(tmpl['bits'])[::-1] + nonce + soln
|
# bytearray, not bytes: Test 9 mutates one byte of the result in place.
|
||||||
|
blk = bytearray(blkver + a2b_hex(tmpl['previousblockhash'])[::-1] + mrklroot + reserved + timestamp + a2b_hex(tmpl['bits'])[::-1] + nonce + soln)
|
||||||
blk += varlenEncode(len(txlist))
|
blk += varlenEncode(len(txlist))
|
||||||
for tx in txlist:
|
for tx in txlist:
|
||||||
blk += tx
|
blk += tx
|
||||||
@@ -95,6 +125,20 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
|
|||||||
Test block proposals with getblocktemplate.
|
Test block proposals with getblocktemplate.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
def setup_chain(self):
|
||||||
|
print("Initializing test directory "+self.options.tmpdir)
|
||||||
|
initialize_chain_clean(self.options.tmpdir, 1)
|
||||||
|
|
||||||
|
def setup_network(self, split=False):
|
||||||
|
# -daaforkheight=0: ContextualCheckBlockHeader only enforces nBits for a
|
||||||
|
# smart chain above daaForkHeight, which defaults to
|
||||||
|
# ASSETCHAINS_RANDOMX_VALIDATION+62000 (millions of blocks) so that a
|
||||||
|
# fresh sync accepts DragonX's historical bad-nBits window. Without this
|
||||||
|
# flag Test 8 (bad bits) is unreachable at regtest heights and the
|
||||||
|
# daemon happily accepts a block with arbitrary nBits.
|
||||||
|
self.nodes = [ start_node(0, self.options.tmpdir, ['-daaforkheight=0']) ]
|
||||||
|
self.is_network_split = False
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
node = self.nodes[0]
|
node = self.nodes[0]
|
||||||
node.generate(1) # Mine a block to leave initial block download
|
node.generate(1) # Mine a block to leave initial block download
|
||||||
@@ -117,9 +161,9 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
|
|||||||
#txlist[0][4+1+36+1+1] -= 1
|
#txlist[0][4+1+36+1+1] -= 1
|
||||||
|
|
||||||
# Test 2: Bad input hash for gen tx
|
# Test 2: Bad input hash for gen tx
|
||||||
txlist[0][4+1] += 1
|
txlist[0][CB_PREVOUT_OFF] += 1
|
||||||
assert_template(node, tmpl, txlist, 'bad-cb-missing')
|
assert_template(node, tmpl, txlist, 'bad-cb-missing')
|
||||||
txlist[0][4+1] -= 1
|
txlist[0][CB_PREVOUT_OFF] -= 1
|
||||||
|
|
||||||
# Test 3: Truncated final tx
|
# Test 3: Truncated final tx
|
||||||
lastbyte = txlist[-1].pop()
|
lastbyte = txlist[-1].pop()
|
||||||
@@ -136,14 +180,33 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Test 5: Add an invalid tx to the end (non-duplicate)
|
# Test 5: Add an invalid tx to the end (non-duplicate)
|
||||||
txlist.append(bytearray(txlist[0]))
|
txlist.append(bytearray(txlist[0]))
|
||||||
txlist[-1][4+1] = b'\xff'
|
txlist[-1][CB_PREVOUT_OFF] = 0xff
|
||||||
|
# DragonX is a fully private chain (ASSETCHAINS_PRIVATE): a non-coinbase
|
||||||
|
# tx paying a positive amount to a t-addr is killed in CheckTransaction
|
||||||
|
# with 'bad-txns-acprivacy-chain' before ConnectBlock ever looks up its
|
||||||
|
# inputs. Zero the output value -- CheckTransaction exempts zero-value
|
||||||
|
# vouts -- so the tx survives to the missing-input check this case is
|
||||||
|
# actually about.
|
||||||
|
_val_off = tx_vout0_value_off(txlist[-1])
|
||||||
|
txlist[-1][_val_off:_val_off+8] = b'\0'*8
|
||||||
assert_template(node, tmpl, txlist, 'bad-txns-inputs-missingorspent')
|
assert_template(node, tmpl, txlist, 'bad-txns-inputs-missingorspent')
|
||||||
txlist.pop()
|
txlist.pop()
|
||||||
|
|
||||||
# Test 6: Future tx lock time
|
# Test 6: Future tx lock time
|
||||||
txlist[0][-4:] = b'\xff\xff\xff\xff'
|
# The server-supplied coinbase carries nSequence=0xffffffff, and
|
||||||
|
# IsFinalTx() short-circuits on all-final inputs, so a future nLockTime
|
||||||
|
# alone leaves the tx final and the block valid. (DragonX's IsFinalTx
|
||||||
|
# also whitelists 0xfffffffe below the Hush hardfork height, which
|
||||||
|
# regtest is.) Make the input genuinely non-final so the future
|
||||||
|
# nLockTime is the thing under test.
|
||||||
|
seq_off = tx_seq_off(txlist[0])
|
||||||
|
realseq = txlist[0][seq_off:seq_off+4]
|
||||||
|
txlist[0][seq_off:seq_off+4] = b'\0\0\0\0'
|
||||||
|
reallocktime = txlist[0][-TX_TAIL_AFTER_LOCKTIME-4:-TX_TAIL_AFTER_LOCKTIME]
|
||||||
|
txlist[0][-TX_TAIL_AFTER_LOCKTIME-4:-TX_TAIL_AFTER_LOCKTIME] = b'\xff\xff\xff\xff'
|
||||||
assert_template(node, tmpl, txlist, 'bad-txns-nonfinal')
|
assert_template(node, tmpl, txlist, 'bad-txns-nonfinal')
|
||||||
txlist[0][-4:] = b'\0\0\0\0'
|
txlist[0][-TX_TAIL_AFTER_LOCKTIME-4:-TX_TAIL_AFTER_LOCKTIME] = reallocktime
|
||||||
|
txlist[0][seq_off:seq_off+4] = realseq
|
||||||
|
|
||||||
# Test 7: Bad tx count
|
# Test 7: Bad tx count
|
||||||
txlist.append(b'')
|
txlist.append(b'')
|
||||||
@@ -171,7 +234,9 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
|
|||||||
tmpl['curtime'] = 0x7fffffff
|
tmpl['curtime'] = 0x7fffffff
|
||||||
assert_template(node, tmpl, txlist, 'time-too-new')
|
assert_template(node, tmpl, txlist, 'time-too-new')
|
||||||
tmpl['curtime'] = 0
|
tmpl['curtime'] = 0
|
||||||
assert_template(node, tmpl, txlist, 'time-too-old')
|
# DragonX split Bitcoin's 'time-too-old' into 'time-too-old-median'
|
||||||
|
# (block time <= prev MedianTimePast) and 'time-too-old-prevblock'.
|
||||||
|
assert_template(node, tmpl, txlist, 'time-too-old-median')
|
||||||
tmpl['curtime'] = realtime
|
tmpl['curtime'] = realtime
|
||||||
|
|
||||||
# Test 11: Valid block
|
# Test 11: Valid block
|
||||||
|
|||||||
@@ -148,14 +148,20 @@ def initialize_chain(test_dir):
|
|||||||
# Same two requirements as start_node(): -regtest must be a command-line flag (the
|
# Same two requirements as start_node(): -regtest must be a command-line flag (the
|
||||||
# conf key is ignored, and without it this cache node runs on MAINNET), and -asmap
|
# conf key is ignored, and without it this cache node runs on MAINNET), and -asmap
|
||||||
# must be absolute or dragonxd refuses to start.
|
# must be absolute or dragonxd refuses to start.
|
||||||
args = [ os.getenv("BITCOIND", "dragonxd"), "-regtest", "-connect=0", "-keypool=1", "-datadir="+datadir, "-discover=0" ]
|
# -connect=<anything> makes init.cpp soft-set -listen=0 ("parameter interaction: -connect
|
||||||
|
# set -> setting -listen=0"), so cache node0 never opened its p2p port and nodes 1-3 could
|
||||||
|
# never sync to it -- initialize_chain() then hung forever in sync_blocks(). Pass -listen
|
||||||
|
# and -bind explicitly (an explicit arg beats SoftSetBoolArg) and keep the loopback bind so
|
||||||
|
# the cache nodes stay off the public network.
|
||||||
|
args = [ os.getenv("BITCOIND", "src/dragonxd"), "-regtest", "-connect=0", "-keypool=1", "-datadir="+datadir, "-discover=0",
|
||||||
|
"-listen=1", "-bind=127.0.0.1", "-dnsseed=0" ]
|
||||||
_am = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../../asmap.dat")
|
_am = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../../asmap.dat")
|
||||||
if os.path.exists(_am):
|
if os.path.exists(_am):
|
||||||
args.append("-asmap=" + os.path.realpath(_am))
|
args.append("-asmap=" + os.path.realpath(_am))
|
||||||
if i > 0:
|
if i > 0:
|
||||||
args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
|
args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
|
||||||
bitcoind_processes[i] = subprocess.Popen(args)
|
bitcoind_processes[i] = subprocess.Popen(args)
|
||||||
cmd = os.getenv("BITCOINCLI", "dragonx-cli")
|
cmd = os.getenv("BITCOINCLI", "src/dragonx-cli")
|
||||||
cmd_args = cmd + " -datadir="+datadir + " -rpcwait getblockcount"
|
cmd_args = cmd + " -datadir="+datadir + " -rpcwait getblockcount"
|
||||||
if os.getenv("PYTHON_DEBUG", ""):
|
if os.getenv("PYTHON_DEBUG", ""):
|
||||||
print("initialize_chain: hushd started, calling: " + cmd_args)
|
print("initialize_chain: hushd started, calling: " + cmd_args)
|
||||||
@@ -198,10 +204,17 @@ def initialize_chain(test_dir):
|
|||||||
wait_bitcoinds()
|
wait_bitcoinds()
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
print("Cleaning up cache dir files")
|
print("Cleaning up cache dir files")
|
||||||
os.remove(log_filename("cache", i, "debug.log"))
|
# log_filename() points at <cache>/node<i>/regtest, but that IS the -datadir we passed;
|
||||||
os.remove(log_filename("cache", i, "db.log"))
|
# dragonxd writes its logs/peers.dat one level deeper, into the net-specific
|
||||||
os.remove(log_filename("cache", i, "peers.dat"))
|
# <datadir>/regtest subdir (same datadir-vs-netdir split that forced -asmap to be
|
||||||
os.remove(log_filename("cache", i, "fee_estimates.dat"))
|
# absolute in start_node). Try both, and tolerate files a node never created.
|
||||||
|
for name in ("debug.log", "db.log", "peers.dat", "fee_estimates.dat"):
|
||||||
|
for cand in (log_filename("cache", i, os.path.join("regtest", name)),
|
||||||
|
log_filename("cache", i, name)):
|
||||||
|
try:
|
||||||
|
os.remove(cand)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
from_dir = os.path.join("cache", "node"+str(i))
|
from_dir = os.path.join("cache", "node"+str(i))
|
||||||
@@ -352,7 +365,7 @@ def stop_nodes(nodes):
|
|||||||
del nodes[:] # Emptying array closes connections as a side effect
|
del nodes[:] # Emptying array closes connections as a side effect
|
||||||
|
|
||||||
def set_node_times(nodes, t):
|
def set_node_times(nodes, t):
|
||||||
print("Setting nodes time to " + t)
|
print("Setting nodes time to " + str(t))
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
node.setmocktime(t)
|
node.setmocktime(t)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2016-2024 The Hush developers
|
# Copyright (c) 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2014 The Bitcoin Core developers
|
# Copyright (c) 2014 The Bitcoin Core developers
|
||||||
# Distributed under the GPLv3 software license, see the accompanying
|
# Distributed under the GPLv3 software license, see the accompanying
|
||||||
@@ -20,8 +20,20 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
print("Initializing test directory "+self.options.tmpdir)
|
print("Initializing test directory "+self.options.tmpdir)
|
||||||
initialize_chain_clean(self.options.tmpdir, 4)
|
initialize_chain_clean(self.options.tmpdir, 4)
|
||||||
|
|
||||||
|
# PORT NOTE (DragonX/regtest, not a change of test intent):
|
||||||
|
# test_framework.start_node() hardcodes "-connect=0", and init.cpp turns that into
|
||||||
|
# "-connect set -> setting -listen=0". With listening off the nodes never bind their
|
||||||
|
# p2p port, so connect_nodes_bi() connects nothing at all (its version==0 poll loop
|
||||||
|
# exits immediately because there are no local peers) and the first sync_all() hangs
|
||||||
|
# forever. Passing -bind forces -listen back to 1. -dnsseed=0 keeps these regtest
|
||||||
|
# nodes from dialing the live DragonX network.
|
||||||
|
NET_ARGS = ["-listen=1", "-bind=127.0.0.1", "-dnsseed=0"]
|
||||||
|
|
||||||
|
def net_args(self, n, extra=None):
|
||||||
|
return [list(self.NET_ARGS) + list(extra or []) for _ in range(n)]
|
||||||
|
|
||||||
def setup_network(self, split=False):
|
def setup_network(self, split=False):
|
||||||
self.nodes = start_nodes(3, self.options.tmpdir)
|
self.nodes = start_nodes(3, self.options.tmpdir, self.net_args(3))
|
||||||
connect_nodes_bi(self.nodes,0,1)
|
connect_nodes_bi(self.nodes,0,1)
|
||||||
connect_nodes_bi(self.nodes,1,2)
|
connect_nodes_bi(self.nodes,1,2)
|
||||||
connect_nodes_bi(self.nodes,0,2)
|
connect_nodes_bi(self.nodes,0,2)
|
||||||
@@ -29,7 +41,7 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
def run_test (self):
|
def run_test (self):
|
||||||
print "Mining blocks..."
|
print("Mining blocks...")
|
||||||
|
|
||||||
self.nodes[0].generate(4)
|
self.nodes[0].generate(4)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
@@ -106,7 +118,7 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
signed_tx = self.nodes[2].signrawtransaction(raw_tx)
|
signed_tx = self.nodes[2].signrawtransaction(raw_tx)
|
||||||
try:
|
try:
|
||||||
self.nodes[2].sendrawtransaction(signed_tx["hex"])
|
self.nodes[2].sendrawtransaction(signed_tx["hex"])
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert("absurdly high fees" in errorString)
|
assert("absurdly high fees" in errorString)
|
||||||
assert("900000000 > 190000" in errorString)
|
assert("900000000 > 190000" in errorString)
|
||||||
@@ -186,7 +198,7 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
|
txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
|
||||||
sync_mempools(self.nodes)
|
sync_mempools(self.nodes)
|
||||||
|
|
||||||
self.nodes.append(start_node(3, self.options.tmpdir))
|
self.nodes.append(start_node(3, self.options.tmpdir, list(self.NET_ARGS)))
|
||||||
connect_nodes_bi(self.nodes, 0, 3)
|
connect_nodes_bi(self.nodes, 0, 3)
|
||||||
sync_blocks(self.nodes)
|
sync_blocks(self.nodes)
|
||||||
|
|
||||||
@@ -227,7 +239,7 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
#do some -walletbroadcast tests
|
#do some -walletbroadcast tests
|
||||||
stop_nodes(self.nodes)
|
stop_nodes(self.nodes)
|
||||||
wait_bitcoinds()
|
wait_bitcoinds()
|
||||||
self.nodes = start_nodes(3, self.options.tmpdir, [["-walletbroadcast=0"],["-walletbroadcast=0"],["-walletbroadcast=0"]])
|
self.nodes = start_nodes(3, self.options.tmpdir, self.net_args(3, ["-walletbroadcast=0"]))
|
||||||
connect_nodes_bi(self.nodes,0,1)
|
connect_nodes_bi(self.nodes,0,1)
|
||||||
connect_nodes_bi(self.nodes,1,2)
|
connect_nodes_bi(self.nodes,1,2)
|
||||||
connect_nodes_bi(self.nodes,0,2)
|
connect_nodes_bi(self.nodes,0,2)
|
||||||
@@ -256,7 +268,7 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
#restart the nodes with -walletbroadcast=1
|
#restart the nodes with -walletbroadcast=1
|
||||||
stop_nodes(self.nodes)
|
stop_nodes(self.nodes)
|
||||||
wait_bitcoinds()
|
wait_bitcoinds()
|
||||||
self.nodes = start_nodes(3, self.options.tmpdir)
|
self.nodes = start_nodes(3, self.options.tmpdir, self.net_args(3))
|
||||||
connect_nodes_bi(self.nodes,0,1)
|
connect_nodes_bi(self.nodes,0,1)
|
||||||
connect_nodes_bi(self.nodes,1,2)
|
connect_nodes_bi(self.nodes,1,2)
|
||||||
connect_nodes_bi(self.nodes,0,2)
|
connect_nodes_bi(self.nodes,0,2)
|
||||||
@@ -290,7 +302,7 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
num_t_recipients = 3000
|
num_t_recipients = 3000
|
||||||
amount_per_recipient = Decimal('0.00000001')
|
amount_per_recipient = Decimal('0.00000001')
|
||||||
errorString = ''
|
errorString = ''
|
||||||
for i in xrange(0,num_t_recipients):
|
for i in range(0,num_t_recipients):
|
||||||
newtaddr = self.nodes[2].getnewaddress()
|
newtaddr = self.nodes[2].getnewaddress()
|
||||||
recipients.append({"address":newtaddr, "amount":amount_per_recipient})
|
recipients.append({"address":newtaddr, "amount":amount_per_recipient})
|
||||||
|
|
||||||
@@ -305,7 +317,7 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
self.nodes[0].z_sendmany(myzaddr, recipients)
|
self.nodes[0].z_sendmany(myzaddr, recipients)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert("Too many outputs, size of raw transaction" in errorString)
|
assert("Too many outputs, size of raw transaction" in errorString)
|
||||||
|
|
||||||
@@ -314,10 +326,10 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
num_z_recipients = 50
|
num_z_recipients = 50
|
||||||
amount_per_recipient = Decimal('0.00000001')
|
amount_per_recipient = Decimal('0.00000001')
|
||||||
errorString = ''
|
errorString = ''
|
||||||
for i in xrange(0,num_t_recipients):
|
for i in range(0,num_t_recipients):
|
||||||
newtaddr = self.nodes[2].getnewaddress()
|
newtaddr = self.nodes[2].getnewaddress()
|
||||||
recipients.append({"address":newtaddr, "amount":amount_per_recipient})
|
recipients.append({"address":newtaddr, "amount":amount_per_recipient})
|
||||||
for i in xrange(0,num_z_recipients):
|
for i in range(0,num_z_recipients):
|
||||||
newzaddr = self.nodes[2].z_getnewaddress()
|
newzaddr = self.nodes[2].z_getnewaddress()
|
||||||
recipients.append({"address":newzaddr, "amount":amount_per_recipient})
|
recipients.append({"address":newzaddr, "amount":amount_per_recipient})
|
||||||
|
|
||||||
@@ -327,7 +339,7 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
self.nodes[0].z_sendmany(myzaddr, recipients)
|
self.nodes[0].z_sendmany(myzaddr, recipients)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert("size of raw transaction would be larger than limit" in errorString)
|
assert("size of raw transaction would be larger than limit" in errorString)
|
||||||
|
|
||||||
@@ -335,12 +347,12 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
num_z_recipients = 100
|
num_z_recipients = 100
|
||||||
amount_per_recipient = Decimal('0.00000001')
|
amount_per_recipient = Decimal('0.00000001')
|
||||||
errorString = ''
|
errorString = ''
|
||||||
for i in xrange(0,num_z_recipients):
|
for i in range(0,num_z_recipients):
|
||||||
newzaddr = self.nodes[2].z_getnewaddress()
|
newzaddr = self.nodes[2].z_getnewaddress()
|
||||||
recipients.append({"address":newzaddr, "amount":amount_per_recipient})
|
recipients.append({"address":newzaddr, "amount":amount_per_recipient})
|
||||||
try:
|
try:
|
||||||
self.nodes[0].z_sendmany(myzaddr, recipients)
|
self.nodes[0].z_sendmany(myzaddr, recipients)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert("Invalid parameter, too many zaddr outputs" in errorString)
|
assert("Invalid parameter, too many zaddr outputs" in errorString)
|
||||||
|
|
||||||
@@ -426,7 +438,7 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
errorString = ""
|
errorString = ""
|
||||||
try:
|
try:
|
||||||
txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1f-4")
|
txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1f-4")
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
|
|
||||||
assert_equal("Invalid amount" in errorString, True)
|
assert_equal("Invalid amount" in errorString, True)
|
||||||
@@ -434,7 +446,7 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
errorString = ""
|
errorString = ""
|
||||||
try:
|
try:
|
||||||
self.nodes[0].generate("2") #use a string to as block amount parameter must fail because it's not interpreted as amount
|
self.nodes[0].generate("2") #use a string to as block amount parameter must fail because it's not interpreted as amount
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
|
|
||||||
assert_equal("not an integer" in errorString, True)
|
assert_equal("not an integer" in errorString, True)
|
||||||
@@ -448,9 +460,9 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
|
myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
|
||||||
assert(myopid)
|
assert(myopid)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
print errorString
|
print(errorString)
|
||||||
assert(False)
|
assert(False)
|
||||||
|
|
||||||
# This fee is larger than the default fee and since amount=0
|
# This fee is larger than the default fee and since amount=0
|
||||||
@@ -462,7 +474,7 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee)
|
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert('Small transaction amount' in errorString)
|
assert('Small transaction amount' in errorString)
|
||||||
|
|
||||||
@@ -475,9 +487,9 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee)
|
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee)
|
||||||
assert(myopid)
|
assert(myopid)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
print errorString
|
print(errorString)
|
||||||
assert(False)
|
assert(False)
|
||||||
|
|
||||||
# Make sure amount=0, fee=0 transaction are valid to add to mempool
|
# Make sure amount=0, fee=0 transaction are valid to add to mempool
|
||||||
@@ -490,9 +502,9 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee)
|
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee)
|
||||||
assert(myopid)
|
assert(myopid)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
print errorString
|
print(errorString)
|
||||||
assert(False)
|
assert(False)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2016-2024 The Hush developers
|
# Copyright (c) 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2018 The Zcash developers
|
# Copyright (c) 2018 The Zcash developers
|
||||||
# Distributed under the GPLv3 software license, see the accompanying
|
# Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2016-2024 The Hush developers
|
# Copyright (c) 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2017 The Zcash developers
|
# Copyright (c) 2017 The Zcash developers
|
||||||
# Distributed under the GPLv3 software license, see the accompanying
|
# Distributed under the GPLv3 software license, see the accompanying
|
||||||
@@ -32,7 +32,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
|||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
def run_test (self):
|
def run_test (self):
|
||||||
print "Mining blocks..."
|
print("Mining blocks...")
|
||||||
|
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
do_not_shield_taddr = self.nodes[0].getnewaddress()
|
do_not_shield_taddr = self.nodes[0].getnewaddress()
|
||||||
@@ -81,7 +81,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
self.nodes[0].z_mergetoaddress("*", myzaddr)
|
self.nodes[0].z_mergetoaddress("*", myzaddr)
|
||||||
assert(False)
|
assert(False)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("JSON value is not an array as expected" in errorString, True)
|
assert_equal("JSON value is not an array as expected" in errorString, True)
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
self.nodes[2].z_mergetoaddress([mytaddr], myzaddr)
|
self.nodes[2].z_mergetoaddress([mytaddr], myzaddr)
|
||||||
assert(False)
|
assert(False)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Could not find any funds to merge" in errorString, True)
|
assert_equal("Could not find any funds to merge" in errorString, True)
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, -1)
|
self.nodes[0].z_mergetoaddress(["*"], myzaddr, -1)
|
||||||
assert(False)
|
assert(False)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Amount out of range" in errorString, True)
|
assert_equal("Amount out of range" in errorString, True)
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('21000000.00000001'))
|
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('21000000.00000001'))
|
||||||
assert(False)
|
assert(False)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Amount out of range" in errorString, True)
|
assert_equal("Amount out of range" in errorString, True)
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, 999)
|
self.nodes[0].z_mergetoaddress(["*"], myzaddr, 999)
|
||||||
assert(False)
|
assert(False)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Insufficient funds" in errorString, True)
|
assert_equal("Insufficient funds" in errorString, True)
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), -1)
|
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), -1)
|
||||||
assert(False)
|
assert(False)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Limit on maximum number of UTXOs cannot be negative" in errorString, True)
|
assert_equal("Limit on maximum number of UTXOs cannot be negative" in errorString, True)
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), 99999999999999)
|
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), 99999999999999)
|
||||||
assert(False)
|
assert(False)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("JSON integer out of range" in errorString, True)
|
assert_equal("JSON integer out of range" in errorString, True)
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), 50, -1)
|
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), 50, -1)
|
||||||
assert(False)
|
assert(False)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Limit on maximum number of notes cannot be negative" in errorString, True)
|
assert_equal("Limit on maximum number of notes cannot be negative" in errorString, True)
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), 50, 99999999999999)
|
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), 50, 99999999999999)
|
||||||
assert(False)
|
assert(False)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("JSON integer out of range" in errorString, True)
|
assert_equal("JSON integer out of range" in errorString, True)
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
|||||||
try:
|
try:
|
||||||
self.nodes[0].z_mergetoaddress([mytaddr], mytaddr)
|
self.nodes[0].z_mergetoaddress([mytaddr], mytaddr)
|
||||||
assert(False)
|
assert(False)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Destination address is also the only source address, and all its funds are already merged" in errorString, True)
|
assert_equal("Destination address is also the only source address, and all its funds are already merged" in errorString, True)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2016-2024 The Hush developers
|
# Copyright (c) 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2016 The Zcash developers
|
# Copyright (c) 2016 The Zcash developers
|
||||||
# Distributed under the GPLv3 software license, see the accompanying
|
# Distributed under the GPLv3 software license, see the accompanying
|
||||||
@@ -7,15 +7,71 @@
|
|||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import assert_equal, assert_true, bitcoind_processes, \
|
from test_framework.util import assert_equal, assert_true, bitcoind_processes, \
|
||||||
connect_nodes_bi, start_node, start_nodes, wait_and_assert_operationid_status
|
connect_nodes_bi, initialize_chain_clean, p2p_port, start_node, start_nodes, \
|
||||||
|
sync_blocks, wait_and_assert_operationid_status
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
class WalletNullifiersTest (BitcoinTestFramework):
|
class WalletNullifiersTest (BitcoinTestFramework):
|
||||||
|
|
||||||
|
# The framework default setup_chain() calls initialize_chain(), which pre-builds a
|
||||||
|
# 200-block chain in a *relative* "cache/" directory shared by every test process
|
||||||
|
# running out of this tree. That directory is guarded only by the datadir lock, so two
|
||||||
|
# qa/rpc-tests running at once collide on it and the second one hangs forever inside
|
||||||
|
# "dragonx-cli -rpcwait" (observed here while a sibling test held cache/node0..3).
|
||||||
|
# Build the identical pre-condition -- 4 nodes, two rounds of 25 blocks each, i.e. 25
|
||||||
|
# mature + 25 immature coinbases per node -- directly in this test's private tmpdir.
|
||||||
|
# This is a setup change only: no assertion below is relaxed, removed or reordered.
|
||||||
|
def setup_chain(self):
|
||||||
|
print("Initializing test directory "+self.options.tmpdir)
|
||||||
|
initialize_chain_clean(self.options.tmpdir, 4)
|
||||||
|
|
||||||
|
# Three networking facts about this daemon force extra flags here. None of them
|
||||||
|
# change what the test exercises; without them the 4 nodes either never peer with
|
||||||
|
# each other, or peer with the LIVE DragonX network instead.
|
||||||
|
#
|
||||||
|
# 1. start_node() hardcodes "-connect=0", which also soft-sets -listen=0, so nothing
|
||||||
|
# binds p2p_port(i) and connect_nodes_bi() can never form the regtest mesh --
|
||||||
|
# sync_blocks() then spins forever (observed: node0 at 25 blocks, nodes 1-3 stuck
|
||||||
|
# at 0, nothing listening on 11005-11008). -listen=1 -bind=127.0.0.1 restores the
|
||||||
|
# mesh and keeps it on loopback.
|
||||||
|
# 2. hush_args() appends node1..node10.dragonx.is to -addnode unconditionally, -regtest
|
||||||
|
# included, and regtest reuses mainnet's network magic. A "regtest" node therefore
|
||||||
|
# joins the live network: node0 of an earlier run handshook 8 production peers
|
||||||
|
# ("receive version message: /DragonX:1.0.3/ ... blocks=3254266") and ingested their
|
||||||
|
# headers. -dns=0 stops those hostname -addnode entries from resolving; RPC addnode
|
||||||
|
# with a numeric 127.0.0.1:port is unaffected.
|
||||||
|
# 3. hush_args() runs BEFORE the config file is read, so its GetArg("-port",0) never
|
||||||
|
# sees the "port=" line initialize_datadir() wrote and GetDefaultPort() stays at the
|
||||||
|
# mainnet p2p port. "-connect=0" is then parsed as the address 0.0.0.0:<mainnet
|
||||||
|
# port>, i.e. the production dragonxd listening on this box -- every node in runs 2
|
||||||
|
# and 3 picked up exactly one peer reporting blocks=3254269. Repeating -port on the
|
||||||
|
# command line points GetDefaultPort() at this node's own regtest port instead.
|
||||||
|
#
|
||||||
|
# -autoshield is on by default on DragonX and is not part of what this test measures:
|
||||||
|
# a background thread sweeps each node's matured coinbase into a seed-derived zaddr
|
||||||
|
# (8 "autoshield operation finished" ops per node while the chain is being mined). That
|
||||||
|
# empties the very taddr this test spends from, and the resulting transactions do not
|
||||||
|
# settle identically on every node ("ERROR: AcceptToMemoryPool: ContextualCheckTransaction
|
||||||
|
# failed" on node1), so sync_mempools() never converges and the run wedges until the
|
||||||
|
# timeout. Turn the background sweeper off; the test does its own shielding explicitly.
|
||||||
|
def net_args(self, i):
|
||||||
|
return ['-listen=1', '-bind=127.0.0.1', '-dns=0', '-autoshield=0',
|
||||||
|
'-port=%d' % p2p_port(i)]
|
||||||
|
|
||||||
def setup_nodes(self):
|
def setup_nodes(self):
|
||||||
return start_nodes(4, self.options.tmpdir,
|
return start_nodes(4, self.options.tmpdir,
|
||||||
extra_args=[['-experimentalfeatures', '-developerencryptwallet']] * 4)
|
extra_args=[['-experimentalfeatures', '-developerencryptwallet']
|
||||||
|
+ self.net_args(i) for i in range(4)])
|
||||||
|
|
||||||
|
def setup_network(self, split = False):
|
||||||
|
super().setup_network(split)
|
||||||
|
# Same block layout initialize_chain() would have handed us.
|
||||||
|
for _ in range(2):
|
||||||
|
for peer in range(4):
|
||||||
|
self.nodes[peer].generate(25)
|
||||||
|
sync_blocks(self.nodes)
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
def run_test (self):
|
def run_test (self):
|
||||||
# add zaddr to node 0
|
# add zaddr to node 0
|
||||||
@@ -44,7 +100,7 @@ class WalletNullifiersTest (BitcoinTestFramework):
|
|||||||
bitcoind_processes[1].wait()
|
bitcoind_processes[1].wait()
|
||||||
|
|
||||||
# restart node 1
|
# restart node 1
|
||||||
self.nodes[1] = start_node(1, self.options.tmpdir)
|
self.nodes[1] = start_node(1, self.options.tmpdir, self.net_args(1))
|
||||||
connect_nodes_bi(self.nodes, 0, 1)
|
connect_nodes_bi(self.nodes, 0, 1)
|
||||||
connect_nodes_bi(self.nodes, 1, 2)
|
connect_nodes_bi(self.nodes, 1, 2)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2016-2024 The Hush developers
|
# Copyright (c) 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2018 The Zcash developers
|
# Copyright (c) 2018 The Zcash developers
|
||||||
# Distributed under the GPLv3 software license, see the accompanying
|
# Distributed under the GPLv3 software license, see the accompanying
|
||||||
@@ -13,6 +13,29 @@ from test_framework.util import (
|
|||||||
)
|
)
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
|
def get_value_pool(pools, pool_id):
|
||||||
|
"""
|
||||||
|
Return the valuePools entry with the given id, or None if this chain does
|
||||||
|
not have that pool. DragonX's getblockchaininfo only reports the Sapling
|
||||||
|
pool (no Sprout history exists on this chain), so the pools list can no
|
||||||
|
longer be indexed positionally the way the upstream test did.
|
||||||
|
"""
|
||||||
|
for pool in pools:
|
||||||
|
if pool['id'] == pool_id:
|
||||||
|
return pool
|
||||||
|
return None
|
||||||
|
|
||||||
|
def assert_pool_values(pools, sprout_value, sapling_value):
|
||||||
|
sprout = get_value_pool(pools, 'sprout')
|
||||||
|
if sprout is not None:
|
||||||
|
assert_equal(sprout['chainValue'], sprout_value)
|
||||||
|
else:
|
||||||
|
# No Sprout pool at all is the same statement as "the Sprout pool holds nothing"
|
||||||
|
assert_equal(sprout_value, Decimal('0'))
|
||||||
|
sapling = get_value_pool(pools, 'sapling')
|
||||||
|
assert_true(sapling is not None, "Sapling value pool missing from getblockchaininfo")
|
||||||
|
assert_equal(sapling['chainValue'], sapling_value)
|
||||||
|
|
||||||
class WalletPersistenceTest (BitcoinTestFramework):
|
class WalletPersistenceTest (BitcoinTestFramework):
|
||||||
|
|
||||||
def setup_chain(self):
|
def setup_chain(self):
|
||||||
@@ -20,8 +43,20 @@ class WalletPersistenceTest (BitcoinTestFramework):
|
|||||||
initialize_chain_clean(self.options.tmpdir, 3)
|
initialize_chain_clean(self.options.tmpdir, 3)
|
||||||
|
|
||||||
def setup_network(self, split=False):
|
def setup_network(self, split=False):
|
||||||
|
# -listen=1/-bind: the framework's start_node() passes -connect=0, and DragonX (like
|
||||||
|
# Bitcoin) reacts to -connect by soft-setting -listen=0. A non-listening node can never
|
||||||
|
# accept the "addnode 127.0.0.1:<port>" that connect_nodes_bi() issues, so without this
|
||||||
|
# the three nodes stay isolated and sync_all() spins forever. -bind keeps the listener on
|
||||||
|
# loopback so a regtest node never becomes reachable from the public internet.
|
||||||
self.nodes = start_nodes(3, self.options.tmpdir,
|
self.nodes = start_nodes(3, self.options.tmpdir,
|
||||||
extra_args=[[
|
extra_args=[[
|
||||||
|
'-listen=1',
|
||||||
|
'-bind=127.0.0.1',
|
||||||
|
# -dns=0: DragonX appends node1..node10.dragonx.is to -addnode for every chain
|
||||||
|
# named DRAGONX (hush_utils.h), and -connect=0 does not suppress -addnode. Without
|
||||||
|
# this a regtest node dials the LIVE DragonX network and is fed mainnet headers.
|
||||||
|
# The addnode calls connect_nodes_bi() makes use literal IPs, so they still work.
|
||||||
|
'-dns=0',
|
||||||
'-nuparams=5ba81b19:100', # Overwinter
|
'-nuparams=5ba81b19:100', # Overwinter
|
||||||
'-nuparams=76b809bb:201', # Sapling
|
'-nuparams=76b809bb:201', # Sapling
|
||||||
]] * 3)
|
]] * 3)
|
||||||
@@ -72,8 +107,7 @@ class WalletPersistenceTest (BitcoinTestFramework):
|
|||||||
|
|
||||||
# Verify size of shielded pools
|
# Verify size of shielded pools
|
||||||
pools = self.nodes[0].getblockchaininfo()['valuePools']
|
pools = self.nodes[0].getblockchaininfo()['valuePools']
|
||||||
assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout
|
assert_pool_values(pools, Decimal('0'), Decimal('20'))
|
||||||
assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling
|
|
||||||
|
|
||||||
# Restart the nodes
|
# Restart the nodes
|
||||||
stop_nodes(self.nodes)
|
stop_nodes(self.nodes)
|
||||||
@@ -82,8 +116,7 @@ class WalletPersistenceTest (BitcoinTestFramework):
|
|||||||
|
|
||||||
# Verify size of shielded pools
|
# Verify size of shielded pools
|
||||||
pools = self.nodes[0].getblockchaininfo()['valuePools']
|
pools = self.nodes[0].getblockchaininfo()['valuePools']
|
||||||
assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout
|
assert_pool_values(pools, Decimal('0'), Decimal('20'))
|
||||||
assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling
|
|
||||||
|
|
||||||
# Node 0 sends some shielded funds to Node 1
|
# Node 0 sends some shielded funds to Node 1
|
||||||
dest_addr = self.nodes[1].z_getnewaddress('sapling')
|
dest_addr = self.nodes[1].z_getnewaddress('sapling')
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2016-2024 The Hush developers
|
# Copyright (c) 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2016 The Zcash developers
|
# Copyright (c) 2016 The Zcash developers
|
||||||
# Distributed under the GPLv3 software license, see the accompanying
|
# Distributed under the GPLv3 software license, see the accompanying
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.authproxy import JSONRPCException
|
from test_framework.authproxy import JSONRPCException
|
||||||
from test_framework.mininode import COIN
|
|
||||||
from test_framework.util import assert_equal, initialize_chain_clean, \
|
from test_framework.util import assert_equal, initialize_chain_clean, \
|
||||||
start_nodes, connect_nodes_bi, wait_and_assert_operationid_status
|
start_nodes, connect_nodes_bi, wait_and_assert_operationid_status
|
||||||
|
|
||||||
@@ -14,6 +13,20 @@ import sys
|
|||||||
import timeit
|
import timeit
|
||||||
from decimal import Decimal
|
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):
|
def check_value_pool(node, name, total):
|
||||||
value_pools = node.getblockchaininfo()['valuePools']
|
value_pools = node.getblockchaininfo()['valuePools']
|
||||||
found = False
|
found = False
|
||||||
@@ -42,7 +55,7 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
|||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
def run_test (self):
|
def run_test (self):
|
||||||
print "Mining blocks..."
|
print("Mining blocks...")
|
||||||
|
|
||||||
self.nodes[0].generate(4)
|
self.nodes[0].generate(4)
|
||||||
|
|
||||||
@@ -59,17 +72,17 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
|||||||
assert_equal(self.nodes[2].getbalance(), 0)
|
assert_equal(self.nodes[2].getbalance(), 0)
|
||||||
assert_equal(self.nodes[3].getbalance(), 0)
|
assert_equal(self.nodes[3].getbalance(), 0)
|
||||||
|
|
||||||
check_value_pool(self.nodes[0], 'sprout', 0)
|
check_value_pool(self.nodes[0], SHIELDED_POOL, 0)
|
||||||
check_value_pool(self.nodes[1], 'sprout', 0)
|
check_value_pool(self.nodes[1], SHIELDED_POOL, 0)
|
||||||
check_value_pool(self.nodes[2], 'sprout', 0)
|
check_value_pool(self.nodes[2], SHIELDED_POOL, 0)
|
||||||
check_value_pool(self.nodes[3], 'sprout', 0)
|
check_value_pool(self.nodes[3], SHIELDED_POOL, 0)
|
||||||
|
|
||||||
# Send will fail because we are enforcing the consensus rule that
|
# Send will fail because we are enforcing the consensus rule that
|
||||||
# coinbase utxos can only be sent to a zaddr.
|
# coinbase utxos can only be sent to a zaddr.
|
||||||
errorString = ""
|
errorString = ""
|
||||||
try:
|
try:
|
||||||
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1)
|
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Coinbase funds can only be sent to a zaddr" in errorString, True)
|
assert_equal("Coinbase funds can only be sent to a zaddr" in errorString, True)
|
||||||
|
|
||||||
@@ -95,11 +108,11 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
|||||||
# Test that the returned status object contains a params field with the operation's input parameters
|
# Test that the returned status object contains a params field with the operation's input parameters
|
||||||
assert_equal(error_result["method"], "z_sendmany")
|
assert_equal(error_result["method"], "z_sendmany")
|
||||||
params = error_result["params"]
|
params = error_result["params"]
|
||||||
assert_equal(params["fee"], Decimal('0.0001')) # default
|
assert_equal(Decimal(params["fee"]), Decimal('0.0001')) # default
|
||||||
assert_equal(params["minconf"], Decimal('1')) # default
|
assert_equal(Decimal(params["minconf"]), Decimal('1')) # default
|
||||||
assert_equal(params["fromaddress"], mytaddr)
|
assert_equal(params["fromaddress"], mytaddr)
|
||||||
assert_equal(params["amounts"][0]["address"], myzaddr)
|
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
|
# Add viewing key for myzaddr to Node 3
|
||||||
myviewingkey = self.nodes[0].z_exportviewingkey(myzaddr)
|
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["private"]), Decimal('19.9999'))
|
||||||
assert_equal(Decimal(resp["total"]), Decimal('39.9999'))
|
assert_equal(Decimal(resp["total"]), Decimal('39.9999'))
|
||||||
|
|
||||||
# The Sprout value pool should reflect the send
|
# The shielded value pool should reflect the send
|
||||||
sproutvalue = shieldvalue
|
shieldedvalue = shieldvalue
|
||||||
check_value_pool(self.nodes[0], 'sprout', sproutvalue)
|
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.
|
# A custom fee of 0 is okay. Here the node will send the note value back to itself.
|
||||||
recipients = []
|
recipients = []
|
||||||
recipients.append({"address":myzaddr, "amount": Decimal('19.9999')})
|
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)
|
mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
self.nodes[1].generate(1)
|
self.nodes[1].generate(1)
|
||||||
@@ -186,8 +202,8 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
|||||||
assert_equal(Decimal(resp["private"]), Decimal('19.9999'))
|
assert_equal(Decimal(resp["private"]), Decimal('19.9999'))
|
||||||
assert_equal(Decimal(resp["total"]), Decimal('39.9999'))
|
assert_equal(Decimal(resp["total"]), Decimal('39.9999'))
|
||||||
|
|
||||||
# The Sprout value pool should be unchanged
|
# The shielded value pool should be unchanged
|
||||||
check_value_pool(self.nodes[0], 'sprout', sproutvalue)
|
check_value_pool(self.nodes[0], SHIELDED_POOL, shieldedvalue)
|
||||||
|
|
||||||
# convert note to transparent funds
|
# convert note to transparent funds
|
||||||
unshieldvalue = Decimal('10.0')
|
unshieldvalue = Decimal('10.0')
|
||||||
@@ -206,12 +222,12 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
|||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
# check balances
|
# check balances
|
||||||
sproutvalue -= unshieldvalue + Decimal('0.0001')
|
shieldedvalue -= unshieldvalue + Decimal('0.0001')
|
||||||
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('9.9998'))
|
assert_equal(Decimal(resp["private"]), Decimal('9.9998'))
|
||||||
assert_equal(Decimal(resp["total"]), Decimal('39.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.
|
# 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.
|
# UTXO selection in z_sendmany sorts in ascending order, so smallest utxos are consumed first.
|
||||||
@@ -226,7 +242,7 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
|||||||
errorString = ""
|
errorString = ""
|
||||||
try:
|
try:
|
||||||
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 99999)
|
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 99999)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Insufficient funds" in errorString, True)
|
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
|
# Send will fail because of insufficient funds unless sender uses coinbase utxos
|
||||||
try:
|
try:
|
||||||
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 21)
|
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 21)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
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)
|
||||||
|
|
||||||
@@ -256,7 +272,7 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
|||||||
# 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()
|
||||||
for i in xrange(0,num_t_recipients):
|
for i in range(0,num_t_recipients):
|
||||||
newtaddr = self.nodes[2].getnewaddress()
|
newtaddr = self.nodes[2].getnewaddress()
|
||||||
recipients.append({"address":newtaddr, "amount":amount_per_recipient})
|
recipients.append({"address":newtaddr, "amount":amount_per_recipient})
|
||||||
elapsed = timeit.default_timer() - start_time
|
elapsed = timeit.default_timer() - start_time
|
||||||
@@ -287,28 +303,30 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
|||||||
|
|
||||||
# check balance
|
# check balance
|
||||||
node2balance = amount_per_recipient * num_t_recipients
|
node2balance = amount_per_recipient * num_t_recipients
|
||||||
sproutvalue -= node2balance + Decimal('0.0001')
|
shieldedvalue -= node2balance + Decimal('0.0001')
|
||||||
assert_equal(self.nodes[2].getbalance(), node2balance)
|
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
|
# Send will fail because fee is negative
|
||||||
try:
|
try:
|
||||||
self.nodes[0].z_sendmany(myzaddr, recipients, 1, -1)
|
self.nodes[0].z_sendmany(myzaddr, recipients, 1, -1)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Amount out of range" in errorString, True)
|
assert_equal("Amount out of range" in errorString, True)
|
||||||
|
|
||||||
# Send will fail because fee is larger than MAX_MONEY
|
# Send will fail because fee is larger than MAX_MONEY
|
||||||
|
errorString = ""
|
||||||
try:
|
try:
|
||||||
self.nodes[0].z_sendmany(myzaddr, recipients, 1, Decimal('21000000.00000001'))
|
self.nodes[0].z_sendmany(myzaddr, recipients, 1, float(Decimal('21000000.00000001')))
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Amount out of range" in errorString, True)
|
assert_equal("Amount out of range" in errorString, True)
|
||||||
|
|
||||||
# Send will fail because fee is larger than sum of outputs
|
# Send will fail because fee is larger than sum of outputs
|
||||||
|
errorString = ""
|
||||||
try:
|
try:
|
||||||
self.nodes[0].z_sendmany(myzaddr, recipients, 1, (amount_per_recipient * num_t_recipients) + Decimal('0.00000001'))
|
self.nodes[0].z_sendmany(myzaddr, recipients, 1, float((amount_per_recipient * num_t_recipients) + Decimal('0.00000001')))
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("is greater than the sum of outputs" in errorString, True)
|
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
|
send_amount = num_recipients * amount_per_recipient
|
||||||
custom_fee = Decimal('0.00012345')
|
custom_fee = Decimal('0.00012345')
|
||||||
zbalance = self.nodes[0].z_getbalance(myzaddr)
|
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()
|
newzaddr = self.nodes[2].z_getnewaddress()
|
||||||
recipients.append({"address":newzaddr, "amount":amount_per_recipient})
|
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)
|
wait_and_assert_operationid_status(self.nodes[0], myopid)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
self.nodes[1].generate(1)
|
self.nodes[1].generate(1)
|
||||||
@@ -353,8 +371,8 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
|||||||
|
|
||||||
resp = self.nodes[0].z_getbalance(myzaddr)
|
resp = self.nodes[0].z_getbalance(myzaddr)
|
||||||
assert_equal(Decimal(resp), zbalance - custom_fee - send_amount)
|
assert_equal(Decimal(resp), zbalance - custom_fee - send_amount)
|
||||||
sproutvalue -= custom_fee
|
shieldedvalue -= custom_fee
|
||||||
check_value_pool(self.nodes[0], 'sprout', sproutvalue)
|
check_value_pool(self.nodes[0], SHIELDED_POOL, shieldedvalue)
|
||||||
|
|
||||||
notes = self.nodes[0].z_listunspent(1, 99999, False, [myzaddr])
|
notes = self.nodes[0].z_listunspent(1, 99999, False, [myzaddr])
|
||||||
sum_of_notes = sum([note["amount"] for note in notes])
|
sum_of_notes = sum([note["amount"] for note in notes])
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2016-2024 The Hush developers
|
# Copyright (c) 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2018 The Zcash developers
|
# Copyright (c) 2018 The Zcash developers
|
||||||
# Distributed under the GPLv3 software license, see the accompanying
|
# Distributed under the GPLv3 software license, see the accompanying
|
||||||
@@ -8,21 +8,99 @@ from test_framework.test_framework import BitcoinTestFramework
|
|||||||
from test_framework.authproxy import JSONRPCException
|
from test_framework.authproxy import JSONRPCException
|
||||||
from test_framework.util import (
|
from test_framework.util import (
|
||||||
assert_equal,
|
assert_equal,
|
||||||
start_nodes,
|
initialize_chain_clean,
|
||||||
|
p2p_port,
|
||||||
|
set_node_times,
|
||||||
|
start_node,
|
||||||
|
sync_blocks,
|
||||||
wait_and_assert_operationid_status,
|
wait_and_assert_operationid_status,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
# Test wallet behaviour with Sapling addresses
|
# Test wallet behaviour with Sapling addresses
|
||||||
class WalletSaplingTest(BitcoinTestFramework):
|
class WalletSaplingTest(BitcoinTestFramework):
|
||||||
|
|
||||||
|
def setup_chain(self):
|
||||||
|
# The shared initialize_chain() cache builder in test_framework/util.py has not been
|
||||||
|
# repaired for DragonX (it spawns the cache nodes by bare name off PATH, drives the
|
||||||
|
# CLI without -regtest so it dials the assetchain RPC port, and deletes debug.log
|
||||||
|
# from the non-net-specific datadir). Build the same starting state here instead --
|
||||||
|
# see _generate_starting_chain() -- so this test does not depend on it.
|
||||||
|
print("Initializing test directory " + self.options.tmpdir)
|
||||||
|
initialize_chain_clean(self.options.tmpdir, 4)
|
||||||
|
|
||||||
|
# !!! test_framework/util.py:start_node() hardcodes "-connect=0" into every regtest
|
||||||
|
# node's argv. Modern Bitcoin Core special-cases that value to mean "make no automatic
|
||||||
|
# connections", but THIS codebase does not (net.cpp ThreadOpenConnections just iterates
|
||||||
|
# mapMultiArgs["-connect"]), so "0" is dialled as a hostname: it resolves to 0.0.0.0,
|
||||||
|
# which on Linux connects to localhost on Params().GetDefaultPort() -- 21768, the live
|
||||||
|
# DRAGONX p2p port. Observed directly: a regtest node started by the unmodified
|
||||||
|
# framework peered with the production dragonxd on this host and with seven public
|
||||||
|
# mainnet nodes (heights ~3.25M) and began ingesting mainnet headers. "-connect" also
|
||||||
|
# soft-sets "-listen=0", so the framework's own connect_nodes_bi() can never establish
|
||||||
|
# the local links a multi-node test needs.
|
||||||
|
#
|
||||||
|
# Both problems are in the shared framework, which this port is not allowed to touch, so
|
||||||
|
# they are worked around per-node here: the daemon is launched through a tiny wrapper
|
||||||
|
# that strips the "-connect=0" argument, and the real topology/listening flags are passed
|
||||||
|
# as extra_args (which start_node appends after its own).
|
||||||
|
def _daemon_wrapper(self):
|
||||||
|
srcdir = os.path.join(
|
||||||
|
os.path.dirname(os.path.abspath(__file__)), "..", "..", "src", "dragonxd")
|
||||||
|
path = os.path.join(self.options.tmpdir, "dragonxd-no-connect0")
|
||||||
|
with open(path, "w") as f:
|
||||||
|
f.write("#!/usr/bin/env bash\n")
|
||||||
|
f.write("args=()\n")
|
||||||
|
f.write('for a in "$@"; do\n')
|
||||||
|
f.write(' if [ "$a" = "-connect=0" ]; then continue; fi\n')
|
||||||
|
f.write(' args+=("$a")\n')
|
||||||
|
f.write("done\n")
|
||||||
|
f.write('exec %s "${args[@]}"\n' % os.path.realpath(srcdir))
|
||||||
|
os.chmod(path, os.stat(path).st_mode | stat.S_IXUSR)
|
||||||
|
return path
|
||||||
|
|
||||||
def setup_nodes(self):
|
def setup_nodes(self):
|
||||||
return start_nodes(4, self.options.tmpdir, [[
|
binary = self._daemon_wrapper()
|
||||||
#'-nuparams=5ba81b19:201', # Overwinter
|
nodes = []
|
||||||
#'-nuparams=76b809bb:203', # Sapling
|
for i in range(4):
|
||||||
#'-experimentalfeatures', '-zmergetoaddress',
|
extra_args = [
|
||||||
]] * 4)
|
#'-nuparams=5ba81b19:201', # Overwinter
|
||||||
|
#'-nuparams=76b809bb:203', # Sapling
|
||||||
|
#'-experimentalfeatures', '-zmergetoaddress',
|
||||||
|
# Listen on this test's PID-keyed port so the nodes can actually peer with
|
||||||
|
# each other, and only ever dial each other -- never the public network.
|
||||||
|
'-listen=1',
|
||||||
|
'-bind=127.0.0.1',
|
||||||
|
'-port=%d' % p2p_port(i),
|
||||||
|
] + ['-connect=127.0.0.1:%d' % p2p_port(j) for j in range(4) if j != i]
|
||||||
|
nodes.append(start_node(i, self.options.tmpdir, extra_args, binary=binary))
|
||||||
|
return nodes
|
||||||
|
|
||||||
|
def setup_network(self, split=False):
|
||||||
|
super(WalletSaplingTest, self).setup_network(split)
|
||||||
|
self._generate_starting_chain()
|
||||||
|
|
||||||
|
def _generate_starting_chain(self):
|
||||||
|
# Equivalent of test_framework.util.initialize_chain(): a 200-block chain where each
|
||||||
|
# of the 4 nodes mined 25 blocks twice, so every node holds 25 mature and 25 immature
|
||||||
|
# coinbases. Block timestamps are 10 minutes apart starting 1 Jan 2014, as there.
|
||||||
|
block_time = 1388534400
|
||||||
|
for _round in range(2):
|
||||||
|
for peer in range(4):
|
||||||
|
for _j in range(25):
|
||||||
|
set_node_times(self.nodes, block_time)
|
||||||
|
self.nodes[peer].generate(1)
|
||||||
|
block_time += 10 * 75
|
||||||
|
# Must sync before next peer starts generating blocks
|
||||||
|
sync_blocks(self.nodes)
|
||||||
|
# Drop back to wall-clock time: initialize_chain() stops the cache nodes and the test
|
||||||
|
# then runs against freshly started nodes that have no mocktime set.
|
||||||
|
set_node_times(self.nodes, 0)
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
# Sanity-check the test harness
|
# Sanity-check the test harness
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2016-2024 The Hush developers
|
# Copyright (c) 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2017 The Zcash developers
|
# Copyright (c) 2017 The Zcash developers
|
||||||
# Distributed under the GPLv3 software license, see the accompanying
|
# Distributed under the GPLv3 software license, see the accompanying
|
||||||
@@ -22,8 +22,24 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework):
|
|||||||
initialize_chain_clean(self.options.tmpdir, 4)
|
initialize_chain_clean(self.options.tmpdir, 4)
|
||||||
|
|
||||||
def setup_network(self, split=False):
|
def setup_network(self, split=False):
|
||||||
args = ['-regtestprotectcoinbase', '-debug=zrpcunsafe']
|
# DragonX-specific environment flags. None of these change what the test
|
||||||
args2 = ['-regtestprotectcoinbase', '-debug=zrpcunsafe', "-mempooltxinputlimit=7"]
|
# asserts; without them the test cannot run at all on this daemon:
|
||||||
|
# -listen=1/-bind=127.0.0.1: the framework's start_node() always passes
|
||||||
|
# -connect=0, and AppInit2 soft-sets -listen=0 whenever -connect is
|
||||||
|
# present, so the nodes never listen and connect_nodes_bi() silently
|
||||||
|
# builds an empty topology (sync_all() then spins forever). An explicit
|
||||||
|
# -listen=1 beats the SoftSetBoolArg.
|
||||||
|
# -dnsseed=0: chainparams_commandline() keeps DRAGONX's DNS seeds and
|
||||||
|
# overwrites pchMessageStart with the DRAGONX chain magic on *every*
|
||||||
|
# network including regtest, so a regtest node otherwise dials and
|
||||||
|
# handshakes with live mainnet peers (observed: 8 mainnet peers,
|
||||||
|
# blocks=3254237, feeding mainnet headers into the regtest node).
|
||||||
|
# -autoshield=0: DragonX auto-shields matured coinbase every 25 blocks
|
||||||
|
# by default, which would race the manual z_shieldcoinbase calls under
|
||||||
|
# test and move the balances this test checks.
|
||||||
|
isolate = ['-listen=1', '-bind=127.0.0.1', '-dnsseed=0', '-autoshield=0']
|
||||||
|
args = ['-regtestprotectcoinbase', '-debug=zrpcunsafe'] + isolate
|
||||||
|
args2 = ['-regtestprotectcoinbase', '-debug=zrpcunsafe', "-mempooltxinputlimit=7"] + isolate
|
||||||
if self.addr_type != 'sprout':
|
if self.addr_type != 'sprout':
|
||||||
nu = [
|
nu = [
|
||||||
'-nuparams=5ba81b19:0', # Overwinter
|
'-nuparams=5ba81b19:0', # Overwinter
|
||||||
@@ -42,7 +58,7 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework):
|
|||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
def run_test (self):
|
def run_test (self):
|
||||||
print "Mining blocks..."
|
print("Mining blocks...")
|
||||||
|
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
@@ -73,42 +89,42 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework):
|
|||||||
self.nodes[2].importaddress(mytaddr)
|
self.nodes[2].importaddress(mytaddr)
|
||||||
try:
|
try:
|
||||||
self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr)
|
self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Could not find any coinbase funds to shield" in errorString, True)
|
assert_equal("Could not find any coinbase funds to shield" in errorString, True)
|
||||||
|
|
||||||
# Shielding will fail because fee is negative
|
# Shielding will fail because fee is negative
|
||||||
try:
|
try:
|
||||||
self.nodes[0].z_shieldcoinbase("*", myzaddr, -1)
|
self.nodes[0].z_shieldcoinbase("*", myzaddr, -1)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Amount out of range" in errorString, True)
|
assert_equal("Amount out of range" in errorString, True)
|
||||||
|
|
||||||
# Shielding will fail because fee is larger than MAX_MONEY
|
# Shielding will fail because fee is larger than MAX_MONEY
|
||||||
try:
|
try:
|
||||||
self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('21000000.00000001'))
|
self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('21000000.00000001'))
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Amount out of range" in errorString, True)
|
assert_equal("Amount out of range" in errorString, True)
|
||||||
|
|
||||||
# Shielding will fail because fee is larger than sum of utxos
|
# Shielding will fail because fee is larger than sum of utxos
|
||||||
try:
|
try:
|
||||||
self.nodes[0].z_shieldcoinbase("*", myzaddr, 999)
|
self.nodes[0].z_shieldcoinbase("*", myzaddr, 999)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Insufficient coinbase funds" in errorString, True)
|
assert_equal("Insufficient coinbase funds" in errorString, True)
|
||||||
|
|
||||||
# Shielding will fail because limit parameter must be at least 0
|
# Shielding will fail because limit parameter must be at least 0
|
||||||
try:
|
try:
|
||||||
self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), -1)
|
self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), -1)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("Limit on maximum number of utxos cannot be negative" in errorString, True)
|
assert_equal("Limit on maximum number of utxos cannot be negative" in errorString, True)
|
||||||
|
|
||||||
# Shielding will fail because limit parameter is absurdly large
|
# Shielding will fail because limit parameter is absurdly large
|
||||||
try:
|
try:
|
||||||
self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), 99999999999999)
|
self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), 99999999999999)
|
||||||
except JSONRPCException,e:
|
except JSONRPCException as e:
|
||||||
errorString = e.error['message']
|
errorString = e.error['message']
|
||||||
assert_equal("JSON integer out of range" in errorString, True)
|
assert_equal("JSON integer out of range" in errorString, True)
|
||||||
|
|
||||||
@@ -214,3 +230,13 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework):
|
|||||||
sync_mempools(self.nodes[:2])
|
sync_mempools(self.nodes[:2])
|
||||||
self.nodes[1].generate(1)
|
self.nodes[1].generate(1)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Upstream (Zcash/Hush) ran this test twice: once with Sprout zaddrs and once
|
||||||
|
# with Sapling. DragonX has no Sprout support at all -- z_getnewaddress only
|
||||||
|
# accepts "sapling" or "amnesia" (src/wallet/rpcwallet.cpp z_getnewaddress),
|
||||||
|
# so WalletShieldCoinbaseTest('sprout') cannot even allocate its target
|
||||||
|
# address. The sprout-only branches inside run_test() are kept intact for
|
||||||
|
# reference but only the sapling variant is executed.
|
||||||
|
print("Running for sapling...")
|
||||||
|
WalletShieldCoinbaseTest('sapling').main()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2016-2024 The Hush developers
|
# Copyright (c) 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2016 The Zcash developers
|
# Copyright (c) 2016 The Zcash developers
|
||||||
# Distributed under the GPLv3 software license, see the accompanying
|
# Distributed under the GPLv3 software license, see the accompanying
|
||||||
@@ -20,7 +20,16 @@ class WalletTreeStateTest (BitcoinTestFramework):
|
|||||||
|
|
||||||
# Start nodes with -regtestprotectcoinbase to set fCoinbaseMustBeProtected to true.
|
# Start nodes with -regtestprotectcoinbase to set fCoinbaseMustBeProtected to true.
|
||||||
def setup_network(self, split=False):
|
def setup_network(self, split=False):
|
||||||
self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-regtestprotectcoinbase','-debug=zrpc']] * 3 )
|
# -listen=1 and -dns=0 are DragonX-specific harness requirements, not part of the
|
||||||
|
# original test: start_node() passes -connect=0, which trips the "-connect set ->
|
||||||
|
# setting -listen=0" parameter interaction, so without -listen=1 the three nodes
|
||||||
|
# cannot open the p2p links connect_nodes_bi() asks for (node1/node2 stay at height
|
||||||
|
# 0 forever and sync_all() can never converge). -dns=0 blocks the unconditional
|
||||||
|
# node1..node10.dragonx.is -addnode injection in hush_args(), which otherwise dials
|
||||||
|
# the real DragonX seed nodes from regtest and floods these nodes with mainnet headers.
|
||||||
|
self.nodes = start_nodes(3, self.options.tmpdir,
|
||||||
|
extra_args=[['-regtestprotectcoinbase','-debug=zrpc',
|
||||||
|
'-listen=1','-dns=0']] * 3 )
|
||||||
connect_nodes_bi(self.nodes,0,1)
|
connect_nodes_bi(self.nodes,0,1)
|
||||||
connect_nodes_bi(self.nodes,1,2)
|
connect_nodes_bi(self.nodes,1,2)
|
||||||
connect_nodes_bi(self.nodes,0,2)
|
connect_nodes_bi(self.nodes,0,2)
|
||||||
@@ -28,7 +37,7 @@ class WalletTreeStateTest (BitcoinTestFramework):
|
|||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
def run_test (self):
|
def run_test (self):
|
||||||
print "Mining blocks..."
|
print("Mining blocks...")
|
||||||
|
|
||||||
self.nodes[0].generate(100)
|
self.nodes[0].generate(100)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
@@ -79,7 +88,7 @@ class WalletTreeStateTest (BitcoinTestFramework):
|
|||||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
|
myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
|
||||||
|
|
||||||
# Wait for Tx 2 to begin executing...
|
# Wait for Tx 2 to begin executing...
|
||||||
for x in xrange(1, 60):
|
for x in range(1, 60):
|
||||||
results = self.nodes[0].z_getoperationstatus([myopid])
|
results = self.nodes[0].z_getoperationstatus([myopid])
|
||||||
status = results[0]["status"]
|
status = results[0]["status"]
|
||||||
if status == "executing":
|
if status == "executing":
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2016-2024 The Hush developers
|
# Copyright (c) 2016-2024 The Hush developers
|
||||||
# Copyright (c) 2014 The Bitcoin Core developers
|
# Copyright (c) 2014 The Bitcoin Core developers
|
||||||
# Distributed under the GPLv3 software license, see the accompanying
|
# Distributed under the GPLv3 software license, see the accompanying
|
||||||
@@ -37,8 +37,8 @@ and confirm again balances are correct.
|
|||||||
from test_framework.test_framework import BitcoinTestFramework
|
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, initialize_chain_clean, \
|
from test_framework.util import assert_equal, initialize_chain_clean, \
|
||||||
start_nodes, start_node, connect_nodes, stop_node, \
|
start_nodes, start_node, connect_nodes, \
|
||||||
sync_blocks, sync_mempools
|
sync_blocks, sync_mempools, bitcoind_processes
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
@@ -48,6 +48,46 @@ import logging
|
|||||||
|
|
||||||
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
|
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
|
||||||
|
|
||||||
|
# Three node flags this test has to supply for itself, because test_framework.util.start_node()
|
||||||
|
# cannot give it a usable isolated regtest network on DragonX:
|
||||||
|
#
|
||||||
|
# -listen=1: start_node() passes "-connect=0" to every node. In DragonX (as in Bitcoin) the
|
||||||
|
# presence of a -connect argument SoftSetBoolArg()s -listen to false, so no test node ever
|
||||||
|
# binds its p2p port and connect_nodes() cannot build the loopback topology this test needs.
|
||||||
|
# Verified on a live run: only the RPC ports were listening and getpeerinfo showed zero
|
||||||
|
# 127.0.0.1 peers on all four nodes. SoftSetBoolArg does not override an explicit value.
|
||||||
|
#
|
||||||
|
# -dns=0: hush_args() unconditionally appends node1..node10.dragonx.is to -addnode whenever the
|
||||||
|
# chain name is DRAGONX, regardless of network, and -connect=0 does not suppress it. On a live
|
||||||
|
# run every "regtest" node ended up with 7-8 established connections to production mainnet
|
||||||
|
# nodes on port 21768, was flooded with mainnet headers ("AcceptBlockHeader: hashPrevBlock ...
|
||||||
|
# not found"), and one of them aborted on CheckBlockIndex(). -dns=0 stops the hostnames from
|
||||||
|
# resolving while leaving the literal 127.0.0.1:PORT addnodes connect_nodes() uses intact.
|
||||||
|
#
|
||||||
|
# -allowlist=127.0.0.1: "-connect=0" does not mean "no connections". The daemon resolves the
|
||||||
|
# literal "0" to 0.0.0.0 and dials it on the chain's default p2p port, i.e. 127.0.0.1:21768 --
|
||||||
|
# which on a machine that also runs a real node is the PRODUCTION daemon (observed:
|
||||||
|
# ESTAB 127.0.0.1:41282 -> 127.0.0.1:21768 from every test node, peer subver /DragonX:1.0.3/,
|
||||||
|
# startingheight 3254254). That peer is outbound, so it is the node's only preferred-download
|
||||||
|
# peer; main.cpp:8398 then computes fFetch=false for every inbound peer, and node3 -- which in
|
||||||
|
# this test's topology is dialed by everyone and dials no one -- never downloads an announced
|
||||||
|
# block, so sync_blocks() hangs forever. Allowlisting loopback makes inbound test peers
|
||||||
|
# preferred-download too (main.cpp:381), which restores block propagation.
|
||||||
|
LISTEN = "-listen=1"
|
||||||
|
NODNS = "-dns=0"
|
||||||
|
ALLOWLIST = "-allowlist=127.0.0.1"
|
||||||
|
|
||||||
|
|
||||||
|
def stop_node_and_reap(node, i):
|
||||||
|
# Equivalent to test_framework.util.stop_node(), which cannot be called: it does
|
||||||
|
# print("Stopping node " + i) with the int index that every caller passes, which raises
|
||||||
|
# TypeError. Reimplemented here rather than editing shared framework code other tests use.
|
||||||
|
print("Stopping node %d" % i)
|
||||||
|
node.stop()
|
||||||
|
bitcoind_processes[i].wait()
|
||||||
|
del bitcoind_processes[i]
|
||||||
|
|
||||||
|
|
||||||
class WalletBackupTest(BitcoinTestFramework):
|
class WalletBackupTest(BitcoinTestFramework):
|
||||||
|
|
||||||
def setup_chain(self):
|
def setup_chain(self):
|
||||||
@@ -62,7 +102,10 @@ class WalletBackupTest(BitcoinTestFramework):
|
|||||||
ed2 = "-exportdir=" + self.options.tmpdir + "/node2"
|
ed2 = "-exportdir=" + self.options.tmpdir + "/node2"
|
||||||
|
|
||||||
# nodes 1, 2,3 are spenders, let's give them a keypool=100
|
# nodes 1, 2,3 are spenders, let's give them a keypool=100
|
||||||
extra_args = [["-keypool=100", ed0], ["-keypool=100", ed1], ["-keypool=100", ed2], []]
|
extra_args = [["-keypool=100", ed0, LISTEN, NODNS, ALLOWLIST],
|
||||||
|
["-keypool=100", ed1, LISTEN, NODNS, ALLOWLIST],
|
||||||
|
["-keypool=100", ed2, LISTEN, NODNS, ALLOWLIST],
|
||||||
|
[LISTEN, NODNS, ALLOWLIST]]
|
||||||
self.nodes = start_nodes(4, self.options.tmpdir, extra_args)
|
self.nodes = start_nodes(4, self.options.tmpdir, extra_args)
|
||||||
connect_nodes(self.nodes[0], 3)
|
connect_nodes(self.nodes[0], 3)
|
||||||
connect_nodes(self.nodes[1], 3)
|
connect_nodes(self.nodes[1], 3)
|
||||||
@@ -95,18 +138,18 @@ class WalletBackupTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# As above, this mirrors the original bash test.
|
# As above, this mirrors the original bash test.
|
||||||
def start_three(self):
|
def start_three(self):
|
||||||
self.nodes[0] = start_node(0, self.options.tmpdir)
|
self.nodes[0] = start_node(0, self.options.tmpdir, [LISTEN, NODNS, ALLOWLIST])
|
||||||
self.nodes[1] = start_node(1, self.options.tmpdir)
|
self.nodes[1] = start_node(1, self.options.tmpdir, [LISTEN, NODNS, ALLOWLIST])
|
||||||
self.nodes[2] = start_node(2, self.options.tmpdir)
|
self.nodes[2] = start_node(2, self.options.tmpdir, [LISTEN, NODNS, ALLOWLIST])
|
||||||
connect_nodes(self.nodes[0], 3)
|
connect_nodes(self.nodes[0], 3)
|
||||||
connect_nodes(self.nodes[1], 3)
|
connect_nodes(self.nodes[1], 3)
|
||||||
connect_nodes(self.nodes[2], 3)
|
connect_nodes(self.nodes[2], 3)
|
||||||
connect_nodes(self.nodes[2], 0)
|
connect_nodes(self.nodes[2], 0)
|
||||||
|
|
||||||
def stop_three(self):
|
def stop_three(self):
|
||||||
stop_node(self.nodes[0], 0)
|
stop_node_and_reap(self.nodes[0], 0)
|
||||||
stop_node(self.nodes[1], 1)
|
stop_node_and_reap(self.nodes[1], 1)
|
||||||
stop_node(self.nodes[2], 2)
|
stop_node_and_reap(self.nodes[2], 2)
|
||||||
|
|
||||||
def erase_three(self):
|
def erase_three(self):
|
||||||
os.remove(self.options.tmpdir + "/node0/regtest/wallet.dat")
|
os.remove(self.options.tmpdir + "/node0/regtest/wallet.dat")
|
||||||
|
|||||||
27
src/chain.h
27
src/chain.h
@@ -113,10 +113,9 @@ enum BlockStatus: uint32_t {
|
|||||||
//! Scripts & signatures ok. Implies all parents are also at least SCRIPTS.
|
//! Scripts & signatures ok. Implies all parents are also at least SCRIPTS.
|
||||||
BLOCK_VALID_SCRIPTS = 5,
|
BLOCK_VALID_SCRIPTS = 5,
|
||||||
|
|
||||||
// flag to check if contextual check block has passed in Accept block, if it has not check at connect block.
|
|
||||||
BLOCK_VALID_CONTEXT = 6,
|
|
||||||
|
|
||||||
//! All validity bits.
|
//! All validity bits.
|
||||||
|
//! NOTE: the levels above are sequential VALUES occupying this 3-bit field, not independent
|
||||||
|
//! bits, so any flag stored in nStatus must live entirely outside this mask.
|
||||||
BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
|
BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
|
||||||
BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,
|
BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,
|
||||||
|
|
||||||
@@ -129,9 +128,29 @@ enum BlockStatus: uint32_t {
|
|||||||
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
|
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
|
||||||
|
|
||||||
BLOCK_ACTIVATES_UPGRADE = 128, //! block activates a network upgrade
|
BLOCK_ACTIVATES_UPGRADE = 128, //! block activates a network upgrade
|
||||||
BLOCK_IN_TMPFILE = 256
|
BLOCK_IN_TMPFILE = 256,
|
||||||
|
|
||||||
|
//! ContextualCheckBlock already passed in AcceptBlock, so ConnectBlock may skip re-running it.
|
||||||
|
//! Was 6 until v1.3.0, which put it INSIDE BLOCK_VALID_MASK (1|2|3|4|5 == 7): `nStatus |=
|
||||||
|
//! BLOCK_VALID_CONTEXT` then overwrote the validity level rather than setting a flag, so a
|
||||||
|
//! block that was only written to disk read back as BLOCK_VALID_SCRIPTS and every later
|
||||||
|
//! RaiseValidity() silently no-opped. Detected by CheckBlockIndex's "CHAIN valid implies all
|
||||||
|
//! parents are CHAIN valid" assert, which aborts any node doing out-of-order block download
|
||||||
|
//! (regtest only, where fDefaultConsistencyChecks is true). Validity was only ever inflated,
|
||||||
|
//! never deflated, so ConnectBlock's full validation was never skipped -- see git history.
|
||||||
|
//! Legacy block indexes still carry the polluted low bits; they resolve on reindex, and until
|
||||||
|
//! then simply re-run the contextual check they used to skip.
|
||||||
|
BLOCK_VALID_CONTEXT = 512
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! The validity level is a small integer packed into BLOCK_VALID_MASK, so every other nStatus flag
|
||||||
|
//! must be disjoint from it. Enforced here so this class of bug cannot be reintroduced silently.
|
||||||
|
static_assert((BLOCK_VALID_CONTEXT & BLOCK_VALID_MASK) == 0, "BLOCK_VALID_CONTEXT overlaps the validity-level field");
|
||||||
|
static_assert((BLOCK_HAVE_MASK & BLOCK_VALID_MASK) == 0, "BLOCK_HAVE_MASK overlaps the validity-level field");
|
||||||
|
static_assert((BLOCK_FAILED_MASK & BLOCK_VALID_MASK) == 0, "BLOCK_FAILED_MASK overlaps the validity-level field");
|
||||||
|
static_assert((BLOCK_ACTIVATES_UPGRADE & BLOCK_VALID_MASK) == 0, "BLOCK_ACTIVATES_UPGRADE overlaps the validity-level field");
|
||||||
|
static_assert((BLOCK_IN_TMPFILE & BLOCK_VALID_MASK) == 0, "BLOCK_IN_TMPFILE overlaps the validity-level field");
|
||||||
|
|
||||||
//! Short-hand for the highest consensus validity we implement.
|
//! Short-hand for the highest consensus validity we implement.
|
||||||
//! Blocks with this validity are assumed to satisfy all consensus rules.
|
//! Blocks with this validity are assumed to satisfy all consensus rules.
|
||||||
static const BlockStatus BLOCK_VALID_CONSENSUS = BLOCK_VALID_SCRIPTS;
|
static const BlockStatus BLOCK_VALID_CONSENSUS = BLOCK_VALID_SCRIPTS;
|
||||||
|
|||||||
Reference in New Issue
Block a user