// quantities so as to generate blocks faster, degrading the system back into
// a proof-of-work situation.
//
-bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, uint256& targetProofOfStake, bool& fFatal, bool fPrintProofOfStake)
+bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, uint256& targetProofOfStake, bool& fFatal, bool fMiner, bool fPrintProofOfStake)
{
if (nTimeTx < txPrev.nTime) // Transaction timestamp violation
{
if (CBigNum(hashProofOfStake) > bnCoinDayWeight * bnTargetPerCoinDay)
{
fFatal = true;
- return error("CheckStakeKernelHash() : proof-of-stake for block %s not meeting target", hashBlockFrom.ToString().c_str());
+ return !fMiner? error("CheckStakeKernelHash() : proof-of-stake not meeting target") : false;
}
if (fDebug && !fPrintProofOfStake)
}
// Check kernel hash target and coinstake signature
-bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake, uint256& targetProofOfStake, bool& fFatal)
+bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake, uint256& targetProofOfStake, bool& fFatal, bool fMiner)
{
if (!tx.IsCoinStake())
{
CCoins coins;
CCoinsViewCache &view = *pcoinsTip;
- if (!view.GetCoins(txin.prevout.hash, coins))
+ if (!view.GetCoinsReadOnly(txin.prevout.hash, coins))
return fDebug? error("CheckProofOfStake() : INFO: read coins for txPrev failed") : false; // previous transaction not in main chain, may occur during initial download
CBlockIndex* pindex = FindBlockByHeight(coins.nHeight);
return error("CheckProofOfStake() : VerifySignature failed on coinstake %s", tx.GetHash().ToString().c_str());
}
- if (!CheckStakeKernelHash(nBits, block, nTxPos, txPrev, txin.prevout, tx.nTime, hashProofOfStake, targetProofOfStake, fFatal, fDebug))
+ if (!CheckStakeKernelHash(nBits, block, nTxPos, txPrev, txin.prevout, tx.nTime, hashProofOfStake, targetProofOfStake, fFatal, fMiner, fDebug))
{
if (fFatal)
return false;
// Check whether stake kernel meets hash target
// Sets hashProofOfStake and targetProofOfStake on success return
-bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, uint256& targetProofOfStake, bool& fFatal, bool fPrintProofOfStake=false);
+bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, uint256& targetProofOfStake, bool& fFatal, bool fMiner=false, bool fPrintProofOfStake=false);
// Check kernel hash target and coinstake signature
// Sets hashProofOfStake and targetProofOfStake on success return
-bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake, uint256& targetProofOfStake, bool& fFatal);
+bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake, uint256& targetProofOfStake, bool& fFatal, bool fMiner=false);
// Check whether the coinstake timestamp meets protocol
bool CheckCoinStakeTimestamp(int64 nTimeBlock, int64 nTimeTx);
return false;
}
+// Select coins from read-only cache or database
+bool CCoinsViewCache::GetCoinsReadOnly(uint256 txid, CCoins &coins) {
+ if (cacheCoins.count(txid)) {
+ coins = cacheCoins[txid]; // get from cache
+ return true;
+ }
+ if (cacheCoinsReadOnly.count(txid)) {
+ coins = cacheCoinsReadOnly[txid]; // get from read-only cache
+ return true;
+ }
+ if (base->GetCoins(txid, coins)) {
+ cacheCoinsReadOnly[txid] = coins; // save to read-only cache
+ return true;
+ }
+ return false;
+}
+
bool CCoinsViewCache::SetCoins(uint256 txid, const CCoins &coins) {
cacheCoins[txid] = coins;
return true;
}
bool CCoinsViewCache::Flush() {
+ cacheCoinsReadOnly.clear(); // purge read-only cache
+
bool fOk = base->BatchWrite(cacheCoins, pindexTip);
if (fOk)
cacheCoins.clear();
protected:
CBlockIndex *pindexTip;
std::map<uint256,CCoins> cacheCoins;
+ std::map<uint256,CCoins> cacheCoinsReadOnly;
public:
CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false);
bool GetCoins(uint256 txid, CCoins &coins);
+ bool GetCoinsReadOnly(uint256 txid, CCoins &coins);
bool SetCoins(uint256 txid, const CCoins &coins);
bool HaveCoins(uint256 txid);
CBlockIndex *GetBestBlock();
return error("CheckStake() : %s is not a proof-of-stake block", hashBlock.GetHex().c_str());
// verify hash target and signature of coinstake tx
- if (!CheckProofOfStake(pblock->vtx[1], pblock->nBits, proofHash, hashTarget, fFatal))
+ if (!CheckProofOfStake(pblock->vtx[1], pblock->nBits, proofHash, hashTarget, fFatal, true))
return error("CheckStake() : proof-of-stake checking failed");
//// debug print
result.push_back(Pair("tx", txinfo));
- if ( block.IsProofOfStake() || (!fTestNet && block.GetBlockTime() < ENTROPY_SWITCH_TIME) )
- result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end())));
+ if ( block.IsProofOfStake() )
+ {
+ CKey key;
+ block.GetGenerator(key);
+ result.push_back(Pair("generator", HexStr(key.GetPubKey().Raw())));
+ result.push_back(Pair("signature", HexStr(block.vchBlockSig)));
+ }
return result;
}
CCoins coins;
{
LOCK2(cs_main, cs_wallet);
- if (!view.GetCoins(pcoin.first->GetHash(), coins))
+ if (!view.GetCoinsReadOnly(pcoin.first->GetHash(), coins))
continue;
}
CCoins coins;
{
LOCK2(cs_main, cs_wallet);
- if (!view.GetCoins(pcoin.first->GetHash(), coins))
+ if (!view.GetCoinsReadOnly(pcoin.first->GetHash(), coins))
continue;
}
bool fFatal = false;
bool fKernelFound = false;
- for (unsigned int n=0; n<min(nSearchInterval,(int64)nMaxStakeSearchInterval) && !fKernelFound && !fShutdown && pindexPrev == pindexBest && !fFatal; n++)
+ for (unsigned int n=0; n<min(nSearchInterval,(int64)nMaxStakeSearchInterval) && !fKernelFound && !fShutdown && pindexPrev == pindexBest; n++)
{
// Search backward in time from the given txNew timestamp
// Search nSearchInterval seconds back up to nMaxStakeSearchInterval
uint256 hashProofOfStake = 0, targetProofOfStake = 0;
COutPoint prevoutStake = COutPoint(pcoin.first->GetHash(), pcoin.second);
- if (CheckStakeKernelHash(nBits, block, nTxPos, *pcoin.first, prevoutStake, txNew.nTime - n, hashProofOfStake, targetProofOfStake, fFatal))
+ if (CheckStakeKernelHash(nBits, block, nTxPos, *pcoin.first, prevoutStake, txNew.nTime - n, hashProofOfStake, targetProofOfStake, fFatal, true))
{
// Found a kernel
if (fDebug && GetBoolArg("-printcoinstake"))