From bc00fcaf030fab695237f5d7c124ffdd1dd14ea1 Mon Sep 17 00:00:00 2001 From: furszy Date: Mon, 11 Jan 2021 16:39:27 -0300 Subject: [PATCH 1/3] Guarding and encapsulating CStakerStatus inside the wallet class. --- src/miner.cpp | 11 ++++---- src/qt/walletmodel.cpp | 2 +- src/rpc/misc.cpp | 2 +- src/wallet/rpcwallet.cpp | 4 +-- src/wallet/wallet.cpp | 54 ++++++++++++++++++++++++++++++++++++++++ src/wallet/wallet.h | 44 +++++++++++++++++--------------- 6 files changed, 88 insertions(+), 29 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 650541bb4fc90..4df074b3f65c8 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -543,13 +543,14 @@ bool fStakeableCoins = false; void CheckForCoins(CWallet* pwallet, std::vector* availableCoins) { - if (!pwallet || !pwallet->pStakerStatus) + if (!pwallet || !pwallet->HasStakingStatus()) return; // control the amount of times the client will check for mintable coins (every block) { WAIT_LOCK(g_best_block_mutex, lock); - if (g_best_block == pwallet->pStakerStatus->GetLastHash()) + Optional opLastHash = pwallet->GetStakingStatusLastHash(); + if (!opLastHash || g_best_block == *opLastHash) return; } fStakeableCoins = pwallet->StakeableCoins(availableCoins); @@ -597,9 +598,9 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake) } //search our map of hashed blocks, see if bestblock has been hashed yet - if (pwallet->pStakerStatus && - pwallet->pStakerStatus->GetLastHash() == pindexPrev->GetBlockHash() && - pwallet->pStakerStatus->GetLastTime() >= GetCurrentTimeSlot()) { + if (pwallet->HasStakingStatus() && + *pwallet->GetStakingStatusLastHash() == pindexPrev->GetBlockHash() && + *pwallet->GetStakingStatusLastTime() >= GetCurrentTimeSlot()) { MilliSleep(2000); continue; } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index d344bb8e4f24b..97a9fdbe59c85 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -84,7 +84,7 @@ bool WalletModel::isSaplingEnforced() const bool WalletModel::isStakingStatusActive() const { - return wallet && wallet->pStakerStatus && wallet->pStakerStatus->IsActive(); + return wallet && wallet->IsStakingActive(); } bool WalletModel::isHDEnabled() const diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index a569e02a27807..42ef7a70441a9 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -119,7 +119,7 @@ UniValue getinfo(const JSONRPCRequest& request) if (pwalletMain) { obj.pushKV("walletversion", pwalletMain->GetVersion()); obj.pushKV("balance", ValueFromAmount(pwalletMain->GetAvailableBalance())); - obj.pushKV("staking status", (pwalletMain->pStakerStatus->IsActive() ? "Staking Active" : "Staking Not Active")); + obj.pushKV("staking status", (pwalletMain->IsStakingActive() ? "Staking Active" : "Staking Not Active")); } #endif obj.pushKV("blocks", (int)chainActive.Height()); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 13de3ce852245..11decbf5f831f 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3683,7 +3683,7 @@ UniValue getstakingstatus(const JSONRPCRequest& request) { LOCK2(cs_main, &pwalletMain->cs_wallet); UniValue obj(UniValue::VOBJ); - obj.pushKV("staking_status", pwalletMain->pStakerStatus->IsActive()); + obj.pushKV("staking_status", pwalletMain->IsStakingActive()); obj.pushKV("staking_enabled", gArgs.GetBoolArg("-staking", DEFAULT_STAKING)); bool fColdStaking = gArgs.GetBoolArg("-coldstaking", true); obj.pushKV("coldstaking_enabled", fColdStaking); @@ -3695,7 +3695,7 @@ UniValue getstakingstatus(const JSONRPCRequest& request) obj.pushKV("stakeablecoins", (int)vCoins.size()); obj.pushKV("stakingbalance", ValueFromAmount(pwalletMain->GetStakingBalance(fColdStaking))); obj.pushKV("stakesplitthreshold", ValueFromAmount(pwalletMain->nStakeSplitThreshold)); - CStakerStatus* ss = pwalletMain->pStakerStatus; + CStakerStatus* ss = pwalletMain->GetStakingStatus(); if (ss) { obj.pushKV("lastattempt_age", (int)(GetTime() - ss->GetLastTime())); obj.pushKV("lastattempt_depth", (chainActive.Height() - ss->GetLastHeight())); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index fc92f199c27c2..18433d1912faa 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4739,3 +4739,57 @@ const CWDestination* CAddressBookIterator::GetDestKey() CStakeableOutput::CStakeableOutput(const CWalletTx* txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, const CBlockIndex*& _pindex) : COutput(txIn, iIn, nDepthIn, fSpendableIn, fSolvableIn), pindex(_pindex) {} + + +//////////////// Staking status getters //////////////// + +bool CWallet::HasStakingStatus() +{ + return pStakerStatus != nullptr; +} + +bool CWallet::IsStakingActive() +{ + return HasStakingStatus() ? pStakerStatus->IsActive() : false; +} + +Optional CWallet::GetStakingStatusLastHash() +{ + return HasStakingStatus() ? Optional(pStakerStatus->GetLastHash()) : nullopt; +} + +Optional CWallet::GetStakingStatusLastTime() +{ + return HasStakingStatus() ? Optional(pStakerStatus->GetLastTime()) : nullopt; +} + +CStakerStatus* CWallet::GetStakingStatus() +{ + return HasStakingStatus() ? pStakerStatus.get() : nullptr; +} + +const CBlockIndex* CStakerStatus::GetLastTip() { LOCK(cs_stakerStatus); return tipBlock; } +uint256 CStakerStatus::GetLastHash() { LOCK(cs_stakerStatus); return (GetLastTip() == nullptr ? UINT256_ZERO : GetLastTip()->GetBlockHash()); } +int CStakerStatus::GetLastHeight() { LOCK(cs_stakerStatus); return (GetLastTip() == nullptr ? 0 : GetLastTip()->nHeight); } +int CStakerStatus::GetLastCoins() { LOCK(cs_stakerStatus); return nCoins; } +int CStakerStatus::GetLastTries() { LOCK(cs_stakerStatus); return nTries; } +int64_t CStakerStatus::GetLastTime() { LOCK(cs_stakerStatus); return nTime; } +// Set +void CStakerStatus::SetLastCoins(const int coins) { LOCK(cs_stakerStatus); nCoins = coins; } +void CStakerStatus::SetLastTries(const int tries) { LOCK(cs_stakerStatus); nTries = tries; } +void CStakerStatus::SetLastTip(const CBlockIndex* lastTip) { LOCK(cs_stakerStatus); tipBlock = lastTip; } +void CStakerStatus::SetLastTime(const uint64_t lastTime) { LOCK(cs_stakerStatus); nTime = lastTime; } +void CStakerStatus::SetNull() +{ + LOCK(cs_stakerStatus); + nCoins = 0; + nTries = 0; + SetLastCoins(0); + SetLastTries(0); + tipBlock = nullptr; + nTime = 0; +} +// Check whether staking status is active (last attempt earlier than 30 seconds ago) +bool CStakerStatus::IsActive() { LOCK(cs_stakerStatus); return (nTime + 30) >= GetTime(); } + +//////////////// End staking status getters //////////////// diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 0cc5ba6a39e23..0734d2ce8d1e3 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -185,29 +185,25 @@ class CStakerStatus int64_t nTime{0}; int nTries{0}; int nCoins{0}; + RecursiveMutex cs_stakerStatus; public: + explicit CStakerStatus() {} // 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; } + const CBlockIndex* GetLastTip(); + uint256 GetLastHash(); + int GetLastHeight(); + int GetLastCoins(); + int GetLastTries(); + int64_t GetLastTime(); // 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); - } + void SetLastCoins(const int coins); + void SetLastTries(const int tries); + void SetLastTip(const CBlockIndex* lastTip); + void SetLastTime(const uint64_t lastTime); + void SetNull(); // Check whether staking status is active (last attempt earlier than 30 seconds ago) - bool IsActive() const { return (nTime + 30) >= GetTime(); } + bool IsActive(); }; struct CRecipient @@ -283,6 +279,9 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface int64_t nNextResend; int64_t nLastResend; + // Staker status (last hashed block and time) + CStakerStatus* pStakerStatus{nullptr}; + /** * Used to keep track of spent outpoints, and * detect and report conflicts (double-spends or @@ -368,8 +367,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount nStakeSplitThreshold; // minimum value allowed for nStakeSplitThreshold (customizable with -minstakesplit flag) static CAmount minStakeSplitThreshold; - // Staker status (last hashed block and time) - CStakerStatus* pStakerStatus = nullptr; // User-defined fee PIV/kb bool fUseCustomFee; @@ -764,6 +761,13 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface /* Wallets parameter interaction */ static bool ParameterInteraction(); + // Staking status getters + bool HasStakingStatus(); + bool IsStakingActive(); + Optional GetStakingStatusLastHash(); + Optional GetStakingStatusLastTime(); + CStakerStatus* GetStakingStatus(); + /** * Wallet post-init setup * Gives the wallet a chance to register repetitive tasks and complete post-init tasks From 6b9088b01441e1096d02de9565aa3eaba90b8dfe Mon Sep 17 00:00:00 2001 From: furszy Date: Mon, 11 Jan 2021 16:48:16 -0300 Subject: [PATCH 2/3] [Wallet] Move CStakerStatus raw pointer to unique_ptr. --- src/wallet/wallet.cpp | 3 +-- src/wallet/wallet.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 18433d1912faa..7e85382f50a10 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4280,7 +4280,6 @@ CWallet::CWallet(std::string strWalletFileIn) CWallet::~CWallet() { delete pwalletdbEncryption; - delete pStakerStatus; } void CWallet::SetNull() @@ -4300,7 +4299,7 @@ void CWallet::SetNull() if (pStakerStatus) { pStakerStatus->SetNull(); } else { - pStakerStatus = new CStakerStatus(); + pStakerStatus = MakeUnique(); } // Stake split threshold nStakeSplitThreshold = DEFAULT_STAKE_SPLIT_THRESHOLD; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 0734d2ce8d1e3..52b790bddc5ae 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -280,7 +280,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface int64_t nLastResend; // Staker status (last hashed block and time) - CStakerStatus* pStakerStatus{nullptr}; + std::unique_ptr pStakerStatus; /** * Used to keep track of spent outpoints, and From f17d80d009b1b95a56c8c4ddd62ec000cd806a06 Mon Sep 17 00:00:00 2001 From: furszy Date: Tue, 12 Jan 2021 10:45:22 -0300 Subject: [PATCH 3/3] [GUI] Topbar: don't try to poll for data if shutdown was requested. --- src/qt/pivx/topbar.cpp | 11 ++++++----- src/qt/walletmodel.cpp | 6 ++++++ src/qt/walletmodel.h | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/qt/pivx/topbar.cpp b/src/qt/pivx/topbar.cpp index 2b9e9f02a8394..52b3d0e346310 100644 --- a/src/qt/pivx/topbar.cpp +++ b/src/qt/pivx/topbar.cpp @@ -443,12 +443,13 @@ void TopBar::setStakingStatusActive(bool fActive) } void TopBar::updateStakingStatus() { - setStakingStatusActive(walletModel && - !walletModel->isWalletLocked() && - walletModel->isStakingStatusActive()); + if (walletModel && !walletModel->isShutdownRequested()) { + setStakingStatusActive(!walletModel->isWalletLocked() && + walletModel->isStakingStatusActive()); - // Taking advantage of this timer to update Tor status if needed. - updateTorIcon(); + // Taking advantage of this timer to update Tor status if needed. + updateTorIcon(); + } } void TopBar::setNumConnections(int count) diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 97a9fdbe59c85..13deb65391991 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -11,6 +11,7 @@ #include "optionsmodel.h" #include "recentrequeststablemodel.h" #include "transactiontablemodel.h" +#include "init.h" // for ShutdownRequested(). Future: move to an interface wrapper #include "base58.h" #include "coincontrol.h" @@ -67,6 +68,11 @@ bool WalletModel::isRegTestNetwork() const return Params().IsRegTestNet(); } +bool WalletModel::isShutdownRequested() +{ + return ShutdownRequested(); +} + bool WalletModel::isColdStakingNetworkelyEnabled() const { return !sporkManager.IsSporkActive(SPORK_19_COLDSTAKING_MAINTENANCE); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 02d3a43cfc146..28c77043ce534 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -152,6 +152,7 @@ class WalletModel : public QObject bool isTestNetwork() const; bool isRegTestNetwork() const; + bool isShutdownRequested(); /** Whether cold staking is enabled or disabled in the network **/ bool isColdStakingNetworkelyEnabled() const; bool isSaplingInMaintenance() const;