Skip to content

Commit

Permalink
[Tests] Refactor zerocoin_valid_public_spend into zerocoin_spends
Browse files Browse the repository at this point in the history
Use PoS cache with pre-minted zerocoins in node2.
Test also v2 spends.
Test balances.
Github-Pull: #1218
Rebased-From: 5821e0b
  • Loading branch information
random-zebra authored and Fuzzbawls committed Jan 11, 2020
1 parent 0b551a9 commit ccd5b80
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 196 deletions.
2 changes: 1 addition & 1 deletion test/functional/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@

'p2p_pos_fakestake.py',
'p2p_pos_fakestake_accepted.py',
'zerocoin_valid_public_spend.py',
'zerocoin_spends.py',
'p2p_zpos_fakestake.py',
#'p2p_zpos_fakestake_accepted.py',
#'zerocoin_wrapped_serials.py',
Expand Down
207 changes: 207 additions & 0 deletions test/functional/zerocoin_spends.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
#!/usr/bin/env python3
# Copyright (c) 2019 The PIVX developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

'''
Tests v2, v3 and v4 Zerocoin Spends
'''


from time import sleep

from test_framework.authproxy import JSONRPCException
from test_framework.test_framework import PivxTestFramework
from test_framework.util import (
sync_blocks,
assert_equal,
assert_greater_than,
assert_raises_rpc_error,
generate_pos,
set_node_times,
activate_spork,
deactivate_spork,
is_spork_active,
DecimalAmt
)


class ZerocoinSpendTest(PivxTestFramework):

def set_test_params(self):
self.num_nodes = 3
# node 0 and node 1 move the chain (node 0 also sets the sporks)
# node 2 does the spends
self.extra_args = [['-staking=0']]*self.num_nodes
self.extra_args[0].append('-sporkkey=932HEevBSujW2ud7RfB1YF91AFygbBRQj3de3LyaCRqNzKKgWXi')

def setup_chain(self):
# Start with PoS cache: 330 blocks
self._initialize_chain(toPosPhase=True)
self.enable_mocktime()

def log_title(self):
title = "*** Starting %s ***" % self.__class__.__name__
underline = "-" * len(title)
description = "Tests v2, v3 and v4 Zerocoin Spends."
self.log.info("\n\n%s\n%s\n%s\n", title, underline, description)

def setV4SpendEnforcement(self, btime, fEnable=True):
sporkId = "SPORK_18_ZEROCOIN_PUBLICSPEND_V4"
# update spork 18 with node[0]
if fEnable:
self.log.info("Enabling v4 PublicSpend version with SPORK 18...")
res = activate_spork(self.nodes, 0, sporkId)
else:
self.log.info("Enabling v3 PublicSpend version with SPORK 18...")
res = deactivate_spork(self.nodes, 0, sporkId)
assert_equal(res, "success")
sleep(1)
# check that node[1] receives it
assert_equal(fEnable, is_spork_active(self.nodes, 1, sporkId))
self.log.info("done")

def run_test(self):

def get_zerocoin_data(coin):
return coin["s"], coin["r"], coin["k"], coin["id"], coin["d"], coin["t"]

def check_balances(denom, zpiv_bal, piv_bal):
zpiv_bal -= denom
assert_equal(self.nodes[2].getzerocoinbalance()['Total'], zpiv_bal)
piv_bal += denom
wi = self.nodes[2].getwalletinfo()
assert_equal(wi['balance'] + wi['immature_balance'], piv_bal)
return zpiv_bal, piv_bal

def stake_4_blocks(block_time):
for peer in range(2):
for i in range(2):
block_time = generate_pos(self.nodes, peer, block_time)
sync_blocks(self.nodes)
return block_time

def check_tx_in_chain(txid):
rawTx = self.nodes[0].getrawtransaction(txid, 1)
assert_greater_than(rawTx["confirmations"], 0)

self.log_title()
block_time = self.mocktime
set_node_times(self.nodes, block_time)

# Start with cache balances
wi = self.nodes[2].getwalletinfo()
balance = wi['balance'] + wi['immature_balance']
zpiv_balance = self.nodes[2].getzerocoinbalance()['Total']
assert_equal(balance, DecimalAmt(13833.92))
assert_equal(zpiv_balance, 6666)

# Export zerocoin data
listmints = self.nodes[2].listmintedzerocoins(True, True)
serial_ids = [mint["serial hash"] for mint in listmints]
exported_zerocoins = [x for x in self.nodes[2].exportzerocoins(False) if x["id"] in serial_ids]
assert_equal(8, len(exported_zerocoins))

# 1) Try to do a v3 spend before activation
self.log.info("Trying to make a public spend...")
serial_0, randomness_0, privkey_0, id_0, denom_0, tx_0 = get_zerocoin_data(exported_zerocoins[0])
assert_raises_rpc_error(-4, "The transaction was rejected!",
self.nodes[2].spendrawzerocoin, serial_0, randomness_0, denom_0, privkey_0, "", tx_0)
self.log.info("GOOD: v3 spend is not possible yet.")

# 2) Spend one minted coin - spend v2 (serial_0)
self.log.info("Spending the minted coin with serial %s..." % serial_0[:16])
txid = self.nodes[2].spendzerocoin(denom_0, False, False, "", False)['txid']
# stake 4 blocks - check it gets included on chain and check balances
block_time = stake_4_blocks(block_time)
check_tx_in_chain(txid)
zpiv_balance, balance = check_balances(denom_0, zpiv_balance, balance)
self.log.info("--> VALID COIN SPEND (v2) PASSED")

# 3) stake more blocks - save a v3 spend for later (serial_1)
serial_1, randomness_1, privkey_1, id_1, denom_1, tx_1 = get_zerocoin_data(exported_zerocoins[1])
self.log.info("Staking 70 blocks to get to public spend activation")
for j in range(5):
for peer in range(2):
for i in range(7):
block_time = generate_pos(self.nodes, peer, block_time)
sync_blocks(self.nodes)
old_spend_v3 = self.nodes[2].createrawzerocoinpublicspend(id_1)

# 4) Check spend v2 disabled
serial_2, randomness_2, privkey_2, id_2, denom_2, tx_2 = get_zerocoin_data(exported_zerocoins[2])
self.log.info("Trying to spend using the old coin spend method..")
try:
self.nodes[2].spendzerocoin(denom_2, False, False, "", False)
except JSONRPCException as e:
# JSONRPCException was thrown as expected. Check the code and message values are correct.
if e.error["code"] != -4:
raise AssertionError("Unexpected JSONRPC error code %i" % e.error["code"])
if ([x for x in ["Couldn't generate the accumulator witness",
"The transaction was rejected!"] if x in e.error['message']] == []):
raise AssertionError("Expected substring not found:" + e.error['message'])
except Exception as e:
raise AssertionError("Unexpected exception raised: " + type(e).__name__)
self.log.info("GOOD: v2 spend was not possible.")

# 5) Spend one minted coin - spend v3 (serial_2)
self.log.info("Spending the minted coin with serial %s..." % serial_2[:16])
txid = self.nodes[2].spendzerocoinmints([id_2])['txid']
# stake 4 blocks - check it gets included on chain and check balances
block_time = stake_4_blocks(block_time)
check_tx_in_chain(txid)
zpiv_balance, balance = check_balances(denom_2, zpiv_balance, balance)
self.log.info("--> VALID PUBLIC COIN SPEND (v3) PASSED")

# 6) Check double spends - spend v3
self.log.info("Trying to spend the serial twice now...")
assert_raises_rpc_error(-4, "Trying to spend an already spent serial",
self.nodes[2].spendrawzerocoin, serial_2, randomness_2, denom_2, privkey_2, "", tx_2)
self.log.info("GOOD: Double-spending transaction did not verify.")

# 7) Activate v4 spends with SPORK_18
self.setV4SpendEnforcement(block_time)

# 8) Spend one minted coin - spend v4 (serial_3)
serial_3, randomness_3, privkey_3, id_3, denom_3, tx_3 = get_zerocoin_data(exported_zerocoins[3])
self.log.info("Spending the minted coin with serial %s..." % serial_3[:16])
txid = self.nodes[2].spendzerocoinmints([id_3])['txid']
# stake 4 blocks - check it gets included on chain and check balances
block_time = stake_4_blocks(block_time)
check_tx_in_chain(txid)
zpiv_balance, balance = check_balances(denom_3, zpiv_balance, balance)
self.log.info("--> VALID PUBLIC COIN SPEND (v4) PASSED")

# 9) Check double spends - spend v4
self.log.info("Trying to spend the serial twice now...")
assert_raises_rpc_error(-4, "Trying to spend an already spent serial",
self.nodes[2].spendrawzerocoin, serial_3, randomness_3, denom_3, privkey_3, "", tx_3)
self.log.info("GOOD: Double-spending transaction did not verify.")

# 10) Try to relay old v3 spend now (serial_1)
self.log.info("Trying to send old v3 spend now...")
assert_raises_rpc_error(-26, "bad-txns-invalid-zpiv",
self.nodes[2].sendrawtransaction, old_spend_v3)
self.log.info("GOOD: Old transaction not sent.")

# 11) Try to double spend with v4 a mint already spent with v3 (serial_2)
self.log.info("Trying to double spend v4 against v3...")
assert_raises_rpc_error(-4, "Trying to spend an already spent serial",
self.nodes[2].spendrawzerocoin, serial_2, randomness_2, denom_2, privkey_2, "", tx_2)
self.log.info("GOOD: Double-spending transaction did not verify.")

# 12) Reactivate v3 spends and try to spend the old saved one (serial_1) again
self.setV4SpendEnforcement(block_time, False)
self.log.info("Trying to send old v3 spend now (serial: %s...)" % serial_1[:16])
txid = self.nodes[2].sendrawtransaction(old_spend_v3)
# stake 4 blocks - check it gets included on chain and check balances
_ = stake_4_blocks(block_time)
check_tx_in_chain(txid)
# need to reset spent mints since this was a raw broadcast
self.nodes[2].resetmintzerocoin()
_, _ = check_balances(denom_1, zpiv_balance, balance)
self.log.info("--> VALID PUBLIC COIN SPEND (v3) PASSED")


if __name__ == '__main__':
ZerocoinSpendTest().main()
Loading

0 comments on commit ccd5b80

Please sign in to comment.