diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 0dfa2a0d5..37d5b97c5 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -98,6 +98,7 @@ public: consensus.BIP34Hash = uint256(); consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; + consensus.fPoSNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 consensus.nMinerConfirmationWindow = 2016; // nTargetTimespan / nTargetSpacing consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; @@ -192,6 +193,7 @@ public: consensus.BIP34Hash = uint256(); consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = false; + consensus.fPoSNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; @@ -271,6 +273,7 @@ public: consensus.BIP34Hash = uint256(); consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = true; + consensus.fPoSNoRetargeting = true; consensus.nRuleChangeActivationThreshold = 108;// 75% for regtest consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016) consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; diff --git a/src/consensus/params.h b/src/consensus/params.h index 4921c7a5f..ead06fe38 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -59,6 +59,7 @@ struct Params { bool fPowAllowMinDifficultyBlocks; int64_t nTargetSpacingV1; bool fPowNoRetargeting; + bool fPoSNoRetargeting; int64_t nTargetSpacing; int64_t nTargetTimespan; int64_t DifficultyAdjustmentInterval() const { return nTargetTimespan / nTargetSpacing; } diff --git a/src/main.cpp b/src/main.cpp index 1f323b246..ffe1b86db 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2419,7 +2419,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin REJECT_INVALID, "bad-pow-height"); // Check difficulty - if (block.nBits != GetNextTargetRequired(pindex->pprev, &block, block.IsProofOfStake(), chainparams.GetConsensus())) + if (block.nBits != GetNextTargetRequired(pindex->pprev, &block, chainparams.GetConsensus(), block.IsProofOfStake())) return state.DoS(100, error("ConnectBlock(): incorrect difficulty"), REJECT_INVALID, "bad-diffbits"); @@ -3494,13 +3494,12 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, const { if (block.nVersion < 7 && Params().GetConsensus().IsProtocolV2(block.GetBlockTime())) return state.Invalid(error("%s: rejected nVersion=%d block", __func__, block.nVersion), - REJECT_OBSOLETE, "bad-version"); + REJECT_OBSOLETE, "bad-version"); // Check proof of work matches claimed amount if (fCheckPOW && !CheckProofOfWork(block.GetPoWHash(), block.nBits, consensusParams)) return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), - REJECT_INVALID, "high-hash"); - + REJECT_INVALID, "high-hash"); return true; } @@ -3635,7 +3634,7 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta return state.DoS(1, error("%s: forked chain older than max reorganization depth (height %d)", __func__, nHeight)); // Preliminary check difficulty in pos-only stage - if (chainActive.Height() > consensusParams.nLastPOWBlock && nHeight > consensusParams.nLastPOWBlock && block.nBits != GetNextTargetRequired(pindexPrev, &block, true, consensusParams)) + if (chainActive.Height() > consensusParams.nLastPOWBlock && nHeight > consensusParams.nLastPOWBlock && block.nBits != GetNextTargetRequired(pindexPrev, &block, consensusParams, true)) return state.DoS(100, error("%s: incorrect difficulty", __func__), REJECT_INVALID, "bad-diffbits"); diff --git a/src/miner.cpp b/src/miner.cpp index 82e4e24df..83a43ed61 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -71,7 +71,7 @@ int64_t UpdateTime(CBlock* pblock, const Consensus::Params& consensusParams, con // Updating time can change work required on testnet: if (consensusParams.fPowAllowMinDifficultyBlocks) - pblock->nBits = GetNextTargetRequired(pindexPrev, pblock, pblock->IsProofOfStake(),consensusParams); + pblock->nBits = GetNextTargetRequired(pindexPrev, pblock, consensusParams, pblock->IsProofOfStake()); return nNewTime - nOldTime; @@ -321,7 +321,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s pblock->nTime = max(pindexPrev->GetPastTimeLimit()+1, GetMaxTransactionTime(pblock)); if (!fProofOfStake) UpdateTime(pblock, Params().GetConsensus(), pindexPrev); - pblock->nBits = GetNextTargetRequired(pindexPrev, pblock, fProofOfStake, Params().GetConsensus()); + pblock->nBits = GetNextTargetRequired(pindexPrev, pblock, Params().GetConsensus(), fProofOfStake); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); @@ -578,8 +578,8 @@ bool SignBlock(CBlock& block, CWallet& wallet, int64_t& nFees) { // make sure coinstake would meet timestamp protocol // as it would be the same as the block timestamp - txCoinBase.nTime = block.nTime = txCoinStake.nTime; - block.vtx[0] = txCoinBase; + txCoinBase.nTime = block.nTime = txCoinStake.nTime; + block.vtx[0] = txCoinBase; // we have to make sure that we have no future timestamps in // our transactions set @@ -605,14 +605,19 @@ bool SignBlock(CBlock& block, CWallet& wallet, int64_t& nFees) void ThreadStakeMiner(CWallet *pwallet, const CChainParams& chainparams) { SetThreadPriority(THREAD_PRIORITY_LOWEST); + LogPrintf("Staking started\n"); // Make this thread recognisable as the mining thread - RenameThread("blackcoin-miner"); + RenameThread("BlackcoinMiner"); CReserveKey reservekey(pwallet); bool fTryToSync = true; - + bool regtestMode = Params().GetConsensus().fPoSNoRetargeting; + if (regtestMode) { + nMinerSleep = 30000; //limit regtest to 30s, otherwise it'll create 2 blocks per second + } + while (true) { while (pwallet->IsLocked()) @@ -621,42 +626,46 @@ void ThreadStakeMiner(CWallet *pwallet, const CChainParams& chainparams) MilliSleep(1000); } - while (vNodes.empty() || IsInitialBlockDownload()) - { - nLastCoinStakeSearchInterval = 0; - fTryToSync = true; - MilliSleep(1000); - } - - if (fTryToSync) - { - fTryToSync = false; - if (vNodes.size() < 3 || pindexBestHeader->GetBlockTime() < GetTime() - 10 * 60) + if (!regtestMode) { + while (vNodes.empty() || IsInitialBlockDownload()) { - MilliSleep(60000); - continue; + nLastCoinStakeSearchInterval = 0; + fTryToSync = true; + MilliSleep(1000); + } + if (fTryToSync) + { + fTryToSync = false; + if (vNodes.size() < 3 || pindexBestHeader->GetBlockTime() < GetTime() - 10 * 60) + { + MilliSleep(60000); + continue; + } } } // // Create new block // - int64_t nFees; - std::unique_ptr pblocktemplate(CreateNewBlock(chainparams, reservekey.reserveScript, &nFees, true)); - if (!pblocktemplate.get()) - return; + if (pwallet->HaveAvailableCoinsForStaking()) { + int64_t nFees = 0; + // First just create an empty block. No need to process transactions until we know we can create a block + std::unique_ptr pblocktemplate(CreateNewBlock(chainparams, reservekey.reserveScript, &nFees, true)); + if (!pblocktemplate.get()) + return; - CBlock *pblock = &pblocktemplate->block; - // Trying to sign a block - if (SignBlock(*pblock, *pwallet, nFees)) - { - SetThreadPriority(THREAD_PRIORITY_NORMAL); - CheckStake(pblock, *pwallet, chainparams); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - MilliSleep(500); + CBlock *pblock = &pblocktemplate->block; + // Trying to sign a block + if (SignBlock(*pblock, *pwallet, nFees)) + { + SetThreadPriority(THREAD_PRIORITY_NORMAL); + CheckStake(pblock, *pwallet, chainparams); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + MilliSleep(500); + } + else + MilliSleep(nMinerSleep); } - else - MilliSleep(nMinerSleep); } } diff --git a/src/pos.cpp b/src/pos.cpp index 00c4e8d41..7f8de1d13 100644 --- a/src/pos.cpp +++ b/src/pos.cpp @@ -81,7 +81,7 @@ bool CheckStakeKernelHash(const CBlockIndex* pindexPrev, unsigned int nBits, con // Weighted target int64_t nValueIn = txPrev->vout[prevout.n].nValue; if (nValueIn == 0) - return error("CheckStakeKernelHash() : nValueIn == 0"); + return error("CheckStakeKernelHash() : nValueIn = 0"); arith_uint256 bnWeight = arith_uint256(nValueIn); bnTarget *= bnWeight; @@ -96,7 +96,7 @@ bool CheckStakeKernelHash(const CBlockIndex* pindexPrev, unsigned int nBits, con if (fPrintProofOfStake) { - LogPrintf("CheckStakeKernelHash() : nStakeModifier=%s txPrev.nTime=%u txPrev.vout.hash=%s txPrev.vout.n=%u nTime=%u hashProof=%s\n", + LogPrintf("CheckStakeKernelHash() : nStakeModifier=%s, txPrev.nTime=%u, txPrev.vout.hash=%s, txPrev.vout.n=%u, nTime=%u, hashProof=%s\n", nStakeModifier.GetHex().c_str(), txPrev->nTime, prevout.hash.ToString(), prevout.n, nTimeTx, hashProofOfStake.ToString()); @@ -108,7 +108,7 @@ bool CheckStakeKernelHash(const CBlockIndex* pindexPrev, unsigned int nBits, con if (fDebug && !fPrintProofOfStake) { - LogPrintf("CheckStakeKernelHash() : nStakeModifier=%s txPrev.nTime=%u txPrev.vout.hash=%s txPrev.vout.n=%u nTime=%u hashProof=%s\n", + LogPrintf("CheckStakeKernelHash() : nStakeModifier=%s, txPrev.nTime=%u, txPrev.vout.hash=%s, txPrev.vout.n=%u, nTime=%u, hashProof=%s\n", nStakeModifier.GetHex().c_str(), txPrev->nTime, prevout.hash.ToString(), prevout.n, nTimeTx, hashProofOfStake.ToString()); diff --git a/src/pow.cpp b/src/pow.cpp index aa93f31d8..297352316 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -12,7 +12,7 @@ #include "util.h" #include -static arith_uint256 GetTargetLimit(int64_t nTime, bool fProofOfStake, const Consensus::Params& params) +static arith_uint256 GetTargetLimit(int64_t nTime, const Consensus::Params& params, bool fProofOfStake) { uint256 nLimit; @@ -28,7 +28,7 @@ static arith_uint256 GetTargetLimit(int64_t nTime, bool fProofOfStake, const Con return UintToArith256(nLimit); } -unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, bool fProofOfStake, const Consensus::Params& params) +unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params, bool fProofOfStake) { unsigned int nTargetLimit = UintToArith256(params.powLimit).GetCompact(); @@ -43,13 +43,18 @@ unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, const CBlockHe if (pindexPrevPrev->pprev == NULL) return nTargetLimit; // second block - return CalculateNextTargetRequired(pindexPrev, pindexPrevPrev->GetBlockTime(), params); + return CalculateNextTargetRequired(pindexPrev, pindexPrevPrev->GetBlockTime(), params, fProofOfStake); } -unsigned int CalculateNextTargetRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params) +unsigned int CalculateNextTargetRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params, bool fProofOfStake) { - if (params.fPowNoRetargeting) + if (fProofOfStake) { + if (params.fPoSNoRetargeting) return pindexLast->nBits; + } else { + if (params.fPowNoRetargeting) + return pindexLast->nBits; + } int64_t nActualSpacing = pindexLast->GetBlockTime() - nFirstBlockTime; int64_t nTargetSpacing = params.IsProtocolV2(pindexLast->GetBlockTime()) ? params.nTargetSpacing : params.nTargetSpacingV1; @@ -61,7 +66,7 @@ unsigned int CalculateNextTargetRequired(const CBlockIndex* pindexLast, int64_t nActualSpacing = nTargetSpacing*10; // retarget with exponential moving toward target spacing - const arith_uint256 bnTargetLimit = GetTargetLimit(pindexLast->GetBlockTime(), pindexLast->IsProofOfStake(), params); + const arith_uint256 bnTargetLimit = GetTargetLimit(pindexLast->GetBlockTime(), params, fProofOfStake); arith_uint256 bnNew; bnNew.SetCompact(pindexLast->nBits); int64_t nInterval = params.nTargetTimespan / nTargetSpacing; diff --git a/src/pow.h b/src/pow.h index 2b55be2c5..d13a20cf0 100644 --- a/src/pow.h +++ b/src/pow.h @@ -15,8 +15,8 @@ class CBlockIndex; class uint256; class arith_uint256; -unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, bool fProofOfStake, const Consensus::Params&); -unsigned int CalculateNextTargetRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params&); +unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&, bool fProofOfStake); +unsigned int CalculateNextTargetRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params&, bool fProofOfStake); /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 7516bf7c2..15be9d350 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -759,124 +759,96 @@ UniValue estimatefee(const UniValue& params, bool fHelp) UniValue checkkernel(const UniValue& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "checkkernel [{\"txid\":txid,\"vout\":n},...] [createblocktemplate=false]\n" - "Check if one of given inputs is a kernel input at the moment.\n" - ); - - RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VBOOL)); - - UniValue inputs = params[0].get_array(); - bool fCreateBlockTemplate = params.size() > 1 ? params[1].get_bool() : false; - - if (vNodes.empty()) - throw JSONRPCError(-9, "BlackCoin is not connected!"); - - if (IsInitialBlockDownload()) - throw JSONRPCError(-10, "BlackCoin is downloading blocks..."); - - COutPoint kernel; - CBlockIndex* pindexPrev = chainActive.Tip(); - CBlockHeader blockHeader = pindexPrev->GetBlockHeader(); - unsigned int nBits = GetNextTargetRequired(pindexPrev, &blockHeader, true, Params().GetConsensus()); - int64_t nTime = GetAdjustedTime(); - nTime &= ~Params().GetConsensus().nStakeTimestampMask; - - for (unsigned int idx = 0; idx < inputs.size(); idx++) { - const UniValue& input = inputs[idx]; - const UniValue& o = input.get_obj(); - - const UniValue& txid_v = find_value(o, "txid"); - if (!txid_v.isStr()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key"); - string txid = txid_v.get_str(); - if (!IsHex(txid)) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid"); - - const UniValue& vout_v = find_value(o, "vout"); - if (!vout_v.isNum()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); - int nOutput = vout_v.get_int(); - if (nOutput < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); - - COutPoint cInput(uint256S(txid), nOutput); - if (CheckKernel(pindexPrev, nBits, nTime, cInput)) - { - kernel = cInput; - break; - } - } - - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("found", !kernel.IsNull())); - - if (kernel.IsNull()) - return result; - - UniValue oKernel(UniValue::VOBJ); - oKernel.push_back(Pair("txid", kernel.hash.GetHex())); - oKernel.push_back(Pair("vout", (int64_t)kernel.n)); - oKernel.push_back(Pair("time", nTime)); - result.push_back(Pair("kernel", oKernel)); - - if (!fCreateBlockTemplate) - return result; - - int64_t nFees; - if (!pwalletMain->IsLocked()) - pwalletMain->TopUpKeyPool(); - - CReserveKey pMiningKey(pwalletMain); - std::unique_ptr pblocktemplate(CreateNewBlock(Params(), pMiningKey.reserveScript, &nFees, true)); - if (!pblocktemplate.get()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); - - CBlock *pblock = &pblocktemplate->block; - pblock->nTime = pblock->vtx[0].nTime = nTime; - - CDataStream ss(SER_DISK, PROTOCOL_VERSION); - ss << *pblock; - - result.push_back(Pair("blocktemplate", HexStr(ss.begin(), ss.end()))); - result.push_back(Pair("blocktemplatefees", nFees)); - - CPubKey pubkey; - if (!pMiningKey.GetReservedKey(pubkey)) - throw JSONRPCError(RPC_MISC_ERROR, "GetReservedKey failed"); - - result.push_back(Pair("blocktemplatesignkey", HexStr(pubkey))); - - return result; - if (fHelp || params.size() != 1) - throw runtime_error( - "estimatefee nblocks\n" - "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" - "confirmation within nblocks blocks.\n" - "\nArguments:\n" - "1. nblocks (numeric)\n" - "\nResult:\n" - "n (numeric) estimated fee-per-kilobyte\n" - "\n" - "A negative value is returned if not enough transactions and blocks\n" - "have been observed to make an estimate.\n" - "\nExample:\n" - + HelpExampleCli("estimatefee", "6") + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "checkkernel [{\"txid\":txid,\"vout\":n},...] [createblocktemplate=false]\n" + "Check if one of given inputs is a kernel input at the moment.\n" ); - RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VBOOL)); - int nBlocks = params[0].get_int(); - if (nBlocks < 1) - nBlocks = 1; + UniValue inputs = params[0].get_array(); + bool fCreateBlockTemplate = params.size() > 1 ? params[1].get_bool() : false; - CFeeRate feeRate = mempool.estimateFee(nBlocks); - if (feeRate == CFeeRate(0)) - return -1.0; + if (vNodes.empty()) + throw JSONRPCError(-9, "BlackCoin is not connected!"); - return ValueFromAmount(feeRate.GetFeePerK()); + if (IsInitialBlockDownload()) + throw JSONRPCError(-10, "BlackCoin is downloading blocks..."); + + COutPoint kernel; + CBlockIndex* pindexPrev = chainActive.Tip(); + CBlockHeader blockHeader = pindexPrev->GetBlockHeader(); + unsigned int nBits = GetNextTargetRequired(pindexPrev, &blockHeader, Params().GetConsensus(), true); + int64_t nTime = GetAdjustedTime(); + nTime &= ~Params().GetConsensus().nStakeTimestampMask; + + for (unsigned int idx = 0; idx < inputs.size(); idx++) { + const UniValue& input = inputs[idx]; + const UniValue& o = input.get_obj(); + + const UniValue& txid_v = find_value(o, "txid"); + if (!txid_v.isStr()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key"); + string txid = txid_v.get_str(); + if (!IsHex(txid)) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid"); + + const UniValue& vout_v = find_value(o, "vout"); + if (!vout_v.isNum()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); + int nOutput = vout_v.get_int(); + if (nOutput < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); + + COutPoint cInput(uint256S(txid), nOutput); + if (CheckKernel(pindexPrev, nBits, nTime, cInput)) + { + kernel = cInput; + break; + } + } + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("found", !kernel.IsNull())); + + if (kernel.IsNull()) + return result; + + UniValue oKernel(UniValue::VOBJ); + oKernel.push_back(Pair("txid", kernel.hash.GetHex())); + oKernel.push_back(Pair("vout", (int64_t)kernel.n)); + oKernel.push_back(Pair("time", nTime)); + result.push_back(Pair("kernel", oKernel)); + + if (!fCreateBlockTemplate) + return result; + + int64_t nFees; + if (!pwalletMain->IsLocked()) + pwalletMain->TopUpKeyPool(); + + CReserveKey pMiningKey(pwalletMain); + std::unique_ptr pblocktemplate(CreateNewBlock(Params(), pMiningKey.reserveScript, &nFees, true)); + if (!pblocktemplate.get()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); + + CBlock *pblock = &pblocktemplate->block; + pblock->nTime = pblock->vtx[0].nTime = nTime; + + CDataStream ss(SER_DISK, PROTOCOL_VERSION); + ss << *pblock; + + result.push_back(Pair("blocktemplate", HexStr(ss.begin(), ss.end()))); + result.push_back(Pair("blocktemplatefees", nFees)); + + CPubKey pubkey; + if (!pMiningKey.GetReservedKey(pubkey)) + throw JSONRPCError(RPC_MISC_ERROR, "GetReservedKey failed"); + + result.push_back(Pair("blocktemplatesignkey", HexStr(pubkey))); + + return result; } UniValue estimatepriority(const UniValue& params, bool fHelp) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 1a24a4261..1e266924f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -607,8 +607,8 @@ void CWallet::AvailableCoinsForStaking(std::vector& vCoins) const if (nDepth < 1) continue; - if (nDepth < Params().GetConsensus().nStakeMinConfirmations) - continue; + if (nDepth < Params().GetConsensus().nStakeMinConfirmations) + continue; if (pcoin->GetBlocksToMaturity() > 0) continue; @@ -626,6 +626,13 @@ void CWallet::AvailableCoinsForStaking(std::vector& vCoins) const } } +bool CWallet::HaveAvailableCoinsForStaking() const +{ + vector vCoins; + AvailableCoinsForStaking(vCoins); + return vCoins.size() > 0; +} + // Select some coins without random shuffle or best subset approximation bool CWallet::SelectCoinsForStaking(CAmount& nTargetValue, std::set >& setCoinsRet, CAmount& nValueRet) const { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 743e3c5f7..52809e7d9 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -904,9 +904,12 @@ public: /* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */ bool AbandonTransaction(const uint256& hashTx); + + /* Staking */ bool CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, CAmount& nFees, CMutableTransaction& tx, CKey& key); bool SelectCoinsForStaking(CAmount& nTargetValue, std::set >& setCoinsRet, CAmount& nValueRet) const; void AvailableCoinsForStaking(std::vector& vCoins) const; + bool HaveAvailableCoinsForStaking() const; uint64_t GetStakeWeight() const; /* Returns the wallets help message */