return true;
}
+bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64& nStakeModifier)
+{
+ int nStakeModifierHeight;
+ int64 nStakeModifierTime;
+
+ return GetKernelStakeModifier(hashBlockFrom, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, false);
+}
+
+
// ppcoin kernel protocol
// coinstake must meet hash target according to the protocol:
// kernel (input 0) must meet the formula
return true;
}
+// Scan given coins set for kernel solution
+bool ScanForStakeKernelHash(MetaMap &mapMeta, KernelSearchSettings &settings, CoinsSet::value_type &kernelcoin, unsigned int &nTimeTx, unsigned int &nBlockTime)
+{
+ uint256 hashProofOfStake = 0;
+
+ // txid => ((txindex, (tx, vout.n)), (block, modifier))
+ for(MetaMap::const_iterator meta_item = mapMeta.begin(); meta_item != mapMeta.end(); meta_item++)
+ {
+ if (!fCoinsDataActual)
+ break;
+
+ CTxIndex txindex = (*meta_item).second.first.first;
+ CBlock block = (*meta_item).second.second.first;
+ uint64 nStakeModifier = (*meta_item).second.second.second;
+
+ // Get coin
+ CoinsSet::value_type pcoin = meta_item->second.first.second;
+
+ static int nMaxStakeSearchInterval = 60;
+
+ // only count coins meeting min age requirement
+ if (nStakeMinAge + block.nTime > settings.nTime - nMaxStakeSearchInterval)
+ continue;
+
+ // Transaction offset inside block
+ unsigned int nTxOffset = txindex.pos.nTxPos - txindex.pos.nBlockPos;
+
+ // Current timestamp scanning interval
+ unsigned int nCurrentSearchInterval = min((int64)settings.nSearchInterval, (int64)nMaxStakeSearchInterval);
+
+ nBlockTime = block.nTime;
+ CBigNum bnTargetPerCoinDay;
+ bnTargetPerCoinDay.SetCompact(settings.nBits);
+ int64 nValueIn = pcoin.first->vout[pcoin.second].nValue;
+
+ // Search backward in time from the given timestamp
+ // Search nSearchInterval seconds back up to nMaxStakeSearchInterval
+ // Stopping search in case of shutting down or cache invalidation
+ for (unsigned int n=0; n<nCurrentSearchInterval && fCoinsDataActual && !fShutdown; n++)
+ {
+ nTimeTx = settings.nTime - n;
+ CBigNum bnCoinDayWeight = CBigNum(nValueIn) * GetWeight((int64)pcoin.first->nTime, (int64)nTimeTx) / COIN / (24 * 60 * 60);
+ CBigNum bnTargetProofOfStake = bnCoinDayWeight * bnTargetPerCoinDay;
+
+ // Build kernel
+ CDataStream ss(SER_GETHASH, 0);
+ ss << nStakeModifier;
+ ss << nBlockTime << nTxOffset << pcoin.first->nTime << pcoin.second << nTimeTx;
+
+ // Calculate kernel hash
+ hashProofOfStake = Hash(ss.begin(), ss.end());
+
+ if (bnTargetProofOfStake >= CBigNum(hashProofOfStake))
+ {
+ if (fDebug)
+ printf("nStakeModifier=0x%016"PRI64x", nBlockTime=%u nTxOffset=%u nTxPrevTime=%u nVout=%u nTimeTx=%u hashProofOfStake=%s Success=true\n",
+ nStakeModifier, nBlockTime, nTxOffset, pcoin.first->nTime, pcoin.second, nTimeTx, hashProofOfStake.GetHex().c_str());
+
+ kernelcoin = pcoin;
+ return true;
+ }
+
+ if (fDebug)
+ printf("nStakeModifier=0x%016"PRI64x", nBlockTime=%u nTxOffset=%u nTxPrevTime=%u nTxNumber=%u nTimeTx=%u hashProofOfStake=%s Success=false\n",
+ nStakeModifier, nBlockTime, nTxOffset, pcoin.first->nTime, pcoin.second, nTimeTx, hashProofOfStake.GetHex().c_str());
+ }
+ }
+
+ return false;
+}
+
// Check kernel hash target and coinstake signature
bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake, uint256& targetProofOfStake)
{
if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex))
return tx.DoS(1, error("CheckProofOfStake() : INFO: read txPrev failed")); // previous transaction not in main chain, may occur during initial download
+#ifndef USE_LEVELDB
+ txdb.Close();
+#endif
+
// Verify signature
- if (!VerifySignature(txPrev, tx, 0, true, 0))
+ if (!VerifySignature(txPrev, tx, 0, MANDATORY_SCRIPT_VERIFY_FLAGS, 0))
return tx.DoS(100, error("CheckProofOfStake() : VerifySignature failed on coinstake %s", tx.GetHash().ToString().c_str()));
// Read block header