Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions doc/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ RPC Changes

- "CoinStake" JSON object in `getblock` output is removed, and replaced with the strings "stakeModifier" and "hashProofOfStake"


- "isPublicSpend" boolean (optional) input parameter is removed from the following commands:
- `createrawzerocoinspend`
- `spendzerocoin`
Expand All @@ -96,16 +97,39 @@ RPC Changes

These commands are now able to create only *public* spends (private spends were already enabled only on regtest).


- "mintchange" and "minimizechange" boolean input parameters are removed from the following commands:
- `spendzerocoin`

Mints are disabled, therefore it is no longer possible to mint the change of a zerocoin spend. The change is minimized by default.


- `setstakesplitthreshold` now accepts decimal amounts. If the provided value is `0`, split staking gets disabled. `getstakesplitthreshold` returns a double.

- `dumpwallet` no longer allows overwriting files. This is a security measure
as well as prevents dangerous user mistakes.

- The output of `getstakingstatus` was reworked. It now shows the following information:
```
{
"staking_status": true|false, (boolean) whether the wallet is staking or not
"staking_enabled": true|false, (boolean) whether staking is enabled/disabled in pivx.conf
"coldstaking_enabled": true|false, (boolean) whether cold-staking is enabled/disabled in pivx.conf
"haveconnections": true|false, (boolean) whether network connections are present
"mnsync": true|false, (boolean) whether masternode data is synced
"walletunlocked": true|false, (boolean) whether the wallet is unlocked
"stakeablecoins": n, (numeric) number of stakeable UTXOs
"stakingbalance": d, (numeric) PIV value of the stakeable coins (minus reserve balance, if any)
"stakesplitthreshold": d, (numeric) value of the current threshold for stake split
"lastattempt_age": n, (numeric) seconds since last stake attempt
"lastattempt_depth": n, (numeric) depth of the block on top of which the last stake attempt was made
"lastattempt_hash": xxx, (hex string) hash of the block on top of which the last stake attempt was made
"lastattempt_coins": n, (numeric) number of stakeable coins available during last stake attempt
"lastattempt_tries": n, (numeric) number of stakeable coins checked during last stake attempt
}
```


### Removed commands

The following commands have been removed from the RPC interface:
Expand Down
48 changes: 30 additions & 18 deletions src/rpc/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,16 +592,20 @@ UniValue getstakingstatus(const UniValue& params, bool fHelp)

"\nResult:\n"
"{\n"
" \"staking_status\": true|false, (boolean) if the wallet is staking or not\n"
" \"staking_enabled\": true|false, (boolean) if staking is enabled/disabled in pivx.conf\n"
" \"tiptime\": n, (integer) chain tip blocktime\n"
" \"haveconnections\": true|false, (boolean) if network connections are present\n"
" \"mnsync\": true|false, (boolean) if masternode data is synced\n"
" \"walletunlocked\": true|false, (boolean) if the wallet is unlocked\n"
" \"stakeablecoins\": true|false, (boolean) if the wallet has mintable balance (greater than reserve balance)\n"
" \"hashLastStakeAttempt\": xxx (hex string) hash of last block on top of which the miner attempted to stake\n"
" \"heightLastStakeAttempt\": n (integer) height of last block on top of which the miner attempted to stake\n"
" \"timeLastStakeAttempt\": n (integer) time of last attempted stake\n"
" \"staking_status\": true|false, (boolean) whether the wallet is staking or not\n"
" \"staking_enabled\": true|false, (boolean) whether staking is enabled/disabled in pivx.conf\n"
" \"coldstaking_enabled\": true|false, (boolean) whether cold-staking is enabled/disabled in pivx.conf\n"
" \"haveconnections\": true|false, (boolean) whether network connections are present\n"
" \"mnsync\": true|false, (boolean) whether the required masternode/spork data is synced\n"
" \"walletunlocked\": true|false, (boolean) whether the wallet is unlocked\n"
" \"stakeablecoins\": n (numeric) number of stakeable UTXOs\n"
" \"stakingbalance\": d (numeric) PIV value of the stakeable coins (minus reserve balance, if any)\n"
" \"stakesplitthreshold\": d (numeric) value of the current threshold for stake split\n"
" \"lastattempt_age\": n (numeric) seconds since last stake attempt\n"
" \"lastattempt_depth\": n (numeric) depth of the block on top of which the last stake attempt was made\n"
" \"lastattempt_hash\": xxx (hex string) hash of the block on top of which the last stake attempt was made\n"
" \"lastattempt_coins\": n (numeric) number of stakeable coins available during last stake attempt\n"
" \"lastattempt_tries\": n (numeric) number of stakeable coins checked during last stake attempt\n"
"}\n"

"\nExamples:\n" +
Expand All @@ -615,16 +619,24 @@ UniValue getstakingstatus(const UniValue& params, bool fHelp)
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("staking_status", pwalletMain->pStakerStatus->IsActive()));
obj.push_back(Pair("staking_enabled", GetBoolArg("-staking", true)));
obj.push_back(Pair("tiptime", (int)chainActive.Tip()->nTime));
bool fColdStaking = GetBoolArg("-coldstaking", true);
obj.push_back(Pair("coldstaking_enabled", fColdStaking));
obj.push_back(Pair("haveconnections", !vNodes.empty()));
obj.push_back(Pair("mnsync", masternodeSync.IsSynced()));
obj.push_back(Pair("mnsync", !masternodeSync.NotCompleted()));
obj.push_back(Pair("walletunlocked", !pwalletMain->IsLocked()));
obj.push_back(Pair("stakeablecoins", pwalletMain->StakeableCoins()));
uint256 lastHash = pwalletMain->pStakerStatus->GetLastHash();
obj.push_back(Pair("hashLastStakeAttempt", lastHash.GetHex()));
obj.push_back(Pair("heightLastStakeAttempt", (mapBlockIndex.count(lastHash) > 0 ?
mapBlockIndex.at(lastHash)->nHeight : -1)) );
obj.push_back(Pair("timeLastStakeAttempt", pwalletMain->pStakerStatus->GetLastTime()));
std::vector<COutput> vCoins;
pwalletMain->StakeableCoins(&vCoins);
obj.push_back(Pair("stakeablecoins", (int)vCoins.size()));
obj.push_back(Pair("stakingbalance", ValueFromAmount(pwalletMain->GetStakingBalance(fColdStaking))));
obj.push_back(Pair("stakesplitthreshold", ValueFromAmount(pwalletMain->nStakeSplitThreshold)));
CStakerStatus* ss = pwalletMain->pStakerStatus;
if (ss) {
obj.push_back(Pair("lastattempt_age", (int)(GetTime() - ss->GetLastTime())));
obj.push_back(Pair("lastattempt_depth", (chainActive.Height() - ss->GetLastHeight())));
obj.push_back(Pair("lastattempt_hash", ss->GetLastHash().GetHex()));
obj.push_back(Pair("lastattempt_coins", ss->GetLastCoins()));
obj.push_back(Pair("lastattempt_tries", ss->GetLastTries()));
}
return obj;
}

Expand Down
4 changes: 3 additions & 1 deletion src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2549,6 +2549,7 @@ bool CWallet::CreateCoinStake(

// update staker status (hash)
pStakerStatus->SetLastTip(pindexPrev);
pStakerStatus->SetLastCoins(listInputs.size());

// Kernel Search
CAmount nCredit;
Expand All @@ -2573,8 +2574,9 @@ bool CWallet::CreateCoinStake(
nAttempts++;
fKernelFound = Stake(pindexPrev, stakeInput.get(), nBits, nTxNewTime, hashProofOfStake);

// update staker status (time)
// update staker status (time, attempts)
pStakerStatus->SetLastTime(nTxNewTime);
pStakerStatus->SetLastTries(nAttempts);

if (!fKernelFound) continue;

Expand Down
44 changes: 30 additions & 14 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ enum ZerocoinSpendStatus {
ZPIV_INVALID_WITNESS = 12, // Spend coin transaction did not verify
ZPIV_BAD_SERIALIZATION = 13, // Transaction verification failed
ZPIV_SPENT_USED_ZPIV = 14, // Coin has already been spend
ZPIV_TX_TOO_LARGE = 15, // The transaction is larger than the max tx size
ZPIV_TX_TOO_LARGE = 15, // The transaction is larger than the max tx size
ZPIV_SPEND_V1_SEC_LEVEL // Spend is V1 and security level is not set to 100
};

Expand Down Expand Up @@ -177,26 +177,42 @@ class CKeyPool
}
};

/** Record info about last kernel stake operation (time and chainTip)**/
class CStakerStatus {
/** Record info about last stake attempt:
* - tipBlock index of the block on top of which last stake attempt was made
* - nTime time slot of last attempt
* - nTries number of UTXOs hashed during last attempt
* - nCoins number of stakeable utxos during last attempt
**/
class CStakerStatus
{
private:
const CBlockIndex* tipLastStakeAttempt = nullptr;
int64_t timeLastStakeAttempt;
const CBlockIndex* tipBlock{nullptr};
int64_t nTime{0};
int nTries{0};
int nCoins{0};

public:
const CBlockIndex* GetLastTip() const { return tipLastStakeAttempt; }
uint256 GetLastHash() const
{
return (tipLastStakeAttempt == nullptr ? UINT256_ZERO : tipLastStakeAttempt->GetBlockHash());
}
int64_t GetLastTime() const { return timeLastStakeAttempt; }
void SetLastTip(const CBlockIndex* lastTip) { tipLastStakeAttempt = lastTip; }
void SetLastTime(const uint64_t lastTime) { timeLastStakeAttempt = lastTime; }
// Get
const CBlockIndex* GetLastTip() const { return tipBlock; }
uint256 GetLastHash() const { return (GetLastTip() == nullptr ? UINT256_ZERO : GetLastTip()->GetBlockHash()); }
int GetLastHeight() const { return (GetLastTip() == nullptr ? 0 : GetLastTip()->nHeight); }
int GetLastCoins() const { return nCoins; }
int GetLastTries() const { return nTries; }
int64_t GetLastTime() const { return nTime; }
// Set
void SetLastCoins(const int coins) { nCoins = coins; }
void SetLastTries(const int tries) { nTries = tries; }
void SetLastTip(const CBlockIndex* lastTip) { tipBlock = lastTip; }
void SetLastTime(const uint64_t lastTime) { nTime = lastTime; }
void SetNull()
{
SetLastCoins(0);
SetLastTries(0);
SetLastTip(nullptr);
SetLastTime(0);
}
bool IsActive() { return (timeLastStakeAttempt + 30) >= GetTime(); }
// Check whether staking status is active (last attempt earlier than 30 seconds ago)
bool IsActive() const { return (nTime + 30) >= GetTime(); }
};

/**
Expand Down
8 changes: 4 additions & 4 deletions test/functional/mining_pos_coldStaking.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def run_test(self):
assert (self.nodes[1].lockunspent(False, [{"txid": x['txid'], "vout": x['vout']}]))
# check that it cannot stake
sleep(1)
assert_equal(self.nodes[1].getstakingstatus()["stakeablecoins"], False)
assert_equal(self.nodes[1].getstakingstatus()["stakeablecoins"], 0)

# 3) nodes[0] generates a owner address
# nodes[1] generates a cold-staking address.
Expand Down Expand Up @@ -202,7 +202,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"], False)
assert_equal(self.nodes[1].getstakingstatus()["stakeablecoins"], 0)
self.log.info("Nice. Cold staker was NOT able to create the block yet.")

self.log.info("Whitelisting the owner...")
Expand All @@ -226,7 +226,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"], True)
assert_equal(self.nodes[1].getstakingstatus()["stakeablecoins"], 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 @@ -357,7 +357,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"], False)
assert_equal(self.nodes[1].getstakingstatus()["stakeablecoins"], 0)
self.log.info("Cigar. Cold staker was NOT able to create any more blocks.")

# 15) check balances when mature.
Expand Down
5 changes: 3 additions & 2 deletions test/functional/test_framework/test_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,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"]
assert ss["stakeablecoins"] > 0
assert ss["stakingbalance"] > 0.0
if btime is not None:
next_btime = btime + 60
fStaked = False
Expand All @@ -1024,7 +1025,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"]):
if not (ss["walletunlocked"] and ss["stakeablecoins"] > 0 and ss["stakingbalance"] > 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