Compare commits
3 Commits
af7d9e2300
...
6d282db216
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d282db216 | |||
| c5fde12485 | |||
| e2e10f6ef8 |
@@ -3,7 +3,7 @@
|
||||
.SH NAME
|
||||
dragonx-cli \- manual page for dragonx-cli v1.3.0
|
||||
.SH DESCRIPTION
|
||||
DragonX RPC client version v1.3.0
|
||||
DragonX RPC client version v1.3.0\-af7d9e230
|
||||
.PP
|
||||
In order to ensure you are adequately protecting your privacy when using
|
||||
DragonX, please see <https://dragonx.is/security/>.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.SH NAME
|
||||
dragonx-tx \- manual page for dragonx-tx v1.3.0
|
||||
.SH DESCRIPTION
|
||||
hush\-tx utility version v1.3.0
|
||||
hush\-tx utility version v1.3.0\-af7d9e230
|
||||
.SS "Usage:"
|
||||
.TP
|
||||
hush\-tx [options] <hex\-tx> [commands]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.SH NAME
|
||||
dragonxd \- manual page for dragonxd v1.3.0
|
||||
.SH DESCRIPTION
|
||||
DragonX Daemon version v1.3.0
|
||||
DragonX Daemon version v1.3.0\-af7d9e230
|
||||
.PP
|
||||
In order to ensure you are adequately protecting your privacy when using
|
||||
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:
|
||||
10000)
|
||||
.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
|
||||
.IP
|
||||
Only auto\-shield once at least this many matured coinbase UTXOs exist
|
||||
@@ -710,6 +717,11 @@ Stratum server options:
|
||||
.IP
|
||||
Enable stratum server (default: off)
|
||||
.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>
|
||||
.IP
|
||||
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 The Zcash developers
|
||||
# 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) 2014 The Bitcoin Core developers
|
||||
# Distributed under the GPLv3 software license, see the accompanying
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.authproxy import JSONRPCException
|
||||
from test_framework.util import initialize_chain_clean, start_node
|
||||
|
||||
from binascii import a2b_hex, b2a_hex
|
||||
from hashlib import sha256
|
||||
@@ -69,14 +70,43 @@ def genmrklroot(leaflist):
|
||||
cur = n
|
||||
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):
|
||||
blkver = pack('<L', tmpl['version'])
|
||||
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'])
|
||||
nonce = b'\0'*32
|
||||
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))
|
||||
for tx in txlist:
|
||||
blk += tx
|
||||
@@ -95,6 +125,20 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
|
||||
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):
|
||||
node = self.nodes[0]
|
||||
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
|
||||
|
||||
# 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')
|
||||
txlist[0][4+1] -= 1
|
||||
txlist[0][CB_PREVOUT_OFF] -= 1
|
||||
|
||||
# Test 3: Truncated final tx
|
||||
lastbyte = txlist[-1].pop()
|
||||
@@ -136,14 +180,33 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
|
||||
|
||||
# Test 5: Add an invalid tx to the end (non-duplicate)
|
||||
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')
|
||||
txlist.pop()
|
||||
|
||||
# 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')
|
||||
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
|
||||
txlist.append(b'')
|
||||
@@ -171,7 +234,9 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
|
||||
tmpl['curtime'] = 0x7fffffff
|
||||
assert_template(node, tmpl, txlist, 'time-too-new')
|
||||
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
|
||||
|
||||
# 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
|
||||
# conf key is ignored, and without it this cache node runs on MAINNET), and -asmap
|
||||
# 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")
|
||||
if os.path.exists(_am):
|
||||
args.append("-asmap=" + os.path.realpath(_am))
|
||||
if i > 0:
|
||||
args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
|
||||
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"
|
||||
if os.getenv("PYTHON_DEBUG", ""):
|
||||
print("initialize_chain: hushd started, calling: " + cmd_args)
|
||||
@@ -198,10 +204,17 @@ def initialize_chain(test_dir):
|
||||
wait_bitcoinds()
|
||||
for i in range(4):
|
||||
print("Cleaning up cache dir files")
|
||||
os.remove(log_filename("cache", i, "debug.log"))
|
||||
os.remove(log_filename("cache", i, "db.log"))
|
||||
os.remove(log_filename("cache", i, "peers.dat"))
|
||||
os.remove(log_filename("cache", i, "fee_estimates.dat"))
|
||||
# log_filename() points at <cache>/node<i>/regtest, but that IS the -datadir we passed;
|
||||
# dragonxd writes its logs/peers.dat one level deeper, into the net-specific
|
||||
# <datadir>/regtest subdir (same datadir-vs-netdir split that forced -asmap to be
|
||||
# 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):
|
||||
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
|
||||
|
||||
def set_node_times(nodes, t):
|
||||
print("Setting nodes time to " + t)
|
||||
print("Setting nodes time to " + str(t))
|
||||
for node in nodes:
|
||||
node.setmocktime(t)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2016-2024 The Hush developers
|
||||
# Copyright (c) 2014 The Bitcoin Core developers
|
||||
# Distributed under the GPLv3 software license, see the accompanying
|
||||
@@ -20,8 +20,20 @@ class WalletTest (BitcoinTestFramework):
|
||||
print("Initializing test directory "+self.options.tmpdir)
|
||||
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):
|
||||
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,1,2)
|
||||
connect_nodes_bi(self.nodes,0,2)
|
||||
@@ -29,7 +41,7 @@ class WalletTest (BitcoinTestFramework):
|
||||
self.sync_all()
|
||||
|
||||
def run_test (self):
|
||||
print "Mining blocks..."
|
||||
print("Mining blocks...")
|
||||
|
||||
self.nodes[0].generate(4)
|
||||
self.sync_all()
|
||||
@@ -106,7 +118,7 @@ class WalletTest (BitcoinTestFramework):
|
||||
signed_tx = self.nodes[2].signrawtransaction(raw_tx)
|
||||
try:
|
||||
self.nodes[2].sendrawtransaction(signed_tx["hex"])
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert("absurdly high fees" in errorString)
|
||||
assert("900000000 > 190000" in errorString)
|
||||
@@ -186,7 +198,7 @@ class WalletTest (BitcoinTestFramework):
|
||||
txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
|
||||
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)
|
||||
sync_blocks(self.nodes)
|
||||
|
||||
@@ -227,7 +239,7 @@ class WalletTest (BitcoinTestFramework):
|
||||
#do some -walletbroadcast tests
|
||||
stop_nodes(self.nodes)
|
||||
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,1,2)
|
||||
connect_nodes_bi(self.nodes,0,2)
|
||||
@@ -256,7 +268,7 @@ class WalletTest (BitcoinTestFramework):
|
||||
#restart the nodes with -walletbroadcast=1
|
||||
stop_nodes(self.nodes)
|
||||
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,1,2)
|
||||
connect_nodes_bi(self.nodes,0,2)
|
||||
@@ -290,7 +302,7 @@ class WalletTest (BitcoinTestFramework):
|
||||
num_t_recipients = 3000
|
||||
amount_per_recipient = Decimal('0.00000001')
|
||||
errorString = ''
|
||||
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})
|
||||
|
||||
@@ -305,7 +317,7 @@ class WalletTest (BitcoinTestFramework):
|
||||
|
||||
try:
|
||||
self.nodes[0].z_sendmany(myzaddr, recipients)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert("Too many outputs, size of raw transaction" in errorString)
|
||||
|
||||
@@ -314,10 +326,10 @@ class WalletTest (BitcoinTestFramework):
|
||||
num_z_recipients = 50
|
||||
amount_per_recipient = Decimal('0.00000001')
|
||||
errorString = ''
|
||||
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})
|
||||
for i in xrange(0,num_z_recipients):
|
||||
for i in range(0,num_z_recipients):
|
||||
newzaddr = self.nodes[2].z_getnewaddress()
|
||||
recipients.append({"address":newzaddr, "amount":amount_per_recipient})
|
||||
|
||||
@@ -327,7 +339,7 @@ class WalletTest (BitcoinTestFramework):
|
||||
|
||||
try:
|
||||
self.nodes[0].z_sendmany(myzaddr, recipients)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert("size of raw transaction would be larger than limit" in errorString)
|
||||
|
||||
@@ -335,12 +347,12 @@ class WalletTest (BitcoinTestFramework):
|
||||
num_z_recipients = 100
|
||||
amount_per_recipient = Decimal('0.00000001')
|
||||
errorString = ''
|
||||
for i in xrange(0,num_z_recipients):
|
||||
for i in range(0,num_z_recipients):
|
||||
newzaddr = self.nodes[2].z_getnewaddress()
|
||||
recipients.append({"address":newzaddr, "amount":amount_per_recipient})
|
||||
try:
|
||||
self.nodes[0].z_sendmany(myzaddr, recipients)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert("Invalid parameter, too many zaddr outputs" in errorString)
|
||||
|
||||
@@ -426,7 +438,7 @@ class WalletTest (BitcoinTestFramework):
|
||||
errorString = ""
|
||||
try:
|
||||
txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1f-4")
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
|
||||
assert_equal("Invalid amount" in errorString, True)
|
||||
@@ -434,7 +446,7 @@ class WalletTest (BitcoinTestFramework):
|
||||
errorString = ""
|
||||
try:
|
||||
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']
|
||||
|
||||
assert_equal("not an integer" in errorString, True)
|
||||
@@ -448,9 +460,9 @@ class WalletTest (BitcoinTestFramework):
|
||||
try:
|
||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
|
||||
assert(myopid)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
print errorString
|
||||
print(errorString)
|
||||
assert(False)
|
||||
|
||||
# This fee is larger than the default fee and since amount=0
|
||||
@@ -462,7 +474,7 @@ class WalletTest (BitcoinTestFramework):
|
||||
|
||||
try:
|
||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert('Small transaction amount' in errorString)
|
||||
|
||||
@@ -475,9 +487,9 @@ class WalletTest (BitcoinTestFramework):
|
||||
try:
|
||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee)
|
||||
assert(myopid)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
print errorString
|
||||
print(errorString)
|
||||
assert(False)
|
||||
|
||||
# Make sure amount=0, fee=0 transaction are valid to add to mempool
|
||||
@@ -490,9 +502,9 @@ class WalletTest (BitcoinTestFramework):
|
||||
try:
|
||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee)
|
||||
assert(myopid)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
print errorString
|
||||
print(errorString)
|
||||
assert(False)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2016-2024 The Hush developers
|
||||
# Copyright (c) 2018 The Zcash developers
|
||||
# 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) 2017 The Zcash developers
|
||||
# Distributed under the GPLv3 software license, see the accompanying
|
||||
@@ -32,7 +32,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
||||
self.sync_all()
|
||||
|
||||
def run_test (self):
|
||||
print "Mining blocks..."
|
||||
print("Mining blocks...")
|
||||
|
||||
self.nodes[0].generate(1)
|
||||
do_not_shield_taddr = self.nodes[0].getnewaddress()
|
||||
@@ -81,7 +81,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
||||
try:
|
||||
self.nodes[0].z_mergetoaddress("*", myzaddr)
|
||||
assert(False)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("JSON value is not an array as expected" in errorString, True)
|
||||
|
||||
@@ -90,7 +90,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
||||
try:
|
||||
self.nodes[2].z_mergetoaddress([mytaddr], myzaddr)
|
||||
assert(False)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Could not find any funds to merge" in errorString, True)
|
||||
|
||||
@@ -98,7 +98,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
||||
try:
|
||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, -1)
|
||||
assert(False)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Amount out of range" in errorString, True)
|
||||
|
||||
@@ -106,7 +106,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
||||
try:
|
||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('21000000.00000001'))
|
||||
assert(False)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Amount out of range" in errorString, True)
|
||||
|
||||
@@ -114,7 +114,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
||||
try:
|
||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, 999)
|
||||
assert(False)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Insufficient funds" in errorString, True)
|
||||
|
||||
@@ -122,7 +122,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
||||
try:
|
||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), -1)
|
||||
assert(False)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Limit on maximum number of UTXOs cannot be negative" in errorString, True)
|
||||
|
||||
@@ -130,7 +130,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
||||
try:
|
||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), 99999999999999)
|
||||
assert(False)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("JSON integer out of range" in errorString, True)
|
||||
|
||||
@@ -138,7 +138,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
||||
try:
|
||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), 50, -1)
|
||||
assert(False)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Limit on maximum number of notes cannot be negative" in errorString, True)
|
||||
|
||||
@@ -146,7 +146,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
||||
try:
|
||||
self.nodes[0].z_mergetoaddress(["*"], myzaddr, Decimal('0.001'), 50, 99999999999999)
|
||||
assert(False)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("JSON integer out of range" in errorString, True)
|
||||
|
||||
@@ -154,7 +154,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework):
|
||||
try:
|
||||
self.nodes[0].z_mergetoaddress([mytaddr], mytaddr)
|
||||
assert(False)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
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 The Zcash developers
|
||||
# Distributed under the GPLv3 software license, see the accompanying
|
||||
@@ -7,15 +7,71 @@
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
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
|
||||
|
||||
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):
|
||||
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):
|
||||
# add zaddr to node 0
|
||||
@@ -44,7 +100,7 @@ class WalletNullifiersTest (BitcoinTestFramework):
|
||||
bitcoind_processes[1].wait()
|
||||
|
||||
# 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, 1, 2)
|
||||
self.sync_all()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2016-2024 The Hush developers
|
||||
# Copyright (c) 2018 The Zcash developers
|
||||
# Distributed under the GPLv3 software license, see the accompanying
|
||||
@@ -13,6 +13,29 @@ from test_framework.util import (
|
||||
)
|
||||
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):
|
||||
|
||||
def setup_chain(self):
|
||||
@@ -20,8 +43,20 @@ class WalletPersistenceTest (BitcoinTestFramework):
|
||||
initialize_chain_clean(self.options.tmpdir, 3)
|
||||
|
||||
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,
|
||||
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=76b809bb:201', # Sapling
|
||||
]] * 3)
|
||||
@@ -72,8 +107,7 @@ class WalletPersistenceTest (BitcoinTestFramework):
|
||||
|
||||
# Verify size of shielded pools
|
||||
pools = self.nodes[0].getblockchaininfo()['valuePools']
|
||||
assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout
|
||||
assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling
|
||||
assert_pool_values(pools, Decimal('0'), Decimal('20'))
|
||||
|
||||
# Restart the nodes
|
||||
stop_nodes(self.nodes)
|
||||
@@ -82,8 +116,7 @@ class WalletPersistenceTest (BitcoinTestFramework):
|
||||
|
||||
# Verify size of shielded pools
|
||||
pools = self.nodes[0].getblockchaininfo()['valuePools']
|
||||
assert_equal(pools[0]['chainValue'], Decimal('0')) # Sprout
|
||||
assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling
|
||||
assert_pool_values(pools, Decimal('0'), Decimal('20'))
|
||||
|
||||
# Node 0 sends some shielded funds to Node 1
|
||||
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 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)
|
||||
|
||||
@@ -95,11 +108,11 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
|
||||
# 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])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2016-2024 The Hush developers
|
||||
# Copyright (c) 2018 The Zcash developers
|
||||
# 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.util import (
|
||||
assert_equal,
|
||||
start_nodes,
|
||||
initialize_chain_clean,
|
||||
p2p_port,
|
||||
set_node_times,
|
||||
start_node,
|
||||
sync_blocks,
|
||||
wait_and_assert_operationid_status,
|
||||
)
|
||||
|
||||
import os
|
||||
import stat
|
||||
|
||||
from decimal import Decimal
|
||||
|
||||
# Test wallet behaviour with Sapling addresses
|
||||
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):
|
||||
return start_nodes(4, self.options.tmpdir, [[
|
||||
#'-nuparams=5ba81b19:201', # Overwinter
|
||||
#'-nuparams=76b809bb:203', # Sapling
|
||||
#'-experimentalfeatures', '-zmergetoaddress',
|
||||
]] * 4)
|
||||
binary = self._daemon_wrapper()
|
||||
nodes = []
|
||||
for i in range(4):
|
||||
extra_args = [
|
||||
#'-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):
|
||||
# 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) 2017 The Zcash developers
|
||||
# Distributed under the GPLv3 software license, see the accompanying
|
||||
@@ -22,8 +22,24 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework):
|
||||
initialize_chain_clean(self.options.tmpdir, 4)
|
||||
|
||||
def setup_network(self, split=False):
|
||||
args = ['-regtestprotectcoinbase', '-debug=zrpcunsafe']
|
||||
args2 = ['-regtestprotectcoinbase', '-debug=zrpcunsafe', "-mempooltxinputlimit=7"]
|
||||
# DragonX-specific environment flags. None of these change what the test
|
||||
# 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':
|
||||
nu = [
|
||||
'-nuparams=5ba81b19:0', # Overwinter
|
||||
@@ -42,7 +58,7 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework):
|
||||
self.sync_all()
|
||||
|
||||
def run_test (self):
|
||||
print "Mining blocks..."
|
||||
print("Mining blocks...")
|
||||
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
@@ -73,42 +89,42 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework):
|
||||
self.nodes[2].importaddress(mytaddr)
|
||||
try:
|
||||
self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Could not find any coinbase funds to shield" in errorString, True)
|
||||
|
||||
# Shielding will fail because fee is negative
|
||||
try:
|
||||
self.nodes[0].z_shieldcoinbase("*", myzaddr, -1)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Amount out of range" in errorString, True)
|
||||
|
||||
# Shielding will fail because fee is larger than MAX_MONEY
|
||||
try:
|
||||
self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('21000000.00000001'))
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Amount out of range" in errorString, True)
|
||||
|
||||
# Shielding will fail because fee is larger than sum of utxos
|
||||
try:
|
||||
self.nodes[0].z_shieldcoinbase("*", myzaddr, 999)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Insufficient coinbase funds" in errorString, True)
|
||||
|
||||
# Shielding will fail because limit parameter must be at least 0
|
||||
try:
|
||||
self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), -1)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("Limit on maximum number of utxos cannot be negative" in errorString, True)
|
||||
|
||||
# Shielding will fail because limit parameter is absurdly large
|
||||
try:
|
||||
self.nodes[0].z_shieldcoinbase("*", myzaddr, Decimal('0.001'), 99999999999999)
|
||||
except JSONRPCException,e:
|
||||
except JSONRPCException as e:
|
||||
errorString = e.error['message']
|
||||
assert_equal("JSON integer out of range" in errorString, True)
|
||||
|
||||
@@ -214,3 +230,13 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework):
|
||||
sync_mempools(self.nodes[:2])
|
||||
self.nodes[1].generate(1)
|
||||
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 The Zcash developers
|
||||
# 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.
|
||||
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,1,2)
|
||||
connect_nodes_bi(self.nodes,0,2)
|
||||
@@ -28,7 +37,7 @@ class WalletTreeStateTest (BitcoinTestFramework):
|
||||
self.sync_all()
|
||||
|
||||
def run_test (self):
|
||||
print "Mining blocks..."
|
||||
print("Mining blocks...")
|
||||
|
||||
self.nodes[0].generate(100)
|
||||
self.sync_all()
|
||||
@@ -79,7 +88,7 @@ class WalletTreeStateTest (BitcoinTestFramework):
|
||||
myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
|
||||
|
||||
# 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])
|
||||
status = results[0]["status"]
|
||||
if status == "executing":
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2016-2024 The Hush developers
|
||||
# Copyright (c) 2014 The Bitcoin Core developers
|
||||
# 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.authproxy import JSONRPCException
|
||||
from test_framework.util import assert_equal, initialize_chain_clean, \
|
||||
start_nodes, start_node, connect_nodes, stop_node, \
|
||||
sync_blocks, sync_mempools
|
||||
start_nodes, start_node, connect_nodes, \
|
||||
sync_blocks, sync_mempools, bitcoind_processes
|
||||
|
||||
import os
|
||||
import shutil
|
||||
@@ -48,6 +48,46 @@ import logging
|
||||
|
||||
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):
|
||||
|
||||
def setup_chain(self):
|
||||
@@ -62,7 +102,10 @@ class WalletBackupTest(BitcoinTestFramework):
|
||||
ed2 = "-exportdir=" + self.options.tmpdir + "/node2"
|
||||
|
||||
# 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)
|
||||
connect_nodes(self.nodes[0], 3)
|
||||
connect_nodes(self.nodes[1], 3)
|
||||
@@ -95,18 +138,18 @@ class WalletBackupTest(BitcoinTestFramework):
|
||||
|
||||
# As above, this mirrors the original bash test.
|
||||
def start_three(self):
|
||||
self.nodes[0] = start_node(0, self.options.tmpdir)
|
||||
self.nodes[1] = start_node(1, self.options.tmpdir)
|
||||
self.nodes[2] = start_node(2, self.options.tmpdir)
|
||||
self.nodes[0] = start_node(0, self.options.tmpdir, [LISTEN, NODNS, ALLOWLIST])
|
||||
self.nodes[1] = start_node(1, self.options.tmpdir, [LISTEN, NODNS, ALLOWLIST])
|
||||
self.nodes[2] = start_node(2, self.options.tmpdir, [LISTEN, NODNS, ALLOWLIST])
|
||||
connect_nodes(self.nodes[0], 3)
|
||||
connect_nodes(self.nodes[1], 3)
|
||||
connect_nodes(self.nodes[2], 3)
|
||||
connect_nodes(self.nodes[2], 0)
|
||||
|
||||
def stop_three(self):
|
||||
stop_node(self.nodes[0], 0)
|
||||
stop_node(self.nodes[1], 1)
|
||||
stop_node(self.nodes[2], 2)
|
||||
stop_node_and_reap(self.nodes[0], 0)
|
||||
stop_node_and_reap(self.nodes[1], 1)
|
||||
stop_node_and_reap(self.nodes[2], 2)
|
||||
|
||||
def erase_three(self):
|
||||
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.
|
||||
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.
|
||||
//! 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_CHAIN | BLOCK_VALID_SCRIPTS,
|
||||
|
||||
@@ -129,9 +128,29 @@ enum BlockStatus: uint32_t {
|
||||
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
|
||||
|
||||
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.
|
||||
//! Blocks with this validity are assumed to satisfy all consensus rules.
|
||||
static const BlockStatus BLOCK_VALID_CONSENSUS = BLOCK_VALID_SCRIPTS;
|
||||
|
||||
Reference in New Issue
Block a user