Skip to content

Commit

Permalink
Shield staking Functional test
Browse files Browse the repository at this point in the history
  • Loading branch information
panleone committed Sep 13, 2023
1 parent 9191b68 commit 1e5f3dd
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 71 deletions.
124 changes: 64 additions & 60 deletions src/consensus/upgrades.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,66 +13,70 @@
* We are using it in the -nuparams startup arg and input it with spaces is just ugly.
*/
const struct NUInfo NetworkUpgradeInfo[Consensus::MAX_NETWORK_UPGRADES] = {
{
/*.strName =*/ "Base",
/*.strInfo =*/ "PIVX network",
},
{
/*.strName =*/ "PoS",
/*.strInfo =*/ "Proof of Stake Consensus activation",
},
{
/*.strName =*/ "PoS_v2",
/*.strInfo =*/ "New selection for stake modifier",
},
{
/*.strName =*/ "Zerocoin",
/*.strInfo =*/ "ZeroCoin protocol activation - start block v4",
},
{
/*.strName =*/ "Zerocoin_v2",
/*.strInfo =*/ "New zerocoin serials and zPOS start",
},
{
/*.strName =*/ "BIP65",
/*.strInfo =*/ "CLTV (BIP65) activation - start block v5",
},
{
/*.strName =*/ "Zerocoin_Public",
/*.strInfo =*/ "Activation of zerocoin public spends (spend v3)",
},
{
/*.strName =*/ "PIVX_v3.4",
/*.strInfo =*/ "New 256-bit stake modifier - start block v6",
},
{
/*.strName =*/ "PIVX_v4.0",
/*.strInfo =*/ "New message sigs - start block v7 - time protocol - zc spend v4",
},
{
/*.strName =*/ "v5_shield",
/*.strInfo =*/ "Sapling Shield - start block v8 - start transaction v3",
},
{
/*.strName =*/ "PIVX_v5.2",
/*.strInfo =*/ "New cold-staking rules",
},
{
/*.strName =*/ "PIVX_v5.3",
/*.strInfo =*/ "New staking rules",
},
{
/*.strName =*/ "PIVX_v5.5",
/*.strInfo =*/ "New rewards structure",
},
{
/*.strName =*/ "v6_evo",
/*.strInfo =*/ "Deterministic Masternodes",
},
{
/*.strName =*/ "Test_dummy",
/*.strInfo =*/ "Test dummy info",
},
{
/*.strName =*/"Base",
/*.strInfo =*/"PIVX network",
},
{
/*.strName =*/"PoS",
/*.strInfo =*/"Proof of Stake Consensus activation",
},
{
/*.strName =*/"PoS_v2",
/*.strInfo =*/"New selection for stake modifier",
},
{
/*.strName =*/"Zerocoin",
/*.strInfo =*/"ZeroCoin protocol activation - start block v4",
},
{
/*.strName =*/"Zerocoin_v2",
/*.strInfo =*/"New zerocoin serials and zPOS start",
},
{
/*.strName =*/"BIP65",
/*.strInfo =*/"CLTV (BIP65) activation - start block v5",
},
{
/*.strName =*/"Zerocoin_Public",
/*.strInfo =*/"Activation of zerocoin public spends (spend v3)",
},
{
/*.strName =*/"PIVX_v3.4",
/*.strInfo =*/"New 256-bit stake modifier - start block v6",
},
{
/*.strName =*/"PIVX_v4.0",
/*.strInfo =*/"New message sigs - start block v7 - time protocol - zc spend v4",
},
{
/*.strName =*/"v5_shield",
/*.strInfo =*/"Sapling Shield - start block v8 - start transaction v3",
},
{
/*.strName =*/"PIVX_v5.2",
/*.strInfo =*/"New cold-staking rules",
},
{
/*.strName =*/"PIVX_v5.3",
/*.strInfo =*/"New staking rules",
},
{
/*.strName =*/"PIVX_v5.5",
/*.strInfo =*/"New rewards structure",
},
{
/*.strName =*/"v6_evo",
/*.strInfo =*/"Deterministic Masternodes",
},
{
/*.strName =*/"shield_staking",
/*.strInfo =*/"Shield Staking",
},
{
/*.strName =*/"Test_dummy",
/*.strInfo =*/"Test dummy info",
},
};

UpgradeState NetworkUpgradeState(
Expand Down
2 changes: 1 addition & 1 deletion src/primitives/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class CBlock : public CBlockHeader
READWRITE(obj.vchBlockSig);

// Shield Staking Proof
if (obj.nVersion >= 12 && obj.IsProofOfStake()) {
if (obj.nVersion >= 12 && obj.IsProofOfShieldStake()) {
READWRITE(obj.shieldStakeProof);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/primitives/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ bool CTransaction::IsCoinStake() const
{
if (vin.empty())
return false;
if (!sapData->vShieldedSpend.empty())
if (sapData && !sapData->vShieldedSpend.empty())
return false;
bool fAllowNull = vin[0].IsZerocoinSpend();
if (vin[0].prevout.IsNull() && !fAllowNull)
Expand Down
12 changes: 6 additions & 6 deletions test/functional/mining_pos_coldStaking.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def run_test(self):
assert self.nodes[1].lockunspent(False, True, [{"txid": x['txid'], "vout": x['vout']}])
# check that it cannot stake
sleep(1)
assert_equal(self.nodes[1].getstakingstatus()["stakeablecoins"], 0)
assert_equal(self.nodes[1].getstakingstatus()["transparent_stakeable_coins"], 0)
# create shielded balance for node 0
self.log.info("Shielding some coins for node0...")
self.nodes[0].shieldsendmany("from_transparent", [{"address": self.nodes[0].getnewshieldaddress(),
Expand Down Expand Up @@ -205,7 +205,7 @@ def run_test(self):
# -----------------------------------------------------------
print("*** 7 ***")
self.log.info("Trying to generate a cold-stake block before whitelisting the owner...")
assert_equal(self.nodes[1].getstakingstatus()["stakeablecoins"], 0)
assert_equal(self.nodes[1].getstakingstatus()["transparent_stakeable_coins"], 0)
assert_equal(self.nodes[1].listdelegators(), [])
self.log.info("Nice. Cold staker was NOT able to create the block yet.")

Expand All @@ -232,7 +232,7 @@ def run_test(self):
# 9) check that the staker can use the coins to stake a block with internal miner.
# --------------------------------------------------------------------------------
print("*** 9 ***")
assert_equal(self.nodes[1].getstakingstatus()["stakeablecoins"], NUM_OF_INPUTS-1)
assert_equal(self.nodes[1].getstakingstatus()["transparent_stakeable_coins"], NUM_OF_INPUTS-1)
self.log.info("Generating one valid cold-stake block...")
self.mocktime = self.generate_pos(1, self.mocktime)
self.log.info("New block created by cold-staking. Trying to submit...")
Expand Down Expand Up @@ -338,12 +338,12 @@ def run_test(self):
assert ret
assert_equal(self.nodes[1].listdelegators(), [])
assert_equal(self.nodes[1].listdelegators(True)[0]["address"], owner_address)
assert_equal(self.nodes[1].getstakingstatus()["stakeablecoins"], 0)
assert_equal(self.nodes[1].getstakingstatus()["transparent_stakeable_coins"], 0)
self.log.info("Re-enable delegation")
ret = self.nodes[1].delegatoradd(owner_address)
assert ret
assert_equal(self.nodes[1].listdelegators()[0]["address"], owner_address)
assert_equal(self.nodes[1].getstakingstatus()["stakeablecoins"], len(stakeable_coins))
assert_equal(self.nodes[1].getstakingstatus()["transparent_stakeable_coins"], len(stakeable_coins))
self.log.info("Cancel the stake delegation spending the delegated utxos...")
delegated_utxos = getDelegatedUtxos(self.nodes[0].listunspent())
# remove one utxo to spend later
Expand Down Expand Up @@ -379,7 +379,7 @@ def run_test(self):
# -----------------------------------------------------------
print("*** 14 ***")
self.log.info("Trying to generate one cold-stake block again...")
assert_equal(self.nodes[1].getstakingstatus()["stakeablecoins"], 0)
assert_equal(self.nodes[1].getstakingstatus()["transparent_stakeable_coins"], 0)
self.log.info("Good. Cold staker was NOT able to create any more blocks.")

# 15) check balances when mature.
Expand Down
76 changes: 76 additions & 0 deletions test/functional/mining_shield_pos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env python3
# Copyright (c) 2023 The PIVX Core 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 PivxTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
disconnect_nodes,
)


class PIVX_ShieldStakingTest(PivxTestFramework):

def set_test_params(self):
self.num_nodes = 3
self.setup_clean_chain = True

def run_test(self):
self.log.info("Shield stake functional tests")

# Mine enough blocks to activate shield staking" + a bonus so node0 has enough pivs to mine the final block
self.nodes[0].generate(800)
self.sync_all()

# Send some shielded notes to node1
saplingAddr1 = self.nodes[1].getnewshieldaddress()
txid = self.nodes[0].sendtoaddress(saplingAddr1, 40000, "", "", True)

# Generate more blocks so the shield notes becomes stakeable
self.nodes[0].generate(20)
self.sync_all()

# Sanity check, shield staking is activated
assert_equal(self.nodes[0].getblockchaininfo()['upgrades']['v5 shield']['status'], 'active')
assert_equal(self.nodes[0].getblockchaininfo()['upgrades']['v6 evo']['status'], 'active')
assert_equal(self.nodes[0].getblockchaininfo()['upgrades']['shield staking']['status'], 'active')

# Node1 has exactly one shield stakeable note
assert_equal(self.nodes[1].getstakingstatus()['shield_stakeables_notes'], 1)
assert_equal(self.nodes[1].getstakingstatus()['transparent_stakeable_coins'], 0)

# Before generating the shield stake block isolate node 2:
disconnect_nodes(self.nodes[0], 2)
disconnect_nodes(self.nodes[2], 0)
disconnect_nodes(self.nodes[1], 2)
disconnect_nodes(self.nodes[2], 1)

# Generate the block and check that reward is 4 shield PIVs
initialBalance = self.nodes[1].getshieldbalance()
shieldStakeBlockHash = self.nodes[1].generate(1)[0]
assert_equal(self.nodes[1].getshieldbalance()-initialBalance, 4)

# Check that a loose coinShieldStakeTx cannot go in mempool
coinShieldStakeTxHash = self.nodes[1].getblock(shieldStakeBlockHash)['tx'][1]
coinShieldStakeTxHex = self.nodes[1].gettransaction(coinShieldStakeTxHash)['hex']
assert_raises_rpc_error(-26, "coinshieldstake", self.nodes[2].sendrawtransaction, coinShieldStakeTxHex)

# Check that node0 accepted the block:
self.sync_all(self.nodes[0:2])
assert_equal(self.nodes[1].getblockhash(821), shieldStakeBlockHash)
assert_equal(self.nodes[0].getblockhash(821), shieldStakeBlockHash)

# Finally verify that the reward can be spent:
recipient = [{"address": self.nodes[0].getnewshieldaddress(), "amount": (initialBalance+2)}]
txid = self.nodes[1].shieldsendmany("from_shield", recipient)
self.sync_all(self.nodes[0:2])
blockHash = self.nodes[0].generate(1)[0]
self.sync_all(self.nodes[0:2])
assert (txid in self.nodes[0].getblock(blockHash)['tx'])
assert_equal(self.nodes[1].getblockhash(822), blockHash)


if __name__ == '__main__':
PIVX_ShieldStakingTest().main()
6 changes: 3 additions & 3 deletions test/functional/test_framework/test_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -886,8 +886,8 @@ def generate_pos(self, node_id, btime=None):
rpc_conn = self.nodes[node_id]
ss = rpc_conn.getstakingstatus()
assert ss["walletunlocked"]
assert ss["stakeablecoins"] > 0
assert ss["stakingbalance"] > 0.0
assert ss["transparent_stakeable_coins"] > 0
assert ss["transparent_staking_balance"] > 0.0
if btime is not None:
next_btime = btime + 60
fStaked = False
Expand All @@ -902,7 +902,7 @@ def generate_pos(self, node_id, btime=None):
# couldn't generate block. check that this node can still stake (after 60 failures)
if failures > 60:
ss = rpc_conn.getstakingstatus()
if not (ss["walletunlocked"] and ss["stakeablecoins"] > 0 and ss["stakingbalance"] > 0.0):
if not (ss["walletunlocked"] and ss["transparent_stakeable_coins"] > 0 and ss["transparent_staking_balance"] > 0.0):
raise AssertionError("Node %d unable to stake!" % node_id)
# try to stake one sec in the future
if btime is not None:
Expand Down
1 change: 1 addition & 0 deletions test/functional/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
'rpc_bind.py --nonloopback', # ~ 126 sec
'feature_uacomment.py', # ~ 125 sec
'interface_rest.py', # ~ 120 sec
'mining_shield_pos.py', # ~ 120 sec

# vv Tests less than 2m vv
'wallet_upgrade.py', # ~ 119 sec
Expand Down

0 comments on commit 1e5f3dd

Please sign in to comment.