Proof-of-stake related code refactoring and cleanup
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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<CBlockTemplate> 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<CBlockTemplate> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
17
src/pow.cpp
17
src/pow.cpp
@@ -12,7 +12,7 @@
|
||||
#include "util.h"
|
||||
#include <stdio.h>
|
||||
|
||||
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;
|
||||
|
||||
@@ -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&);
|
||||
|
||||
@@ -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<CBlockTemplate> 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<CBlockTemplate> 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)
|
||||
|
||||
@@ -607,8 +607,8 @@ void CWallet::AvailableCoinsForStaking(std::vector<COutput>& 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<COutput>& vCoins) const
|
||||
}
|
||||
}
|
||||
|
||||
bool CWallet::HaveAvailableCoinsForStaking() const
|
||||
{
|
||||
vector<COutput> vCoins;
|
||||
AvailableCoinsForStaking(vCoins);
|
||||
return vCoins.size() > 0;
|
||||
}
|
||||
|
||||
// Select some coins without random shuffle or best subset approximation
|
||||
bool CWallet::SelectCoinsForStaking(CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const
|
||||
{
|
||||
|
||||
@@ -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<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const;
|
||||
void AvailableCoinsForStaking(std::vector<COutput>& vCoins) const;
|
||||
bool HaveAvailableCoinsForStaking() const;
|
||||
uint64_t GetStakeWeight() const;
|
||||
|
||||
/* Returns the wallets help message */
|
||||
|
||||
Reference in New Issue
Block a user