Major updates integration from all upstreams

This commit is contained in:
miketout
2018-09-18 14:33:53 -07:00
396 changed files with 25517 additions and 6854 deletions

View File

@@ -16,13 +16,16 @@ testScripts=(
'prioritisetransaction.py'
'wallet_treestate.py'
'wallet_anchorfork.py'
'wallet_changeindicator.py'
'wallet_protectcoinbase.py'
'wallet_shieldcoinbase.py'
'wallet_mergetoaddress.py'
'wallet.py'
'wallet_overwintertx.py'
'wallet_nullifiers.py'
# 'wallet_nullifiers.py'
'wallet_1941.py'
'wallet_addresses.py'
'wallet_sapling.py'
'listtransactions.py'
'mempool_resurrect_test.py'
'txn_doublespend.py'
@@ -39,7 +42,7 @@ testScripts=(
'zapwallettxes.py'
'proxy_test.py'
'merkle_blocks.py'
'fundrawtransaction.py'
# 'fundrawtransaction.py'
'signrawtransactions.py'
'walletbackup.py'
'key_import_export.py'
@@ -49,6 +52,7 @@ testScripts=(
'timestampindex.py'
'spentindex.py'
'decodescript.py'
'blockchain.py'
'disablewallet.py'
'zcjoinsplit.py'
'zcjoinsplitdoublespend.py'
@@ -58,6 +62,9 @@ testScripts=(
'bip65-cltv-p2p.py'
'bipdersig-p2p.py'
'overwinter_peer_management.py'
'rewind_index.py'
'p2p_txexpiry_dos.py'
'p2p_node_bloom.py'
);
testScriptsExt=(
'getblocktemplate_longpoll.py'

53
qa/rpc-tests/blockchain.py Executable file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python2
# Copyright (c) 2014 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
# Test RPC calls related to blockchain state. Tests correspond to code in
# rpc/blockchain.cpp.
#
import decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
initialize_chain,
assert_equal,
start_nodes,
connect_nodes_bi,
)
class BlockchainTest(BitcoinTestFramework):
"""
Test blockchain-related RPC calls:
- gettxoutsetinfo
"""
def setup_chain(self):
print("Initializing test directory " + self.options.tmpdir)
initialize_chain(self.options.tmpdir)
def setup_network(self, split=False):
self.nodes = start_nodes(2, self.options.tmpdir)
connect_nodes_bi(self.nodes, 0, 1)
self.is_network_split = False
self.sync_all()
def run_test(self):
node = self.nodes[0]
res = node.gettxoutsetinfo()
assert_equal(res[u'total_amount'], decimal.Decimal('2181.25000000')) # 150*12.5 + 49*6.25
assert_equal(res[u'transactions'], 200)
assert_equal(res[u'height'], 200)
assert_equal(res[u'txouts'], 349) # 150*2 + 49
assert_equal(res[u'bytes_serialized'], 14951), # 32*199 + 48*90 + 49*60 + 27*49
assert_equal(len(res[u'bestblock']), 64)
assert_equal(len(res[u'hash_serialized']), 64)
if __name__ == '__main__':
BlockchainTest().main()

View File

@@ -6,6 +6,9 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, initialize_chain_clean, \
start_nodes
from test_framework.mininode import CTransaction
from binascii import hexlify, unhexlify
from cStringIO import StringIO
class DecodeScriptTest(BitcoinTestFramework):
@@ -109,10 +112,77 @@ class DecodeScriptTest(BitcoinTestFramework):
rpc_result = self.nodes[0].decodescript('63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac')
assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_NOP2 OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm'])
def decoderawtransaction_asm_sighashtype(self):
"""Tests decoding scripts via RPC command "decoderawtransaction".
This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
"""
# this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output
tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000'
rpc_result = self.nodes[0].decoderawtransaction(tx)
assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm'])
# this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs.
# it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc
# verify that we have not altered scriptPubKey decoding.
tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000'
rpc_result = self.nodes[0].decoderawtransaction(tx)
assert_equal('8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid'])
assert_equal('0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm'])
assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])
assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])
txSave = CTransaction()
txSave.deserialize(StringIO(unhexlify(tx)))
# make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type
tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000'
rpc_result = self.nodes[0].decoderawtransaction(tx)
assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm'])
# verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks
tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000'
rpc_result = self.nodes[0].decoderawtransaction(tx)
assert_equal('OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])
assert_equal('OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])
# some more full transaction tests of varying specific scriptSigs. used instead of
# tests in decodescript_script_sig because the decodescript RPC is specifically
# for working on scriptPubKeys (argh!).
push_signature = hexlify(txSave.vin[0].scriptSig)[2:(0x48*2+4)]
signature = push_signature[2:]
der_signature = signature[:-2]
signature_sighash_decoded = der_signature + '[ALL]'
signature_2 = der_signature + '82'
push_signature_2 = '48' + signature_2
signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]'
# 1) P2PK scriptSig
txSave.vin[0].scriptSig = unhexlify(push_signature)
rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize()))
assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
# make sure that the sighash decodes come out correctly for a more complex / lesser used case.
txSave.vin[0].scriptSig = unhexlify(push_signature_2)
rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize()))
assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
# 2) multisig scriptSig
txSave.vin[0].scriptSig = unhexlify('00' + push_signature + push_signature_2)
rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize()))
assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
# 3) test a scriptSig that contains more than push operations.
# in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it.
txSave.vin[0].scriptSig = unhexlify('6a143011020701010101010101020601010101010101')
rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize()))
print(hexlify('636174'))
assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])
def run_test(self):
self.decodescript_script_sig()
self.decodescript_script_pub_key()
self.decoderawtransaction_asm_sighashtype()
if __name__ == '__main__':
DecodeScriptTest().main()

View File

@@ -4,8 +4,8 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import initialize_chain_clean, start_nodes, \
connect_nodes_bi
from test_framework.util import assert_equal, connect_nodes_bi, \
initialize_chain_clean, start_nodes
class GetBlockTemplateTest(BitcoinTestFramework):
@@ -49,11 +49,16 @@ class GetBlockTemplateTest(BitcoinTestFramework):
# Test 5: General checks
tmpl = node.getblocktemplate()
assert(len(tmpl['noncerange']) == 16)
assert_equal(16, len(tmpl['noncerange']))
# Test 6: coinbasetxn checks
assert('foundersreward' in tmpl['coinbasetxn'])
assert(tmpl['coinbasetxn']['required'])
# Test 7: hashFinalSaplingRoot checks
assert('finalsaplingroothash' in tmpl)
finalsaplingroothash = '3e49b5f954aa9d3545bc6c37744661eea48d7c34e3000d82b7f0010c30f4c2fb'
assert_equal(finalsaplingroothash, tmpl['finalsaplingroothash'])
if __name__ == '__main__':
GetBlockTemplateTest().main()

View File

@@ -15,7 +15,10 @@ class MempoolUpgradeActivationTest(BitcoinTestFramework):
alert_filename = None # Set by setup_network
def setup_network(self):
args = ["-checkmempool", "-debug=mempool", "-blockmaxsize=4000", "-nuparams=5ba81b19:200"]
args = ["-checkmempool", "-debug=mempool", "-blockmaxsize=4000",
"-nuparams=5ba81b19:200", # Overwinter
"-nuparams=76b809bb:210", # Sapling
]
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, args))
self.nodes.append(start_node(1, self.options.tmpdir, args))
@@ -44,76 +47,100 @@ class MempoolUpgradeActivationTest(BitcoinTestFramework):
print wait_and_assert_operationid_status(self.nodes[1], myopid)
self.sync_all()
# Mine block 198. After this, the mempool expects
# block 199, which is the last Sprout block.
self.nodes[0].generate(1)
# Mempool checks for activation of upgrade Y at height H on base X
def nu_activation_checks():
# Mine block H - 2. After this, the mempool expects
# block H - 1, which is the last X block.
self.nodes[0].generate(1)
self.sync_all()
# Mempool should be empty.
assert_equal(set(self.nodes[0].getrawmempool()), set())
# Check node 0 shielded balance
assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10'))
# Fill the mempool with twice as many transactions as can fit into blocks
node0_taddr = self.nodes[0].getnewaddress()
x_txids = []
while self.nodes[1].getmempoolinfo()['bytes'] < 2 * 4000:
x_txids.append(self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')))
self.sync_all()
# Spends should be in the mempool
x_mempool = set(self.nodes[0].getrawmempool())
assert_equal(x_mempool, set(x_txids))
# Mine block H - 1. After this, the mempool expects
# block H, which is the first Y block.
self.nodes[0].generate(1)
self.sync_all()
# mempool should be empty.
assert_equal(set(self.nodes[0].getrawmempool()), set())
# Block H - 1 should contain a subset of the original mempool
# (with all other transactions having been dropped)
block_txids = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['tx']
assert(len(block_txids) < len(x_txids))
for txid in block_txids[1:]: # Exclude coinbase
assert(txid in x_txids)
# Create some transparent Y transactions
y_txids = [self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')) for i in range(10)]
self.sync_all()
# Create a shielded Y transaction
recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}]
myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients, 1, Decimal('0'))
shielded = wait_and_assert_operationid_status(self.nodes[0], myopid)
assert(shielded != None)
y_txids.append(shielded)
self.sync_all()
# Spends should be in the mempool
assert_equal(set(self.nodes[0].getrawmempool()), set(y_txids))
# Node 0 note should be unspendable
assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('0'))
# Invalidate block H - 1.
block_hm1 = self.nodes[0].getbestblockhash()
self.nodes[0].invalidateblock(block_hm1)
# BUG: Ideally, the mempool should now only contain the transactions
# that were in block H - 1, the Y transactions having been dropped.
# However, because chainActive is not updated until after the transactions
# in the disconnected block have been re-added to the mempool, the height
# seen by AcceptToMemoryPool is one greater than it should be. This causes
# the block H - 1 transactions to be validated against the Y rules,
# and rejected because they (obviously) fail.
#assert_equal(set(self.nodes[0].getrawmempool()), set(block_txids[1:]))
assert_equal(set(self.nodes[0].getrawmempool()), set())
# Node 0 note should be spendable again
assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10'))
# Reconsider block H - 1.
self.nodes[0].reconsiderblock(block_hm1)
# Mine blocks on node 1, so that the Y transactions in its mempool
# will be cleared.
self.nodes[1].generate(6)
self.sync_all()
print('Testing Sprout -> Overwinter activation boundary')
# Current height = 197
nu_activation_checks()
# Current height = 205
self.nodes[0].generate(2)
self.sync_all()
# Mempool should be empty.
assert_equal(set(self.nodes[0].getrawmempool()), set())
# Check node 0 shielded balance
assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10'))
# Fill the mempool with twice as many transactions as can fit into blocks
node0_taddr = self.nodes[0].getnewaddress()
sprout_txids = []
while self.nodes[1].getmempoolinfo()['bytes'] < 2 * 4000:
sprout_txids.append(self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')))
self.sync_all()
# Spends should be in the mempool
sprout_mempool = set(self.nodes[0].getrawmempool())
assert_equal(sprout_mempool, set(sprout_txids))
# Mine block 199. After this, the mempool expects
# block 200, which is the first Overwinter block.
self.nodes[0].generate(1)
self.sync_all()
# mempool should be empty.
assert_equal(set(self.nodes[0].getrawmempool()), set())
# Block 199 should contain a subset of the original mempool
# (with all other transactions having been dropped)
block_txids = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['tx']
assert(len(block_txids) < len(sprout_txids))
for txid in block_txids[1:]: # Exclude coinbase
assert(txid in sprout_txids)
# Create some transparent Overwinter transactions
overwinter_txids = [self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')) for i in range(10)]
self.sync_all()
# Create a shielded Overwinter transaction
recipients = [{'address': node0_taddr, 'amount': Decimal('10')}]
myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients, 1, Decimal('0'))
shielded = wait_and_assert_operationid_status(self.nodes[0], myopid)
assert(shielded != None)
overwinter_txids.append(shielded)
self.sync_all()
# Spends should be in the mempool
assert_equal(set(self.nodes[0].getrawmempool()), set(overwinter_txids))
# Node 0 note should be unspendable
assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('0'))
# Invalidate block 199.
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# BUG: Ideally, the mempool should now only contain the transactions
# that were in block 199, the Overwinter transactions having been dropped.
# However, because chainActive is not updated until after the transactions
# in the disconnected block have been re-added to the mempool, the height
# seen by AcceptToMemoryPool is one greater than it should be. This causes
# the block 199 transactions to be validated against the Overwinter rules,
# and rejected because they (obviously) fail.
#assert_equal(set(self.nodes[0].getrawmempool()), set(block_txids[1:]))
assert_equal(set(self.nodes[0].getrawmempool()), set())
# Node 0 note should be spendable again
assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10'))
print('Testing Overwinter -> Sapling activation boundary')
# Current height = 207
nu_activation_checks()
# Current height = 215
if __name__ == '__main__':
MempoolUpgradeActivationTest().main()

View File

@@ -20,9 +20,9 @@ class MempoolTxExpiryTest(BitcoinTestFramework):
return start_nodes(4, self.options.tmpdir, [["-nuparams=5ba81b19:205", "-txexpirydelta=4", "-debug=mempool"]] * 4)
# Test before, at, and after expiry block
# TODO: Test case of dependent txs in reorgs
# chain is at block height 199 when run_test executes
def run_test(self):
alice = self.nodes[0].getnewaddress()
z_alice = self.nodes[0].z_getnewaddress()
bob = self.nodes[2].getnewaddress()
z_bob = self.nodes[2].z_getnewaddress()
@@ -36,6 +36,42 @@ class MempoolTxExpiryTest(BitcoinTestFramework):
self.nodes[0].generate(6)
self.sync_all()
print "Splitting network..."
self.split_network()
# When Overwinter is activated, test dependent txs
firstTx = self.nodes[0].sendtoaddress(alice, 0.1)
firstTxInfo = self.nodes[0].getrawtransaction(firstTx, 1)
print "First tx expiry height:", firstTxInfo['expiryheight']
# Mine first transaction
self.nodes[0].generate(1)
for outpoint in firstTxInfo['vout']:
if outpoint['value'] == Decimal('0.10000000'):
vout = outpoint
break
inputs = [{'txid': firstTx, 'vout': vout['n'], 'scriptPubKey': vout['scriptPubKey']['hex']}]
outputs = {alice: 0.1}
rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
rawTxSigned = self.nodes[0].signrawtransaction(rawTx)
assert(rawTxSigned['complete'])
secondTx = self.nodes[0].sendrawtransaction(rawTxSigned['hex'])
secondTxInfo = self.nodes[0].getrawtransaction(secondTx, 1)
print "Second tx expiry height:", secondTxInfo['expiryheight']
# Mine second, dependent transaction
self.nodes[0].generate(1)
print "Mine 6 competing blocks on Node 2..."
blocks = self.nodes[2].generate(6)
print "Connect nodes to force a reorg"
connect_nodes_bi(self.nodes,0,2)
self.is_network_split = False
print "Syncing blocks"
sync_blocks(self.nodes)
print "Ensure that both txs are dropped from mempool of node 0"
print "Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks']
print "Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks']
assert_equal(set(self.nodes[0].getrawmempool()), set())
assert_equal(set(self.nodes[2].getrawmempool()), set())
## Shield one of Alice's coinbase funds to her zaddr
res = self.nodes[0].z_shieldcoinbase("*", z_alice, 0.0001, 1)
wait_and_assert_operationid_status(self.nodes[0], res['opid'])
@@ -51,6 +87,7 @@ class MempoolTxExpiryTest(BitcoinTestFramework):
self.split_network()
# Create transactions
blockheight = self.nodes[0].getblockchaininfo()['blocks']
zsendamount = Decimal('1.0') - Decimal('0.0001')
recipients = []
recipients.append({"address": z_bob, "amount": zsendamount})
@@ -61,7 +98,7 @@ class MempoolTxExpiryTest(BitcoinTestFramework):
rawtx = self.nodes[0].getrawtransaction(persist_transparent, 1)
assert_equal(rawtx["version"], 3)
assert_equal(rawtx["overwintered"], True)
assert_equal(rawtx["expiryheight"], 212)
assert_equal(rawtx["expiryheight"], blockheight + 5)
print "Blockheight at persist_transparent & persist_shielded creation:", self.nodes[0].getblockchaininfo()['blocks']
print "Expiryheight of persist_transparent:", rawtx['expiryheight']
# Verify shielded transaction is version 3 intended for Overwinter branch
@@ -69,7 +106,7 @@ class MempoolTxExpiryTest(BitcoinTestFramework):
print "Expiryheight of persist_shielded", rawtx['expiryheight']
assert_equal(rawtx["version"], 3)
assert_equal(rawtx["overwintered"], True)
assert_equal(rawtx["expiryheight"], 212)
assert_equal(rawtx["expiryheight"], blockheight + 5)
print "\n Blockheight advances to less than expiry block height. After reorg, txs should persist in mempool"
assert(persist_transparent in self.nodes[0].getrawmempool())

View File

@@ -17,7 +17,7 @@ class MempoolTxInputLimitTest(BitcoinTestFramework):
alert_filename = None # Set by setup_network
def setup_network(self):
args = ["-checkmempool", "-debug=mempool", "-mempooltxinputlimit=2"]
args = ["-checkmempool", "-debug=mempool", "-mempooltxinputlimit=2", "-nuparams=5ba81b19:110"]
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, args))
self.nodes.append(start_node(1, self.options.tmpdir, args))
@@ -100,6 +100,7 @@ class MempoolTxInputLimitTest(BitcoinTestFramework):
myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients)
wait_and_assert_operationid_status(self.nodes[0], myopid)
self.sync_all()
self.nodes[1].generate(1)
self.sync_all()
@@ -120,5 +121,31 @@ class MempoolTxInputLimitTest(BitcoinTestFramework):
# Spend should be in the mempool
assert_equal(set(self.nodes[1].getrawmempool()), set([ spend_taddr_id2 ]))
# Mine three blocks
self.nodes[1].generate(3)
self.sync_all()
# The next block to be mined, 109, is the last Sprout block
bci = self.nodes[0].getblockchaininfo()
assert_equal(bci['consensus']['chaintip'], '00000000')
assert_equal(bci['consensus']['nextblock'], '00000000')
# z_sendmany should be limited by -mempooltxinputlimit
recipients = []
recipients.append({"address":node0_zaddr, "amount":Decimal('30.0')-Decimal('0.0001')}) # utxo amount less fee
myopid = self.nodes[0].z_sendmany(node0_taddr, recipients)
wait_and_assert_operationid_status(self.nodes[0], myopid, 'failed', 'Too many transparent inputs 3 > limit 2')
# Mine one block
self.nodes[1].generate(1)
self.sync_all()
# The next block to be mined, 110, is the first Overwinter block
bci = self.nodes[0].getblockchaininfo()
assert_equal(bci['consensus']['chaintip'], '00000000')
assert_equal(bci['consensus']['nextblock'], '5ba81b19')
# z_sendmany should no longer be limited by -mempooltxinputlimit
myopid = self.nodes[0].z_sendmany(node0_taddr, recipients)
wait_and_assert_operationid_status(self.nodes[0], myopid)
if __name__ == '__main__':
MempoolTxInputLimitTest().main()

View File

@@ -7,6 +7,7 @@
# Test merkleblock fetch/validation
#
import string
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, assert_raises, \
@@ -86,5 +87,13 @@ class MerkleBlockTest(BitcoinTestFramework):
# ...or if we have a -txindex
assert_equal(self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof([txid_spent])), [txid_spent])
# Quick test of getblock using blockhash and different levels of verbosity
result = self.nodes[0].getblock(blockhash, 2)
coinbase_txid = result["tx"][0]["txid"]
result = self.nodes[0].getblock(blockhash, 1)
assert_equal(coinbase_txid, result["tx"][0]) # verbosity 1 only lists txids
result = self.nodes[0].getblock(blockhash, 0)
assert(c in string.hexdigits for c in result) # verbosity 0 returns raw hex
if __name__ == '__main__':
MerkleBlockTest().main()

View File

@@ -4,7 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.mininode import NodeConn, NodeConnCB, NetworkThread, \
msg_ping, MY_VERSION, OVERWINTER_PROTO_VERSION
msg_ping, SPROUT_PROTO_VERSION, OVERWINTER_PROTO_VERSION
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import initialize_chain_clean, start_nodes, \
p2p_port, assert_equal
@@ -55,8 +55,10 @@ class OverwinterPeerManagementTest(BitcoinTestFramework):
# Launch 10 Sprout and 10 Overwinter mininodes
nodes = []
for x in xrange(10):
nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", False))
nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", True))
nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0],
test, "regtest", SPROUT_PROTO_VERSION))
nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0],
test, "regtest", OVERWINTER_PROTO_VERSION))
# Start up network handling in another thread
NetworkThread().start()
@@ -68,7 +70,7 @@ class OverwinterPeerManagementTest(BitcoinTestFramework):
# Verify mininodes are still connected to zcashd node
peerinfo = self.nodes[0].getpeerinfo()
versions = [x["version"] for x in peerinfo]
assert_equal(10, versions.count(MY_VERSION))
assert_equal(10, versions.count(SPROUT_PROTO_VERSION))
assert_equal(10, versions.count(OVERWINTER_PROTO_VERSION))
# Overwinter consensus rules activate at block height 10
@@ -86,19 +88,19 @@ class OverwinterPeerManagementTest(BitcoinTestFramework):
# Verify Sprout mininodes have been dropped and Overwinter mininodes are still connected.
peerinfo = self.nodes[0].getpeerinfo()
versions = [x["version"] for x in peerinfo]
assert_equal(0, versions.count(MY_VERSION))
assert_equal(0, versions.count(SPROUT_PROTO_VERSION))
assert_equal(10, versions.count(OVERWINTER_PROTO_VERSION))
# Extend the Overwinter chain with another block.
self.nodes[0].generate(1)
# Connect a new Overwinter mininode to the zcashd node, which is accepted.
nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", True))
nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", OVERWINTER_PROTO_VERSION))
time.sleep(3)
assert_equal(11, len(self.nodes[0].getpeerinfo()))
# Try to connect a new Sprout mininode to the zcashd node, which is rejected.
sprout = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", False)
sprout = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", SPROUT_PROTO_VERSION)
nodes.append(sprout)
time.sleep(3)
assert("Version must be 170003 or greater" in str(sprout.rejectMessage))
@@ -106,7 +108,7 @@ class OverwinterPeerManagementTest(BitcoinTestFramework):
# Verify that only Overwinter mininodes are connected.
peerinfo = self.nodes[0].getpeerinfo()
versions = [x["version"] for x in peerinfo]
assert_equal(0, versions.count(MY_VERSION))
assert_equal(0, versions.count(SPROUT_PROTO_VERSION))
assert_equal(11, versions.count(OVERWINTER_PROTO_VERSION))
for node in nodes:

111
qa/rpc-tests/p2p_node_bloom.py Executable file
View File

@@ -0,0 +1,111 @@
#!/usr/bin/env python2
# Copyright (c) 2018 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.mininode import NodeConn, NodeConnCB, NetworkThread, \
msg_filteradd, msg_filterclear, mininode_lock, SPROUT_PROTO_VERSION
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import initialize_chain_clean, start_nodes, \
p2p_port, assert_equal
import time
class TestNode(NodeConnCB):
def __init__(self):
NodeConnCB.__init__(self)
self.create_callback_map()
self.connection = None
def add_connection(self, conn):
self.connection = conn
# Spin until verack message is received from the node.
# We use this to signal that our test can begin. This
# is called from the testing thread, so it needs to acquire
# the global lock.
def wait_for_verack(self):
while True:
with mininode_lock:
if self.verack_received:
return
time.sleep(0.05)
# Wrapper for the NodeConn's send_message function
def send_message(self, message):
self.connection.send_message(message)
def on_close(self, conn):
pass
def on_reject(self, conn, message):
conn.rejectMessage = message
class NodeBloomTest(BitcoinTestFramework):
def setup_chain(self):
print "Initializing test directory "+self.options.tmpdir
initialize_chain_clean(self.options.tmpdir, 2)
def setup_network(self):
self.nodes = start_nodes(2, self.options.tmpdir,
extra_args=[['-nopeerbloomfilters', '-enforcenodebloom'], []])
def run_test(self):
nobf_node = TestNode()
bf_node = TestNode()
connections = []
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], nobf_node))
connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], bf_node))
nobf_node.add_connection(connections[0])
bf_node.add_connection(connections[1])
# Start up network handling in another thread
NetworkThread().start()
nobf_node.wait_for_verack()
bf_node.wait_for_verack()
# Verify mininodes are connected to zcashd nodes
peerinfo = self.nodes[0].getpeerinfo()
versions = [x["version"] for x in peerinfo]
assert_equal(1, versions.count(SPROUT_PROTO_VERSION))
peerinfo = self.nodes[1].getpeerinfo()
versions = [x["version"] for x in peerinfo]
assert_equal(1, versions.count(SPROUT_PROTO_VERSION))
# Mininodes send filterclear message to zcashd node.
nobf_node.send_message(msg_filterclear())
bf_node.send_message(msg_filterclear())
time.sleep(3)
# Verify mininodes are still connected to zcashd nodes
peerinfo = self.nodes[0].getpeerinfo()
versions = [x["version"] for x in peerinfo]
assert_equal(1, versions.count(SPROUT_PROTO_VERSION))
peerinfo = self.nodes[1].getpeerinfo()
versions = [x["version"] for x in peerinfo]
assert_equal(1, versions.count(SPROUT_PROTO_VERSION))
# Mininodes send filteradd message to zcashd node.
nobf_node.send_message(msg_filteradd())
bf_node.send_message(msg_filteradd())
time.sleep(3)
# Verify NoBF mininode has been dropped, and BF mininode is still connected.
peerinfo = self.nodes[0].getpeerinfo()
versions = [x["version"] for x in peerinfo]
assert_equal(0, versions.count(SPROUT_PROTO_VERSION))
peerinfo = self.nodes[1].getpeerinfo()
versions = [x["version"] for x in peerinfo]
assert_equal(1, versions.count(SPROUT_PROTO_VERSION))
[ c.disconnect_node() for c in connections ]
if __name__ == '__main__':
NodeBloomTest().main()

133
qa/rpc-tests/p2p_txexpiry_dos.py Executable file
View File

@@ -0,0 +1,133 @@
#!/usr/bin/env python2
# Copyright (c) 2018 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.mininode import NodeConn, NodeConnCB, NetworkThread, \
CTransaction, msg_tx, mininode_lock, OVERWINTER_PROTO_VERSION
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import initialize_chain_clean, start_nodes, \
p2p_port, assert_equal
import time, cStringIO
from binascii import hexlify, unhexlify
class TestNode(NodeConnCB):
def __init__(self):
NodeConnCB.__init__(self)
self.create_callback_map()
self.connection = None
def add_connection(self, conn):
self.connection = conn
# Spin until verack message is received from the node.
# We use this to signal that our test can begin. This
# is called from the testing thread, so it needs to acquire
# the global lock.
def wait_for_verack(self):
while True:
with mininode_lock:
if self.verack_received:
return
time.sleep(0.05)
# Wrapper for the NodeConn's send_message function
def send_message(self, message):
self.connection.send_message(message)
def on_close(self, conn):
pass
def on_reject(self, conn, message):
conn.rejectMessage = message
class TxExpiryDoSTest(BitcoinTestFramework):
def setup_chain(self):
print "Initializing test directory "+self.options.tmpdir
initialize_chain_clean(self.options.tmpdir, 1)
def setup_network(self):
self.nodes = start_nodes(1, self.options.tmpdir,
extra_args=[['-nuparams=5ba81b19:10']])
def create_transaction(self, node, coinbase, to_address, amount, txModifier=None):
from_txid = node.getblock(coinbase)['tx'][0]
inputs = [{ "txid" : from_txid, "vout" : 0}]
outputs = { to_address : amount }
rawtx = node.createrawtransaction(inputs, outputs)
tx = CTransaction()
if txModifier:
f = cStringIO.StringIO(unhexlify(rawtx))
tx.deserialize(f)
txModifier(tx)
rawtx = hexlify(tx.serialize())
signresult = node.signrawtransaction(rawtx)
f = cStringIO.StringIO(unhexlify(signresult['hex']))
tx.deserialize(f)
return tx
def run_test(self):
test_node = TestNode()
connections = []
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0],
test_node, "regtest", OVERWINTER_PROTO_VERSION))
test_node.add_connection(connections[0])
# Start up network handling in another thread
NetworkThread().start()
test_node.wait_for_verack()
# Verify mininodes are connected to zcashd nodes
peerinfo = self.nodes[0].getpeerinfo()
versions = [x["version"] for x in peerinfo]
assert_equal(1, versions.count(OVERWINTER_PROTO_VERSION))
assert_equal(0, peerinfo[0]["banscore"])
self.coinbase_blocks = self.nodes[0].generate(1)
self.nodes[0].generate(100)
self.nodeaddress = self.nodes[0].getnewaddress()
# Mininodes send transaction to zcashd node.
def setExpiryHeight(tx):
tx.nExpiryHeight = 101
spendtx = self.create_transaction(self.nodes[0],
self.coinbase_blocks[0],
self.nodeaddress, 1.0,
txModifier=setExpiryHeight)
test_node.send_message(msg_tx(spendtx))
time.sleep(3)
# Verify test mininode has not been dropped
# and still has a banscore of 0.
peerinfo = self.nodes[0].getpeerinfo()
versions = [x["version"] for x in peerinfo]
assert_equal(1, versions.count(OVERWINTER_PROTO_VERSION))
assert_equal(0, peerinfo[0]["banscore"])
# Mine a block and resend the transaction
self.nodes[0].generate(1)
test_node.send_message(msg_tx(spendtx))
time.sleep(3)
# Verify test mininode has not been dropped
# but has a banscore of 10.
peerinfo = self.nodes[0].getpeerinfo()
versions = [x["version"] for x in peerinfo]
assert_equal(1, versions.count(OVERWINTER_PROTO_VERSION))
assert_equal(10, peerinfo[0]["banscore"])
[ c.disconnect_node() for c in connections ]
if __name__ == '__main__':
TxExpiryDoSTest().main()

View File

@@ -145,5 +145,11 @@ class RawTransactionsTest(BitcoinTestFramework):
self.sync_all()
assert_equal(self.nodes[0].getbalance(), bal+Decimal('10.00000000')+Decimal('2.19900000')) #block reward + tx
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}]
outputs = { self.nodes[0].getnewaddress() : 1 }
rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
decrawtx= self.nodes[0].decoderawtransaction(rawtx)
assert_equal(decrawtx['vin'][0]['sequence'], 1000)
if __name__ == '__main__':
RawTransactionsTest().main()

85
qa/rpc-tests/rewind_index.py Executable file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/env python2
# Copyright (c) 2018 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, initialize_chain_clean, \
start_nodes, start_node, connect_nodes_bi, bitcoind_processes
import time
class RewindBlockIndexTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 3)
def setup_network(self, split=False):
# Node 0 - Overwinter, then Sprout, then Overwinter again
# Node 1 - Sprout
# Node 2 - Overwinter
self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-nuparams=5ba81b19:10'], [], ['-nuparams=5ba81b19:10']])
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
self.is_network_split=False
self.sync_all()
def run_test (self):
# Bring all nodes to just before the activation block
print("Mining blocks...")
self.nodes[0].generate(8)
block9 = self.nodes[0].generate(1)[0]
self.sync_all()
assert_equal(self.nodes[0].getbestblockhash(), block9)
assert_equal(self.nodes[1].getbestblockhash(), block9)
print("Mining diverging blocks")
block10s = self.nodes[1].generate(1)[0]
block10o = self.nodes[2].generate(1)[0]
self.sync_all()
assert_equal(self.nodes[0].getbestblockhash(), block10o)
assert_equal(self.nodes[1].getbestblockhash(), block10s)
assert_equal(self.nodes[2].getbestblockhash(), block10o)
# Restart node 0 using Sprout instead of Overwinter
print("Switching node 0 from Overwinter to Sprout")
self.nodes[0].stop()
bitcoind_processes[0].wait()
self.nodes[0] = start_node(0,self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
# Assume node 1 will send block10s to node 0 quickly
# (if we used self.sync_all() here and there was a bug, the test would hang)
time.sleep(2)
# Node 0 has rewound and is now on the Sprout chain
assert_equal(self.nodes[0].getblockcount(), 10)
assert_equal(self.nodes[0].getbestblockhash(), block10s)
# Restart node 0 using Overwinter instead of Sprout
print("Switching node 0 from Sprout to Overwinter")
self.nodes[0].stop()
bitcoind_processes[0].wait()
self.nodes[0] = start_node(0,self.options.tmpdir, extra_args=['-nuparams=5ba81b19:10'])
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
# Assume node 2 will send block10o to node 0 quickly
# (if we used self.sync_all() here and there was a bug, the test would hang)
time.sleep(2)
# Node 0 has rewound and is now on the Overwinter chain again
assert_equal(self.nodes[0].getblockcount(), 10)
assert_equal(self.nodes[0].getbestblockhash(), block10o)
if __name__ == '__main__':
RewindBlockIndexTest().main()

View File

@@ -41,9 +41,11 @@ from .equihash import (
OVERWINTER_PROTO_VERSION = 170003
BIP0031_VERSION = 60000
MY_VERSION = 170002 # past bip-31 for ping/pong
SPROUT_PROTO_VERSION = 170002 # past bip-31 for ping/pong
MY_SUBVERSION = "/python-mininode-tester:0.0.1/"
OVERWINTER_VERSION_GROUP_ID = 0x03C48270
MAX_INV_SZ = 50000
@@ -328,7 +330,7 @@ class CInv(object):
class CBlockLocator(object):
def __init__(self):
self.nVersion = MY_VERSION
self.nVersion = SPROUT_PROTO_VERSION
self.vHave = []
def deserialize(self, f):
@@ -565,20 +567,26 @@ class CTxOut(object):
class CTransaction(object):
def __init__(self, tx=None):
if tx is None:
self.fOverwintered = False
self.nVersion = 1
self.nVersionGroupId = 0
self.vin = []
self.vout = []
self.nLockTime = 0
self.nExpiryHeight = 0
self.vjoinsplit = []
self.joinSplitPubKey = None
self.joinSplitSig = None
self.sha256 = None
self.hash = None
else:
self.fOverwintered = tx.fOverwintered
self.nVersion = tx.nVersion
self.nVersionGroupId = tx.nVersionGroupId
self.vin = copy.deepcopy(tx.vin)
self.vout = copy.deepcopy(tx.vout)
self.nLockTime = tx.nLockTime
self.nExpiryHeight = tx.nExpiryHeight
self.vjoinsplit = copy.deepcopy(tx.vjoinsplit)
self.joinSplitPubKey = tx.joinSplitPubKey
self.joinSplitSig = tx.joinSplitSig
@@ -586,24 +594,46 @@ class CTransaction(object):
self.hash = None
def deserialize(self, f):
self.nVersion = struct.unpack("<i", f.read(4))[0]
header = struct.unpack("<I", f.read(4))[0]
self.fOverwintered = bool(header >> 31)
self.nVersion = header & 0x7FFFFFFF
self.nVersionGroupId = (struct.unpack("<I", f.read(4))[0]
if self.fOverwintered else 0)
isOverwinterV3 = (self.fOverwintered and
self.nVersionGroupId == OVERWINTER_VERSION_GROUP_ID and
self.nVersion == 3)
self.vin = deser_vector(f, CTxIn)
self.vout = deser_vector(f, CTxOut)
self.nLockTime = struct.unpack("<I", f.read(4))[0]
if isOverwinterV3:
self.nExpiryHeight = struct.unpack("<I", f.read(4))[0]
if self.nVersion >= 2:
self.vjoinsplit = deser_vector(f, JSDescription)
if len(self.vjoinsplit) > 0:
self.joinSplitPubKey = deser_uint256(f)
self.joinSplitSig = f.read(64)
self.sha256 = None
self.hash = None
def serialize(self):
header = (int(self.fOverwintered)<<31) | self.nVersion
isOverwinterV3 = (self.fOverwintered and
self.nVersionGroupId == OVERWINTER_VERSION_GROUP_ID and
self.nVersion == 3)
r = ""
r += struct.pack("<i", self.nVersion)
r += struct.pack("<I", header)
if self.fOverwintered:
r += struct.pack("<I", self.nVersionGroupId)
r += ser_vector(self.vin)
r += ser_vector(self.vout)
r += struct.pack("<I", self.nLockTime)
if isOverwinterV3:
r += struct.pack("<I", self.nExpiryHeight)
if self.nVersion >= 2:
r += ser_vector(self.vjoinsplit)
if len(self.vjoinsplit) > 0:
@@ -628,8 +658,10 @@ class CTransaction(object):
return True
def __repr__(self):
r = "CTransaction(nVersion=%i vin=%s vout=%s nLockTime=%i" \
% (self.nVersion, repr(self.vin), repr(self.vout), self.nLockTime)
r = ("CTransaction(fOverwintered=%r nVersion=%i nVersionGroupId=0x%08x "
"vin=%s vout=%s nLockTime=%i nExpiryHeight=%i"
% (self.fOverwintered, self.nVersion, self.nVersionGroupId,
repr(self.vin), repr(self.vout), self.nLockTime, self.nExpiryHeight))
if self.nVersion >= 2:
r += " vjoinsplit=%s" % repr(self.vjoinsplit)
if len(self.vjoinsplit) > 0:
@@ -869,12 +901,8 @@ class CAlert(object):
class msg_version(object):
command = "version"
def __init__(self, overwintered=False):
if overwintered:
self.nVersion = OVERWINTER_PROTO_VERSION
else:
self.nVersion = MY_VERSION
def __init__(self, protocol_version=SPROUT_PROTO_VERSION):
self.nVersion = protocol_version
self.nServices = 1
self.nTime = time.time()
self.addrTo = CAddress()
@@ -1231,6 +1259,38 @@ class msg_reject(object):
% (self.message, self.code, self.reason, self.data)
class msg_filteradd(object):
command = "filteradd"
def __init__(self):
self.data = ""
def deserialize(self, f):
self.data = deser_string(f)
def serialize(self):
return ser_string(self.data)
def __repr__(self):
return "msg_filteradd(data=%s)" % (repr(self.data))
class msg_filterclear(object):
command = "filterclear"
def __init__(self):
pass
def deserialize(self, f):
pass
def serialize(self):
return ""
def __repr__(self):
return "msg_filterclear()"
# This is what a callback should look like for NodeConn
# Reimplement the on_* functions to provide handling for events
class NodeConnCB(object):
@@ -1270,7 +1330,7 @@ class NodeConnCB(object):
def on_version(self, conn, message):
if message.nVersion >= 209:
conn.send_message(msg_verack())
conn.ver_send = min(MY_VERSION, message.nVersion)
conn.ver_send = min(SPROUT_PROTO_VERSION, message.nVersion)
if message.nVersion < 209:
conn.ver_recv = conn.ver_send
@@ -1331,7 +1391,7 @@ class NodeConn(asyncore.dispatcher):
"regtest": "\xaa\xe8\x3f\x5f" # regtest
}
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", overwintered=False):
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", protocol_version=SPROUT_PROTO_VERSION):
asyncore.dispatcher.__init__(self, map=mininode_socket_map)
self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport))
self.dstaddr = dstaddr
@@ -1348,7 +1408,7 @@ class NodeConn(asyncore.dispatcher):
self.disconnect = False
# stuff version msg into sendbuf
vt = msg_version(overwintered)
vt = msg_version(protocol_version)
vt.addrTo.ip = self.dstaddr
vt.addrTo.port = self.dstport
vt.addrFrom.ip = "0.0.0.0"

View File

@@ -389,9 +389,18 @@ def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
return (txid, signresult["hex"], fee)
def assert_equal(thing1, thing2):
if thing1 != thing2:
raise AssertionError("%s != %s"%(str(thing1),str(thing2)))
def assert_equal(expected, actual, message = ""):
if expected != actual:
if message:
message = "%s; " % message
raise AssertionError("%sexpected: <%s> but was: <%s>" % (message, str(expected), str(actual)))
def assert_true(condition, message = ""):
if not condition:
raise AssertionError(message)
def assert_false(condition, message = ""):
assert_true(not condition, message)
def assert_greater_than(thing1, thing2):
if thing1 <= thing2:
@@ -427,12 +436,12 @@ def wait_and_assert_operationid_status(node, myopid, in_status='success', in_err
elif status == "success":
txid = results[0]['result']['txid']
break
assert_equal(in_status, status)
if errormsg is not None:
assert(in_errormsg is not None)
assert_equal(in_errormsg in errormsg, True)
if os.getenv("PYTHON_DEBUG", ""):
print('...returned status: {}'.format(status))
if errormsg is not None:
print('...returned error: {}'.format(errormsg))
assert_equal(in_status, status)
if errormsg is not None:
assert(in_errormsg is not None)
assert_equal(in_errormsg in errormsg, True)
return txid

View File

@@ -89,6 +89,26 @@ class WalletTest (BitcoinTestFramework):
assert_equal(len(node2utxos), 2)
assert_equal(sum(int(uxto["generated"] is True) for uxto in node2utxos), 0)
# Catch an attempt to send a transaction with an absurdly high fee.
# Send 1.0 from an utxo of value 10.0 but don't specify a change output, so then
# the change of 9.0 becomes the fee, which is greater than estimated fee of 0.0019.
inputs = []
outputs = {}
for utxo in node2utxos:
if utxo["amount"] == Decimal("10.0"):
break
assert_equal(utxo["amount"], Decimal("10.0"))
inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]})
outputs[self.nodes[2].getnewaddress("")] = Decimal("1.0")
raw_tx = self.nodes[2].createrawtransaction(inputs, outputs)
signed_tx = self.nodes[2].signrawtransaction(raw_tx)
try:
self.nodes[2].sendrawtransaction(signed_tx["hex"])
except JSONRPCException,e:
errorString = e.error['message']
assert("absurdly high fees" in errorString)
assert("900000000 > 190000" in errorString)
# create both transactions
txns_to_send = []
for utxo in node0utxos:
@@ -443,6 +463,62 @@ class WalletTest (BitcoinTestFramework):
assert_equal("not an integer" in errorString, True);
myzaddr = self.nodes[0].z_getnewaddress()
recipients = [ {"address": myzaddr, "amount": Decimal('0.0') } ]
errorString = ''
# Make sure that amount=0 transactions can use the default fee
# without triggering "absurd fee" errors
try:
myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
assert(myopid)
except JSONRPCException,e:
errorString = e.error['message']
print errorString
assert(False)
# This fee is larger than the default fee and since amount=0
# it should trigger error
fee = Decimal('0.1')
recipients = [ {"address": myzaddr, "amount": Decimal('0.0') } ]
minconf = 1
errorString = ''
try:
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee)
except JSONRPCException,e:
errorString = e.error['message']
assert('Small transaction amount' in errorString)
# This fee is less than default and greater than amount, but still valid
fee = Decimal('0.0000001')
recipients = [ {"address": myzaddr, "amount": Decimal('0.00000001') } ]
minconf = 1
errorString = ''
try:
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee)
assert(myopid)
except JSONRPCException,e:
errorString = e.error['message']
print errorString
assert(False)
# Make sure amount=0, fee=0 transaction are valid to add to mempool
# though miners decide whether to add to a block
fee = Decimal('0.0')
minconf = 1
recipients = [ {"address": myzaddr, "amount": Decimal('0.0') } ]
errorString = ''
try:
myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee)
assert(myopid)
except JSONRPCException,e:
errorString = e.error['message']
print errorString
assert(False)
if __name__ == '__main__':
WalletTest ().main ()

View File

@@ -0,0 +1,77 @@
#!/usr/bin/env python2
# Copyright (c) 2018 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, start_nodes
# Test wallet address behaviour across network upgradesa\
class WalletAddressesTest(BitcoinTestFramework):
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir, [[
'-nuparams=5ba81b19:202', # Overwinter
'-nuparams=76b809bb:204', # Sapling
]] * 4)
def run_test(self):
def addr_checks(default_type):
# Check default type, as well as explicit types
types_and_addresses = [
(default_type, self.nodes[0].z_getnewaddress()),
('sprout', self.nodes[0].z_getnewaddress('sprout')),
('sapling', self.nodes[0].z_getnewaddress('sapling')),
]
all_addresses = self.nodes[0].z_listaddresses()
for addr_type, addr in types_and_addresses:
res = self.nodes[0].z_validateaddress(addr)
assert(res['isvalid'])
assert(res['ismine'])
assert_equal(res['type'], addr_type)
assert(addr in all_addresses)
# Sanity-check the test harness
assert_equal(self.nodes[0].getblockcount(), 200)
# Current height = 200 -> Sprout
# Default address type is Sprout
print "Testing height 200 (Sprout)"
addr_checks('sprout')
self.nodes[0].generate(1)
self.sync_all()
# Current height = 201 -> Sprout
# Default address type is Sprout
print "Testing height 201 (Sprout)"
addr_checks('sprout')
self.nodes[0].generate(1)
self.sync_all()
# Current height = 202 -> Overwinter
# Default address type is Sprout
print "Testing height 202 (Overwinter)"
addr_checks('sprout')
self.nodes[0].generate(1)
self.sync_all()
# Current height = 203 -> Overwinter
# Default address type is Sprout
print "Testing height 203 (Overwinter)"
addr_checks('sprout')
self.nodes[0].generate(1)
self.sync_all()
# Current height = 204 -> Sapling
# Default address type is Sprout
print "Testing height 204 (Sapling)"
addr_checks('sprout')
if __name__ == '__main__':
WalletAddressesTest().main()

View File

@@ -4,7 +4,6 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
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, stop_nodes, connect_nodes_bi, \
wait_and_assert_operationid_status, wait_bitcoinds

View File

@@ -0,0 +1,77 @@
#!/usr/bin/env python2
# Copyright (c) 2018 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_true, assert_false, wait_and_assert_operationid_status
from decimal import Decimal
class WalletChangeIndicatorTest (BitcoinTestFramework):
# Helper Methods
def generate_and_sync(self):
self.sync_all()
self.nodes[0].generate(1)
self.sync_all()
# Tests
def run_test(self):
taddr = self.nodes[1].getnewaddress()
zaddr1 = self.nodes[1].z_getnewaddress()
zaddr2 = self.nodes[1].z_getnewaddress()
self.nodes[0].sendtoaddress(taddr, Decimal('1.0'))
self.generate_and_sync()
# Send 1 ZEC to a zaddr
wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(taddr, [{'address': zaddr1, 'amount': 1.0, 'memo': 'c0ffee01'}], 1, 0))
self.generate_and_sync()
# Check that we have received 1 note which is not change
receivedbyaddress = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
listunspent = self.nodes[1].z_listunspent()
assert_equal(1, len(receivedbyaddress), "Should have received 1 note")
assert_false(receivedbyaddress[0]['change'], "Note should not be change")
assert_equal(1, len(listunspent), "Should have 1 unspent note")
assert_false(listunspent[0]['change'], "Unspent note should not be change")
# Generate some change
wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(zaddr1, [{'address': zaddr2, 'amount': 0.6, 'memo': 'c0ffee02'}], 1, 0))
self.generate_and_sync()
# Check zaddr1 received
sortedreceived1 = sorted(self.nodes[1].z_listreceivedbyaddress(zaddr1, 0), key = lambda received: received['amount'])
assert_equal(2, len(sortedreceived1), "zaddr1 Should have received 2 notes")
assert_equal(Decimal('0.4'), sortedreceived1[0]['amount'])
assert_true(sortedreceived1[0]['change'], "Note valued at 0.4 should be change")
assert_equal(Decimal('1.0'), sortedreceived1[1]['amount'])
assert_false(sortedreceived1[1]['change'], "Note valued at 1.0 should not be change")
# Check zaddr2 received
sortedreceived2 = sorted(self.nodes[1].z_listreceivedbyaddress(zaddr2, 0), key = lambda received: received['amount'])
assert_equal(1, len(sortedreceived2), "zaddr2 Should have received 1 notes")
assert_equal(Decimal('0.6'), sortedreceived2[0]['amount'])
assert_false(sortedreceived2[0]['change'], "Note valued at 0.6 should not be change")
# Check unspent
sortedunspent = sorted(self.nodes[1].z_listunspent(), key = lambda received: received['amount'])
assert_equal(2, len(sortedunspent), "Should have 2 unspent notes")
assert_equal(Decimal('0.4'), sortedunspent[0]['amount'])
assert_true(sortedunspent[0]['change'], "Unspent note valued at 0.4 should be change")
assert_equal(Decimal('0.6'), sortedunspent[1]['amount'])
assert_false(sortedunspent[1]['change'], "Unspent note valued at 0.6 should not be change")
# Give node 0 a viewing key
viewing_key = self.nodes[1].z_exportviewingkey(zaddr1)
self.nodes[0].z_importviewingkey(viewing_key)
received_node0 = self.nodes[0].z_listreceivedbyaddress(zaddr1, 0)
assert_equal(2, len(received_node0))
unspent_node0 = self.nodes[0].z_listunspent(1, 9999999, True)
assert_equal(2, len(unspent_node0))
# node 0 only has a viewing key so does not see the change field
assert_false('change' in received_node0[0])
assert_false('change' in received_node0[1])
assert_false('change' in unspent_node0[0])
assert_false('change' in unspent_node0[1])
if __name__ == '__main__':
WalletChangeIndicatorTest().main()

View File

@@ -5,7 +5,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, start_node, \
from test_framework.util import assert_equal, assert_true, start_node, \
start_nodes, connect_nodes_bi, bitcoind_processes
import time
@@ -188,10 +188,24 @@ class WalletNullifiersTest (BitcoinTestFramework):
assert_equal(myzaddr in self.nodes[3].z_listaddresses(), False)
assert_equal(myzaddr in self.nodes[3].z_listaddresses(True), True)
# Node 3 should see the same received notes as node 2
assert_equal(
self.nodes[2].z_listreceivedbyaddress(myzaddr),
self.nodes[3].z_listreceivedbyaddress(myzaddr))
# Node 3 should see the same received notes as node 2; however,
# some of the notes were change for node 2 but not for node 3.
# Aside from that the recieved notes should be the same. So,
# group by txid and then check that all properties aside from
# change are equal.
node2Received = dict([r['txid'], r] for r in self.nodes[2].z_listreceivedbyaddress(myzaddr))
node3Received = dict([r['txid'], r] for r in self.nodes[3].z_listreceivedbyaddress(myzaddr))
assert_equal(len(node2Received), len(node2Received))
for txid in node2Received:
received2 = node2Received[txid]
received3 = node3Received[txid]
# the change field will be omitted for received3, but all other fields should be shared
assert_true(len(received2) >= len(received3))
for key in received2:
# check all the properties except for change
if key != 'change':
assert_equal(received2[key], received3[key])
# Node 3's balances should be unchanged without explicitly requesting
# to include watch-only balances

View File

@@ -6,6 +6,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, initialize_chain_clean, \
start_nodes, connect_nodes_bi, wait_and_assert_operationid_status
from test_framework.authproxy import JSONRPCException
from decimal import Decimal
@@ -46,6 +47,13 @@ class WalletOverwinterTxTest (BitcoinTestFramework):
assert_equal(bci['consensus']['nextblock'], '00000000')
assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending')
# Cannot use the expiryheight parameter of createrawtransaction if Overwinter is not active in the next block
try:
self.nodes[0].createrawtransaction([], {}, 0, 99)
except JSONRPCException,e:
errorString = e.error['message']
assert_equal("Invalid parameter, expiryheight can only be used if Overwinter is active when the transaction is mined" in errorString, True)
# Node 0 sends transparent funds to Node 2
tsendamount = Decimal('1.0')
txid_transparent = self.nodes[0].sendtoaddress(taddr2, tsendamount)
@@ -92,6 +100,24 @@ class WalletOverwinterTxTest (BitcoinTestFramework):
assert_equal(bci['consensus']['nextblock'], '5ba81b19')
assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending')
# Test using expiryheight parameter of createrawtransaction when Overwinter is active in the next block
errorString = ""
try:
self.nodes[0].createrawtransaction([], {}, 0, 499999999)
except JSONRPCException,e:
errorString = e.error['message']
assert_equal("", errorString)
try:
self.nodes[0].createrawtransaction([], {}, 0, -1)
except JSONRPCException,e:
errorString = e.error['message']
assert_equal("Invalid parameter, expiryheight must be nonnegative and less than 500000000" in errorString, True)
try:
self.nodes[0].createrawtransaction([], {}, 0, 500000000)
except JSONRPCException,e:
errorString = e.error['message']
assert_equal("Invalid parameter, expiryheight must be nonnegative and less than 500000000" in errorString, True)
# Node 0 sends transparent funds to Node 3
tsendamount = Decimal('1.0')
txid_transparent = self.nodes[0].sendtoaddress(taddr3, tsendamount)

View File

@@ -8,7 +8,7 @@ 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, stop_node, wait_and_assert_operationid_status
start_nodes, connect_nodes_bi, wait_and_assert_operationid_status
import sys
import time
@@ -96,8 +96,6 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
break
assert_equal("failed", status)
assert_equal("no UTXOs found for taddr from address" in errorString, True)
stop_node(self.nodes[3], 3)
self.nodes.pop()
# This send will fail because our wallet does not allow any change when protecting a coinbase utxo,
# as it's currently not possible to specify a change address in z_sendmany.
@@ -129,6 +127,10 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
assert_equal("failed", status)
assert_equal("wallet does not allow any change" in errorString, True)
# Add viewing key for myzaddr to Node 3
myviewingkey = self.nodes[0].z_exportviewingkey(myzaddr)
self.nodes[3].z_importviewingkey(myviewingkey, "no")
# This send will succeed. We send two coinbase utxos totalling 20.0 less a fee of 0.00010000, with no change.
shieldvalue = Decimal('20.0') - Decimal('0.0001')
recipients = []
@@ -136,9 +138,43 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
self.sync_all()
# Verify that z_listunspent can return a note that has zero confirmations
results = self.nodes[0].z_listunspent()
assert(len(results) == 0)
results = self.nodes[0].z_listunspent(0) # set minconf to zero
assert(len(results) == 1)
assert_equal(results[0]["address"], myzaddr)
assert_equal(results[0]["amount"], shieldvalue)
assert_equal(results[0]["confirmations"], 0)
# Mine the tx
self.nodes[1].generate(1)
self.sync_all()
# Verify that z_listunspent returns one note which has been confirmed
results = self.nodes[0].z_listunspent()
assert(len(results) == 1)
assert_equal(results[0]["address"], myzaddr)
assert_equal(results[0]["amount"], shieldvalue)
assert_equal(results[0]["confirmations"], 1)
assert_equal(results[0]["spendable"], True)
# Verify that z_listunspent returns note for watchonly address on node 3.
results = self.nodes[3].z_listunspent(1, 999, True)
assert(len(results) == 1)
assert_equal(results[0]["address"], myzaddr)
assert_equal(results[0]["amount"], shieldvalue)
assert_equal(results[0]["confirmations"], 1)
assert_equal(results[0]["spendable"], False)
# Verify that z_listunspent returns error when address spending key from node 0 is not available in wallet of node 1.
try:
results = self.nodes[1].z_listunspent(1, 999, False, [myzaddr])
except JSONRPCException as e:
errorString = e.error['message']
assert_equal("Invalid parameter, spending key for address does not belong to wallet" in errorString, True)
# Verify that debug=zrpcunsafe logs params, and that full txid is associated with opid
logpath = self.options.tmpdir+"/node0/regtest/debug.log"
logcounter = 0
@@ -226,7 +262,7 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 10000.0001")
myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient protected funds, have 9.9998, need 10000.0001")
wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient shielded funds, have 9.9998, need 10000.0001")
# Send will fail because of insufficient funds unless sender uses coinbase utxos
try:
@@ -333,13 +369,22 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
self.nodes[1].generate(1)
self.sync_all()
# check balances
# check balances and unspent notes
resp = self.nodes[2].z_gettotalbalance()
assert_equal(Decimal(resp["private"]), send_amount)
notes = self.nodes[2].z_listunspent()
sum_of_notes = sum([note["amount"] for note in notes])
assert_equal(Decimal(resp["private"]), sum_of_notes)
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)
notes = self.nodes[0].z_listunspent(1, 99999, False, [myzaddr])
sum_of_notes = sum([note["amount"] for note in notes])
assert_equal(Decimal(resp), sum_of_notes)
if __name__ == '__main__':
WalletProtectCoinbaseTest().main()

104
qa/rpc-tests/wallet_sapling.py Executable file
View File

@@ -0,0 +1,104 @@
#!/usr/bin/env python2
# Copyright (c) 2018 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
start_nodes,
wait_and_assert_operationid_status,
)
from decimal import Decimal
# Test wallet behaviour with Sapling addresses
class WalletSaplingTest(BitcoinTestFramework):
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir, [[
'-nuparams=5ba81b19:201', # Overwinter
'-nuparams=76b809bb:201', # Sapling
]] * 4)
def run_test(self):
# Sanity-check the test harness
assert_equal(self.nodes[0].getblockcount(), 200)
# Activate Sapling
self.nodes[2].generate(1)
self.sync_all()
taddr0 = self.nodes[0].getnewaddress()
# Skip over the address containing node 1's coinbase
self.nodes[1].getnewaddress()
taddr1 = self.nodes[1].getnewaddress()
saplingAddr0 = self.nodes[0].z_getnewaddress('sapling')
saplingAddr1 = self.nodes[1].z_getnewaddress('sapling')
# Verify addresses
assert(saplingAddr0 in self.nodes[0].z_listaddresses())
assert(saplingAddr1 in self.nodes[1].z_listaddresses())
assert_equal(self.nodes[0].z_validateaddress(saplingAddr0)['type'], 'sapling')
assert_equal(self.nodes[0].z_validateaddress(saplingAddr1)['type'], 'sapling')
# Verify balance
assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('0'))
assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('0'))
assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0'))
# Node 0 shields some funds
# taddr -> Sapling
# -> taddr (change)
recipients = []
recipients.append({"address": saplingAddr0, "amount": Decimal('20')})
myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0)
wait_and_assert_operationid_status(self.nodes[0], myopid)
self.sync_all()
self.nodes[2].generate(1)
self.sync_all()
# Verify balance
assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('20'))
assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('0'))
assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0'))
# Node 0 sends some shielded funds to node 1
# Sapling -> Sapling
# -> Sapling (change)
recipients = []
recipients.append({"address": saplingAddr1, "amount": Decimal('15')})
myopid = self.nodes[0].z_sendmany(saplingAddr0, recipients, 1, 0)
wait_and_assert_operationid_status(self.nodes[0], myopid)
self.sync_all()
self.nodes[2].generate(1)
self.sync_all()
# Verify balance
assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('5'))
assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('15'))
assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0'))
# Node 1 sends some shielded funds to node 0, as well as unshielding
# Sapling -> Sapling
# -> taddr
# -> Sapling (change)
recipients = []
recipients.append({"address": saplingAddr0, "amount": Decimal('5')})
recipients.append({"address": taddr1, "amount": Decimal('5')})
myopid = self.nodes[1].z_sendmany(saplingAddr1, recipients, 1, 0)
wait_and_assert_operationid_status(self.nodes[1], myopid)
self.sync_all()
self.nodes[2].generate(1)
self.sync_all()
# Verify balance
assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('10'))
assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('5'))
assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('5'))
if __name__ == '__main__':
WalletSaplingTest().main()

View File

@@ -9,11 +9,10 @@ from test_framework.util import assert_equal, assert_greater_than, start_nodes,\
initialize_chain_clean, connect_nodes_bi, wait_and_assert_operationid_status
import logging
import time
import math
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
fee = Decimal('0.0001') # constant (but can be changed within reason)
class ZkeyImportExportTest (BitcoinTestFramework):
@@ -22,7 +21,7 @@ class ZkeyImportExportTest (BitcoinTestFramework):
initialize_chain_clean(self.options.tmpdir, 5)
def setup_network(self, split=False):
self.nodes = start_nodes(5, self.options.tmpdir )
self.nodes = start_nodes(5, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
@@ -34,19 +33,16 @@ class ZkeyImportExportTest (BitcoinTestFramework):
def run_test(self):
[alice, bob, charlie, david, miner] = self.nodes
# the sender loses 'amount' plus fee; to_addr receives exactly 'amount'
def z_send(from_node, from_addr, to_addr, amount):
opid = from_node.z_sendmany(from_addr, [{"address": to_addr, "amount": Decimal(amount)}])
global fee
opid = from_node.z_sendmany(from_addr,
[{"address": to_addr, "amount": Decimal(amount)}], 1, fee)
wait_and_assert_operationid_status(from_node, opid)
self.sync_all()
miner.generate(1)
self.sync_all()
def z_getbalance(node, zaddr):
bal = node.z_getbalance(zaddr)
# Ignore fees for sake of comparison
round_balance = math.ceil(bal*100)/100
return round_balance
def verify_utxos(node, amts, zaddr):
amts.sort(reverse=True)
txs = node.z_listreceivedbyaddress(zaddr)
@@ -60,6 +56,12 @@ class ZkeyImportExportTest (BitcoinTestFramework):
try:
assert_equal(amts, [tx["amount"] for tx in txs])
for tx in txs:
# make sure JoinSplit keys exist and have valid values
assert_equal("jsindex" in tx, True)
assert_equal("jsoutindex" in tx, True)
assert_greater_than(tx["jsindex"], -1)
assert_greater_than(tx["jsoutindex"], -1)
except AssertionError:
logging.error(
'Expected amounts: %r; txs: %r',
@@ -107,27 +109,27 @@ class ZkeyImportExportTest (BitcoinTestFramework):
z_send(alice, alice_zaddr, bob_zaddr, amount)
logging.info("Exporting privkey from bob...")
privkey = bob.z_exportkey(bob_zaddr)
bob_privkey = bob.z_exportkey(bob_zaddr)
logging.info("Sending post-export txns...")
for amount in amounts[2:4]:
z_send(alice, alice_zaddr, bob_zaddr, amount)
print("Bob amounts:", amounts[:4])
verify_utxos(bob, amounts[:4], bob_zaddr)
# verify_utxos(charlie, [])
logging.info("Importing privkey into charlie...")
logging.info("Importing bob_privkey into charlie...")
# z_importkey rescan defaults to "whenkeyisnew", so should rescan here
charlie.z_importkey(privkey)
charlie.z_importkey(bob_privkey)
ipk_zaddr = find_imported_key(charlie, bob_zaddr)
# z_importkey should have rescanned for new key, so this should pass:
verify_utxos(charlie, amounts[:4], ipk_zaddr)
# Verify idempotent behavior:
charlie.z_importkey(privkey)
charlie.z_importkey(bob_privkey)
ipk_zaddr2 = find_imported_key(charlie, bob_zaddr)
assert_equal(ipk_zaddr, ipk_zaddr2)
# amounts should be unchanged
verify_utxos(charlie, amounts[:4], ipk_zaddr2)
@@ -140,22 +142,26 @@ class ZkeyImportExportTest (BitcoinTestFramework):
verify_utxos(charlie, amounts, ipk_zaddr)
verify_utxos(charlie, amounts, ipk_zaddr2)
# keep track of the fees incurred by bob (his sends)
bob_fee = Decimal(0)
# Try to reproduce zombie balance reported in #1936
# At generated zaddr, receive ZEC, and send ZEC back out. bob -> alice
for amount in amounts[:2]:
print("Sending amount from bob to alice: ", amount)
z_send(bob, bob_zaddr, alice_zaddr, amount)
bob_fee += fee
balance = float(sum(amounts) - sum(amounts[:2]))
assert_equal(z_getbalance(bob, bob_zaddr), balance)
bob_balance = sum(amounts[2:]) - bob_fee
assert_equal(bob.z_getbalance(bob_zaddr), bob_balance)
# z_import onto new node "david" (blockchain rescan, default or True?)
david.z_importkey(privkey)
david.z_importkey(bob_privkey)
d_ipk_zaddr = find_imported_key(david, bob_zaddr)
# Check if amt bob spent is deducted for charlie and david
assert_equal(z_getbalance(charlie, ipk_zaddr), balance)
assert_equal(z_getbalance(david, d_ipk_zaddr), balance)
assert_equal(charlie.z_getbalance(ipk_zaddr), bob_balance)
assert_equal(david.z_getbalance(d_ipk_zaddr), bob_balance)
if __name__ == '__main__':
ZkeyImportExportTest().main()

View File

@@ -5,7 +5,6 @@ import plyvel
import progressbar
import os
import stat
import struct
import subprocess
import sys
import tarfile

View File

@@ -4,6 +4,7 @@
#
import argparse
from glob import glob
import os
import re
import subprocess
@@ -62,12 +63,18 @@ def check_security_hardening():
# PIE, RELRO, Canary, and NX are tested by make check-security.
ret &= subprocess.call(['make', '-C', repofile('src'), 'check-security']) == 0
# The remaining checks are only for ELF binaries
# Assume that if zcashd is an ELF binary, they all are
with open(repofile('src/zcashd'), 'rb') as f:
magic = f.read(4)
if not magic.startswith(b'\x7fELF'):
return ret
ret &= test_rpath_runpath('src/zcashd')
ret &= test_rpath_runpath('src/zcash-cli')
ret &= test_rpath_runpath('src/zcash-gtest')
ret &= test_rpath_runpath('src/zcash-tx')
ret &= test_rpath_runpath('src/test/test_bitcoin')
ret &= test_rpath_runpath('src/zcash/GenerateParams')
# NOTE: checksec.sh does not reliably determine whether FORTIFY_SOURCE
# is enabled for the entire binary. See issue #915.
@@ -76,16 +83,18 @@ def check_security_hardening():
ret &= test_fortify_source('src/zcash-gtest')
ret &= test_fortify_source('src/zcash-tx')
ret &= test_fortify_source('src/test/test_bitcoin')
ret &= test_fortify_source('src/zcash/GenerateParams')
return ret
def ensure_no_dot_so_in_depends():
arch_dir = os.path.join(
REPOROOT,
'depends',
'x86_64-unknown-linux-gnu',
)
depends_dir = os.path.join(REPOROOT, 'depends')
arch_dir = os.path.join(depends_dir, 'x86_64-unknown-linux-gnu')
if not os.path.isdir(arch_dir):
# Not Linux, try MacOS
arch_dirs = glob(os.path.join(depends_dir, 'x86_64-apple-darwin*'))
if arch_dirs:
# Just try the first one; there will only be on in CI
arch_dir = arch_dirs[0]
exit_code = 0
@@ -99,7 +108,7 @@ def ensure_no_dot_so_in_depends():
exit_code = 1
else:
exit_code = 2
print "arch-specific build dir not present: {}".format(arch_dir)
print "arch-specific build dir not present"
print "Did you build the ./depends tree?"
print "Are you on a currently unsupported architecture?"