X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Fkernel.cpp;h=b18ae2b7c180f836f687b46f019c134ba17cd513;hp=7429a38779a09e432ef325653982469f59b55c3e;hb=89d4073d0a6545330af16bb8b2352881b6f55cf5;hpb=6fccda8e55816a81e21f89ae54c92785242ee8f8 diff --git a/src/kernel.cpp b/src/kernel.cpp index 7429a38..b18ae2b 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -1,10 +1,14 @@ // Copyright (c) 2012-2013 The PPCoin developers +// Copyright (c) 2013-2015 The Novacoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include "kernel.h" +#include "kernel_worker.h" #include "txdb.h" extern unsigned int nStakeMaxAge; @@ -32,6 +36,9 @@ static std::map mapStakeModifierCheckpoints = (143990, 0x9c592c78u ) (149000, 0x48f2bdc4u ) (160000, 0x789df0f0u ) + (200000, 0x01ec1503u ) + (221047, 0x0b39ef50u ) + (243100, 0xe928d83au ) ; // Hard checkpoints of stake modifiers to ensure they are deterministic (testNet) @@ -94,18 +101,6 @@ bool IsFixedModifierInterval(unsigned int nTimeBlock) return (nTimeBlock >= (fTestNet? nModifierTestSwitchTime : nModifierSwitchTime)); } -// Get time weight -int64_t GetWeight(int64_t nIntervalBeginning, int64_t nIntervalEnd) -{ - // Kernel hash weight starts from 0 at the 30-day min age - // this change increases active coins participating the hash and helps - // to secure the network when proof-of-stake difficulty is low - // - // Maximum TimeWeight is 90 days. - - return min(nIntervalEnd - nIntervalBeginning - nStakeMinAge, (int64_t)nStakeMaxAge); -} - // Get the last stake modifier and its generation time from a given block static bool GetLastStakeModifier(const CBlockIndex* pindex, uint64_t& nStakeModifier, int64_t& nModifierTime) { @@ -168,13 +163,13 @@ static bool SelectBlockFromCandidates(vector >& vSortedBy if (fSelected && hashSelection < hashBest) { hashBest = hashSelection; - *pindexSelected = (const CBlockIndex*) pindex; + *pindexSelected = pindex; } else if (!fSelected) { fSelected = true; hashBest = hashSelection; - *pindexSelected = (const CBlockIndex*) pindex; + *pindexSelected = pindex; } } if (fDebug && GetBoolArg("-printstakemodifier")) @@ -388,7 +383,7 @@ bool CheckStakeKernelHash(uint32_t nBits, const CBlock& blockFrom, uint32_t nTxP uint256 hashBlockFrom = blockFrom.GetHash(); - CBigNum bnCoinDayWeight = CBigNum(nValueIn) * GetWeight((int64_t)txPrev.nTime, (int64_t)nTimeTx) / COIN / (24 * 60 * 60); + CBigNum bnCoinDayWeight = CBigNum(nValueIn) * GetWeight((int64_t)txPrev.nTime, (int64_t)nTimeTx) / COIN / nOneDay; targetProofOfStake = (bnCoinDayWeight * bnTargetPerCoinDay).getuint256(); // Calculate hash @@ -410,10 +405,10 @@ bool CheckStakeKernelHash(uint32_t nBits, const CBlock& blockFrom, uint32_t nTxP DateTimeStrFormat(nStakeModifierTime).c_str(), mapBlockIndex[hashBlockFrom]->nHeight, DateTimeStrFormat(blockFrom.GetBlockTime()).c_str()); - printf("CheckStakeKernelHash() : check modifier=0x%016" PRIx64 " nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", + printf("CheckStakeKernelHash() : check modifier=0x%016" PRIx64 " nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashTarget=%s hashProof=%s\n", nStakeModifier, nTimeBlockFrom, nTxPrevOffset, txPrev.nTime, prevout.n, nTimeTx, - hashProofOfStake.ToString().c_str()); + targetProofOfStake.ToString().c_str(), hashProofOfStake.ToString().c_str()); } // Now check if proof-of-stake hash meets target protocol @@ -426,147 +421,57 @@ bool CheckStakeKernelHash(uint32_t nBits, const CBlock& blockFrom, uint32_t nTxP DateTimeStrFormat(nStakeModifierTime).c_str(), mapBlockIndex[hashBlockFrom]->nHeight, DateTimeStrFormat(blockFrom.GetBlockTime()).c_str()); - printf("CheckStakeKernelHash() : pass modifier=0x%016" PRIx64 " nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", + printf("CheckStakeKernelHash() : pass modifier=0x%016" PRIx64 " nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashTarget=%s hashProof=%s\n", nStakeModifier, nTimeBlockFrom, nTxPrevOffset, txPrev.nTime, prevout.n, nTimeTx, - hashProofOfStake.ToString().c_str()); + targetProofOfStake.ToString().c_str(), hashProofOfStake.ToString().c_str()); } return true; } -// Scan given coins set for kernel solution -bool ScanForStakeKernelHash(MetaMap &mapMeta, uint32_t nBits, uint32_t nTime, uint32_t nSearchInterval, CoinsSet::value_type &kernelcoin, uint32_t &nTimeTx, uint32_t &nBlockTime, uint64_t &nKernelsTried, uint64_t &nCoinDaysTried) +// Scan given kernel for solution +bool ScanKernelForward(unsigned char *kernel, uint32_t nBits, uint32_t nInputTxTime, int64_t nValueIn, std::pair &SearchInterval, std::vector > &solutions) { - uint256 hashProofOfStake = 0; + // TODO: custom threads amount - // (txid, vout.n) => ((txindex, (tx, vout.n)), (block, modifier)) - for(MetaMap::const_iterator meta_item = mapMeta.begin(); meta_item != mapMeta.end(); meta_item++) + uint32_t nThreads = boost::thread::hardware_concurrency(); + if (nThreads == 0) { - if (!fCoinsDataActual) - break; - - CTxIndex txindex = (*meta_item).second.first.first; - CBlock block = (*meta_item).second.second.first; - uint64_t nStakeModifier = (*meta_item).second.second.second; - - // Get coin - CoinsSet::value_type pcoin = meta_item->second.first.second; - - static unsigned int nMaxStakeSearchInterval = 60; - - // only count coins meeting min age requirement - if (nStakeMinAge + block.nTime > nTime - nMaxStakeSearchInterval) - continue; - - // Transaction offset inside block - uint32_t nTxOffset = txindex.pos.nTxPos - txindex.pos.nBlockPos; - - // Current timestamp scanning interval - unsigned int nCurrentSearchInterval = min(nSearchInterval, nMaxStakeSearchInterval); - - nBlockTime = block.nTime; - CBigNum bnTargetPerCoinDay; - bnTargetPerCoinDay.SetCompact(nBits); - int64_t 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; nnTime, (int64_t)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()); - - // Update statistics - nKernelsTried += 1; - nCoinDaysTried += bnCoinDayWeight.getuint64(); - - if (bnTargetProofOfStake >= CBigNum(hashProofOfStake)) - { - if (fDebug) - printf("nStakeModifier=0x%016" PRIx64 ", 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" PRIx64 ", 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()); - } + nThreads = 1; + printf("Warning: hardware_concurrency() failed in %s:%d\n", __FILE__, __LINE__); } + uint32_t nPart = (SearchInterval.second - SearchInterval.first) / nThreads; - return false; -} - -// Scan given input for kernel solution -bool ScanInputForStakeKernelHash(CTransaction &tx, uint32_t nOut, uint32_t nBits, uint32_t nSearchInterval, std::pair &solution) -{ - CTxDB txdb("r"); - - CBlock block; - CTxIndex txindex; - - // Load transaction index item - if (!txdb.ReadTxIndex(tx.GetHash(), txindex)) - return false; - - // Read block header - if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) - return false; - - uint64_t nStakeModifier = 0; - if (!GetKernelStakeModifier(block.GetHash(), nStakeModifier)) - return false; - - uint32_t nTime = GetTime(); - // Only count coins meeting min age requirement - if (nStakeMinAge + block.nTime > nTime) - nTime += (nStakeMinAge + block.nTime - nTime); + KernelWorker *workers = new KernelWorker[nThreads]; - // Transaction offset inside block - uint32_t nTxOffset = txindex.pos.nTxPos - txindex.pos.nBlockPos; - int64_t nValueIn = tx.vout[nOut].nValue; - - CBigNum bnTargetPerCoinDay; - bnTargetPerCoinDay.SetCompact(nBits); - - // Search forward in time from the given timestamp - // Stopping search in case of shutting down - for (unsigned int n=0; n workerFnc = boost::bind(&KernelWorker::Do, &workers[i]); + group.create_thread(workerFnc); + } - // Build kernel - CDataStream ss(SER_GETHASH, 0); - ss << nStakeModifier; - ss << block.nTime << nTxOffset << tx.nTime << nOut << nTimeTx; + group.join_all(); + solutions.clear(); - // Calculate kernel hash - uint256 hashProofOfStake = Hash(ss.begin(), ss.end()); + for(size_t i = 0; i < nThreads; i++) + { + std::vector > ws = workers[i].GetSolutions(); + solutions.insert(solutions.end(), ws.begin(), ws.end()); + } - if (bnTargetProofOfStake >= CBigNum(hashProofOfStake)) - { - solution.first = hashProofOfStake; - solution.second = nTimeTx; + delete [] workers; - return true; - } + if (solutions.size() == 0) + { + // no solutions + return false; } - return false; + return true; } // Check kernel hash target and coinstake signature @@ -615,7 +520,7 @@ uint32_t GetStakeModifierChecksum(const CBlockIndex* pindex) ss << pindex->nFlags << pindex->hashProofOfStake << pindex->nStakeModifier; uint256 hashChecksum = Hash(ss.begin(), ss.end()); hashChecksum >>= (256 - 32); - return hashChecksum.Get64(); + return static_cast(hashChecksum.Get64()); } // Check stake modifier hard checkpoints