X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Fminer.cpp;h=aae9589b92937585b8d001786a2fec434f909e3a;hp=4f0130a7cc08305e2c4d800625234593d858caf8;hb=a0bfbd64a8dc93eb87a452843f76dbb9dec9f30b;hpb=126e51d5d96f8bc2c900df18af5827c279967dcc diff --git a/src/miner.cpp b/src/miner.cpp index 4f0130a..aae9589 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -7,6 +7,7 @@ #include "txdb.h" #include "miner.h" #include "kernel.h" +#include "kernel_worker.h" using namespace std; @@ -17,6 +18,7 @@ using namespace std; int64_t nReserveBalance = 0; static unsigned int nMaxStakeSearchInterval = 60; +uint64_t nStakeInputsMapSize = 0; int static FormatHashBlocks(void* pbuffer, unsigned int len) { @@ -68,14 +70,6 @@ public: ptx = ptxIn; dPriority = dFeePerKb = 0; } - - void print() const - { - printf("COrphan(hash=%s, dPriority=%.1f, dFeePerKb=%.1f)\n", - ptx->GetHash().ToString().substr(0,10).c_str(), dPriority, dFeePerKb); - BOOST_FOREACH(uint256 hash, setDependsOn) - printf(" setDependsOn %s\n", hash.ToString().substr(0,10).c_str()); - } }; @@ -145,18 +139,18 @@ CBlock* CreateNewBlock(CWallet* pwallet, CTransaction *txCoinStake) } // Largest block you're willing to create: - unsigned int nBlockMaxSize = GetArg("-blockmaxsize", MAX_BLOCK_SIZE_GEN/2); + unsigned int nBlockMaxSize = GetArgUInt("-blockmaxsize", MAX_BLOCK_SIZE_GEN/2); // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: - nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); + nBlockMaxSize = std::max(1000u, std::min(MAX_BLOCK_SIZE-1000u, nBlockMaxSize)); // How much of the block should be dedicated to high-priority transactions, // included regardless of the fees they pay - unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", 27000); + unsigned int nBlockPrioritySize = GetArgUInt("-blockprioritysize", 27000); nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); // Minimum block size you want to create; block will be filled with free transactions // until there are no more or the block reaches this size: - unsigned int nBlockMinSize = GetArg("-blockminsize", 0); + unsigned int nBlockMinSize = GetArgUInt("-blockminsize", 0); nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); // Fee-per-kilobyte amount considered the same as "free" @@ -288,9 +282,6 @@ CBlock* CreateNewBlock(CWallet* pwallet, CTransaction *txCoinStake) if (tx.nTime > GetAdjustedTime() || (fProofOfStake && tx.nTime > txCoinStake->nTime)) continue; - // Simplify transaction fee - allow free = false - int64_t nMinFee = tx.GetMinFee(nBlockSize, true, GMF_BLOCK, nTxSize); - // Skip free transactions if we're past the minimum block size: if (fSortedByFee && (dFeePerKb < nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; @@ -313,10 +304,13 @@ CBlock* CreateNewBlock(CWallet* pwallet, CTransaction *txCoinStake) if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs, fInvalid)) continue; + // Transaction fee int64_t nTxFees = tx.GetValueIn(mapInputs)-tx.GetValueOut(); + int64_t nMinFee = tx.GetMinFee(nBlockSize, true, GMF_BLOCK, nTxSize); if (nTxFees < nMinFee) continue; + // Sigops accumulation nTxSigOps += tx.GetP2SHSigOpCount(mapInputs); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; @@ -529,10 +523,10 @@ bool CheckStake(CBlock* pblock, CWallet& wallet) } // Precalculated SHA256 contexts and metadata -// (txid, vout.n) => (SHA256_CTX, (tx.nTime, nAmount)) -typedef std::map, std::pair > > MidstateMap; +// (txid, vout.n) => (kernel, (tx.nTime, nAmount)) +typedef std::map, std::pair, std::pair > > MidstateMap; -// Fill the inputs map with precalculated states and metadata +// Fill the inputs map with precalculated contexts and metadata bool FillMap(CWallet *pwallet, uint32_t nUpperTime, MidstateMap &inputsMap) { // Choose coins to use @@ -588,20 +582,24 @@ bool FillMap(CWallet *pwallet, uint32_t nUpperTime, MidstateMap &inputsMap) if (nStakeMinAge + block.nTime > nTime - nMaxStakeSearchInterval) continue; + // Get stake modifier uint64_t nStakeModifier = 0; if (!GetKernelStakeModifier(block.GetHash(), nStakeModifier)) continue; - SHA256_CTX ctx; - // Calculate midstate using (modifier, block time, tx offset, tx time, output number) - GetKernelMidstate(nStakeModifier, block.nTime, txindex.pos.nTxPos - txindex.pos.nBlockPos, pcoin->first->nTime, pcoin->second, ctx); + // Build static part of kernel + CDataStream ssKernel(SER_GETHASH, 0); + ssKernel << nStakeModifier; + ssKernel << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << pcoin->first->nTime << pcoin->second; - // (txid, vout.n) => (SHA256_CTX, (tx.nTime, nAmount)) - inputsMap[key] = make_pair(ctx, make_pair(pcoin->first->nTime, pcoin->first->vout[pcoin->second].nValue)); + // (txid, vout.n) => (kernel, (tx.nTime, nAmount)) + inputsMap[key] = make_pair(std::vector(ssKernel.begin(), ssKernel.end()), make_pair(pcoin->first->nTime, pcoin->first->vout[pcoin->second].nValue)); } + nStakeInputsMapSize = inputsMap.size(); + if (fDebug) - printf("Stake miner: %" PRIszu " precalculated contexts created\n", inputsMap.size()); + printf("FillMap() : Map of %" PRIu64 " precalculated contexts has been created by stake miner\n", nStakeInputsMapSize); } return true; @@ -621,13 +619,13 @@ bool ScanMap(const MidstateMap &inputsMap, uint32_t nBits, MidstateMap::key_type interval.first = nSearchTime; interval.second = nSearchTime - min(nSearchTime-nLastCoinStakeSearchTime, nMaxStakeSearchInterval); - // (txid, nout) => (SHA256_CTX, (tx.nTime, nAmount)) + // (txid, nout) => (kernel, (tx.nTime, nAmount)) for(MidstateMap::const_iterator input = inputsMap.begin(); input != inputsMap.end(); input++) { - SHA256_CTX ctx = input->second.first; + unsigned char *kernel = (unsigned char *) &input->second.first[0]; // scan(State, Bits, Time, Amount, ...) - if (ScanMidstateBackward(ctx, nBits, input->second.second.first, input->second.second.second, interval, solution)) + if (ScanKernelBackward(kernel, nBits, input->second.second.first, input->second.second.second, interval, solution)) { // Solution found LuckyInput = input->first; // (txid, nout) @@ -646,12 +644,14 @@ bool ScanMap(const MidstateMap &inputsMap, uint32_t nBits, MidstateMap::key_type return false; } -void StakeMiner(CWallet *pwallet) +// Stake miner thread +void ThreadStakeMiner(void* parg) { SetThreadPriority(THREAD_PRIORITY_LOWEST); // Make this thread recognisable as the mining thread RenameThread("novacoin-miner"); + CWallet* pwallet = (CWallet*)parg; MidstateMap inputsMap; if (!FillMap(pwallet, GetAdjustedTime(), inputsMap)) @@ -662,107 +662,128 @@ void StakeMiner(CWallet *pwallet) CBlockIndex* pindexPrev = pindexBest; uint32_t nBits = GetNextTargetRequired(pindexPrev, true); - while (true) + printf("ThreadStakeMinter started\n"); + + try { - if (fShutdown) - return; + vnThreadsRunning[THREAD_MINTER]++; - while (pwallet->IsLocked()) - { - Sleep(1000); - if (fShutdown) - return; - } + MidstateMap::key_type LuckyInput; + std::pair solution; - while (vNodes.empty() || IsInitialBlockDownload()) + // Main miner loop + do { - fTrySync = true; - - Sleep(1000); if (fShutdown) - return; - } + goto _endloop; - if (fTrySync) - { - fTrySync = false; - if (vNodes.size() < 3 || nBestHeight < GetNumBlocksOfPeers()) + while (pwallet->IsLocked()) { Sleep(1000); - continue; + if (fShutdown) + goto _endloop; // Don't be afraid to use a goto if that's the best option. } - } - - MidstateMap::key_type LuckyInput; - std::pair solution; - - if (ScanMap(inputsMap, nBits, LuckyInput, solution)) - { - SetThreadPriority(THREAD_PRIORITY_NORMAL); - // Remove lucky input from the map - inputsMap.erase(inputsMap.find(LuckyInput)); + while (vNodes.empty() || IsInitialBlockDownload()) + { + fTrySync = true; - CKey key; - CTransaction txCoinStake; + Sleep(1000); + if (fShutdown) + goto _endloop; + } - // Create new coinstake transaction - if (!pwallet->CreateCoinStake(LuckyInput.first, LuckyInput.second, solution.second, pindexPrev->nBits, txCoinStake, key)) + if (fTrySync) { - string strMessage = _("Warning: Unable to create coinstake transaction, see debug.log for the details. Mining thread has been stopped."); - strMiscWarning = strMessage; - printf("*** %s\n", strMessage.c_str()); - - return; + // Don't try mine blocks unless we're at the top of chain and have at least three p2p connections. + fTrySync = false; + if (vNodes.size() < 3 || nBestHeight < GetNumBlocksOfPeers()) + { + Sleep(1000); + continue; + } } - // Now we have new coinstake, it's time to create the block ... - CBlock* pblock; - pblock = CreateNewBlock(pwallet, &txCoinStake); - if (!pblock) + if (ScanMap(inputsMap, nBits, LuckyInput, solution)) { - string strMessage = _("Warning: Unable to allocate memory for the new block object. Mining thread has been stopped."); - strMiscWarning = strMessage; - printf("*** %s\n", strMessage.c_str()); + SetThreadPriority(THREAD_PRIORITY_NORMAL); - return; - } + // Remove lucky input from the map + inputsMap.erase(inputsMap.find(LuckyInput)); - unsigned int nExtraNonce = 0; - IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + CKey key; + CTransaction txCoinStake; - // ... and sign it - if (!key.Sign(pblock->GetHash(), pblock->vchBlockSig)) - { - string strMessage = _("Warning: Proof-of-Stake miner is unable to sign the block (locked wallet?). Mining thread has been stopped."); - strMiscWarning = strMessage; - printf("*** %s\n", strMessage.c_str()); + // Create new coinstake transaction + if (!pwallet->CreateCoinStake(LuckyInput.first, LuckyInput.second, solution.second, nBits, txCoinStake, key)) + { + string strMessage = _("Warning: Unable to create coinstake transaction, see debug.log for the details. Mining thread has been stopped."); + strMiscWarning = strMessage; + printf("*** %s\n", strMessage.c_str()); - return; - } + break; + } - CheckStake(pblock, *pwallet); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - Sleep(500); - } + // Now we have new coinstake, it's time to create the block ... + CBlock* pblock; + pblock = CreateNewBlock(pwallet, &txCoinStake); + if (!pblock) + { + string strMessage = _("Warning: Unable to allocate memory for the new block object. Mining thread has been stopped."); + strMiscWarning = strMessage; + printf("*** %s\n", strMessage.c_str()); - if (pindexPrev != pindexBest) - { - // The best block has been changed, we need to refill the map - if (FillMap(pwallet, GetAdjustedTime(), inputsMap)) - { - pindexPrev = pindexBest; - nBits = GetNextTargetRequired(pindexPrev, true); + break; + } + + unsigned int nExtraNonce = 0; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + // ... and sign it + if (!key.Sign(pblock->GetHash(), pblock->vchBlockSig)) + { + string strMessage = _("Warning: Proof-of-Stake miner is unable to sign the block (locked wallet?). Mining thread has been stopped."); + strMiscWarning = strMessage; + printf("*** %s\n", strMessage.c_str()); + + break; + } + + CheckStake(pblock, *pwallet); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + Sleep(500); } - else + + if (pindexPrev != pindexBest) { - // Clear existent data if FillMap failed - inputsMap.clear(); + // The best block has been changed, we need to refill the map + if (FillMap(pwallet, GetAdjustedTime(), inputsMap)) + { + pindexPrev = pindexBest; + nBits = GetNextTargetRequired(pindexPrev, true); + } + else + { + // Clear existent data if FillMap failed + inputsMap.clear(); + } } - } - Sleep(500); + Sleep(500); - continue; + _endloop: + (void)0; // do nothing + } + while(!fShutdown); + + vnThreadsRunning[THREAD_MINTER]--; + } + catch (std::exception& e) { + vnThreadsRunning[THREAD_MINTER]--; + PrintException(&e, "ThreadStakeMinter()"); + } catch (...) { + vnThreadsRunning[THREAD_MINTER]--; + PrintException(NULL, "ThreadStakeMinter()"); } + printf("ThreadStakeMinter exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINTER]); }