]> Git Repo - VerusCoin.git/blame - src/miner.cpp
Merge pull request #4718
[VerusCoin.git] / src / miner.cpp
CommitLineData
d247a5d1 1// Copyright (c) 2009-2010 Satoshi Nakamoto
57702541 2// Copyright (c) 2009-2014 The Bitcoin developers
d247a5d1
JG
3// Distributed under the MIT/X11 software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
2a72d459
LD
6#include <inttypes.h>
7
d247a5d1 8#include "miner.h"
51ed9ec9
BD
9
10#include "core.h"
85aab2a0 11#include "hash.h"
d247a5d1 12#include "main.h"
51ed9ec9 13#include "net.h"
df852d2b 14#include "pow.h"
df840de5 15#ifdef ENABLE_WALLET
51ed9ec9 16#include "wallet.h"
df840de5 17#endif
09eb201b
WL
18
19using namespace std;
7b4737c8 20
d247a5d1
JG
21//////////////////////////////////////////////////////////////////////////////
22//
23// BitcoinMiner
24//
25
c6cb21d1
GA
26//
27// Unconfirmed transactions in the memory pool often depend on other
28// transactions in the memory pool. When we select transactions from the
29// pool, we select by highest priority or fee rate, so we might consider
30// transactions that depend on transactions that aren't yet in the block.
31// The COrphan class keeps track of these 'temporary orphans' while
32// CreateBlock is figuring out which transactions to include.
33//
d247a5d1
JG
34class COrphan
35{
36public:
4d707d51 37 const CTransaction* ptx;
d247a5d1 38 set<uint256> setDependsOn;
c6cb21d1 39 CFeeRate feeRate;
02bec4b2 40 double dPriority;
d247a5d1 41
c6cb21d1 42 COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0)
d247a5d1 43 {
d247a5d1 44 }
d247a5d1
JG
45};
46
51ed9ec9
BD
47uint64_t nLastBlockTx = 0;
48uint64_t nLastBlockSize = 0;
d247a5d1 49
c6cb21d1
GA
50// We want to sort transactions by priority and fee rate, so:
51typedef boost::tuple<double, CFeeRate, const CTransaction*> TxPriority;
d247a5d1
JG
52class TxPriorityCompare
53{
54 bool byFee;
0655fac0 55
d247a5d1
JG
56public:
57 TxPriorityCompare(bool _byFee) : byFee(_byFee) { }
0655fac0 58
d247a5d1
JG
59 bool operator()(const TxPriority& a, const TxPriority& b)
60 {
61 if (byFee)
62 {
63 if (a.get<1>() == b.get<1>())
64 return a.get<0>() < b.get<0>();
65 return a.get<1>() < b.get<1>();
66 }
67 else
68 {
69 if (a.get<0>() == b.get<0>())
70 return a.get<1>() < b.get<1>();
71 return a.get<0>() < b.get<0>();
72 }
73 }
74};
75
f1dbed92 76CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
d247a5d1
JG
77{
78 // Create new block
79 auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
80 if(!pblocktemplate.get())
81 return NULL;
82 CBlock *pblock = &pblocktemplate->block; // pointer for convenience
83
84 // Create coinbase tx
4949004d 85 CMutableTransaction txNew;
d247a5d1
JG
86 txNew.vin.resize(1);
87 txNew.vin[0].prevout.SetNull();
88 txNew.vout.resize(1);
7e170189 89 txNew.vout[0].scriptPubKey = scriptPubKeyIn;
d247a5d1 90
4949004d
PW
91 // Add dummy coinbase tx as first transaction
92 pblock->vtx.push_back(CTransaction());
d247a5d1
JG
93 pblocktemplate->vTxFees.push_back(-1); // updated at end
94 pblocktemplate->vTxSigOps.push_back(-1); // updated at end
95
96 // Largest block you're willing to create:
ad898b40 97 unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
d247a5d1
JG
98 // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity:
99 nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize));
100
101 // How much of the block should be dedicated to high-priority transactions,
102 // included regardless of the fees they pay
103 unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE);
104 nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize);
105
106 // Minimum block size you want to create; block will be filled with free transactions
107 // until there are no more or the block reaches this size:
037b4f14 108 unsigned int nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE);
d247a5d1
JG
109 nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize);
110
111 // Collect memory pool transactions into the block
51ed9ec9 112 int64_t nFees = 0;
0655fac0 113
d247a5d1
JG
114 {
115 LOCK2(cs_main, mempool.cs);
4c6d41b8 116 CBlockIndex* pindexPrev = chainActive.Tip();
d247a5d1
JG
117 CCoinsViewCache view(*pcoinsTip, true);
118
119 // Priority order to process transactions
120 list<COrphan> vOrphan; // list memory doesn't move
121 map<uint256, vector<COrphan*> > mapDependers;
122 bool fPrintPriority = GetBoolArg("-printpriority", false);
123
124 // This vector will be sorted into a priority queue:
125 vector<TxPriority> vecPriority;
126 vecPriority.reserve(mempool.mapTx.size());
4d707d51
GA
127 for (map<uint256, CTxMemPoolEntry>::iterator mi = mempool.mapTx.begin();
128 mi != mempool.mapTx.end(); ++mi)
d247a5d1 129 {
4d707d51 130 const CTransaction& tx = mi->second.GetTx();
665bdd3b 131 if (tx.IsCoinBase() || !IsFinalTx(tx, pindexPrev->nHeight + 1))
d247a5d1
JG
132 continue;
133
134 COrphan* porphan = NULL;
135 double dPriority = 0;
51ed9ec9 136 int64_t nTotalIn = 0;
d247a5d1
JG
137 bool fMissingInputs = false;
138 BOOST_FOREACH(const CTxIn& txin, tx.vin)
139 {
140 // Read prev transaction
141 if (!view.HaveCoins(txin.prevout.hash))
142 {
143 // This should never happen; all transactions in the memory
144 // pool should connect to either transactions in the chain
145 // or other transactions in the memory pool.
146 if (!mempool.mapTx.count(txin.prevout.hash))
147 {
881a85a2 148 LogPrintf("ERROR: mempool transaction missing input\n");
d247a5d1
JG
149 if (fDebug) assert("mempool transaction missing input" == 0);
150 fMissingInputs = true;
151 if (porphan)
152 vOrphan.pop_back();
153 break;
154 }
155
156 // Has to wait for dependencies
157 if (!porphan)
158 {
159 // Use list for automatic deletion
160 vOrphan.push_back(COrphan(&tx));
161 porphan = &vOrphan.back();
162 }
163 mapDependers[txin.prevout.hash].push_back(porphan);
164 porphan->setDependsOn.insert(txin.prevout.hash);
4d707d51 165 nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue;
d247a5d1
JG
166 continue;
167 }
168 const CCoins &coins = view.GetCoins(txin.prevout.hash);
169
51ed9ec9 170 int64_t nValueIn = coins.vout[txin.prevout.n].nValue;
d247a5d1
JG
171 nTotalIn += nValueIn;
172
173 int nConf = pindexPrev->nHeight - coins.nHeight + 1;
174
175 dPriority += (double)nValueIn * nConf;
176 }
177 if (fMissingInputs) continue;
178
d6eb2599 179 // Priority is sum(valuein * age) / modified_txsize
d247a5d1 180 unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
4d707d51 181 dPriority = tx.ComputePriority(dPriority, nTxSize);
d247a5d1 182
2a72d459
LD
183 uint256 hash = tx.GetHash();
184 mempool.ApplyDeltas(hash, dPriority, nTotalIn);
185
c6cb21d1 186 CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize);
d247a5d1
JG
187
188 if (porphan)
189 {
190 porphan->dPriority = dPriority;
c6cb21d1 191 porphan->feeRate = feeRate;
d247a5d1
JG
192 }
193 else
c6cb21d1 194 vecPriority.push_back(TxPriority(dPriority, feeRate, &mi->second.GetTx()));
d247a5d1
JG
195 }
196
197 // Collect transactions into block
51ed9ec9
BD
198 uint64_t nBlockSize = 1000;
199 uint64_t nBlockTx = 0;
d247a5d1
JG
200 int nBlockSigOps = 100;
201 bool fSortedByFee = (nBlockPrioritySize <= 0);
202
203 TxPriorityCompare comparer(fSortedByFee);
204 std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
205
206 while (!vecPriority.empty())
207 {
208 // Take highest priority transaction off the priority queue:
209 double dPriority = vecPriority.front().get<0>();
c6cb21d1 210 CFeeRate feeRate = vecPriority.front().get<1>();
4d707d51 211 const CTransaction& tx = *(vecPriority.front().get<2>());
d247a5d1
JG
212
213 std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
214 vecPriority.pop_back();
215
216 // Size limits
217 unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
218 if (nBlockSize + nTxSize >= nBlockMaxSize)
219 continue;
220
221 // Legacy limits on sigOps:
222 unsigned int nTxSigOps = GetLegacySigOpCount(tx);
223 if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
224 continue;
225
226 // Skip free transactions if we're past the minimum block size:
2a72d459
LD
227 const uint256& hash = tx.GetHash();
228 double dPriorityDelta = 0;
229 int64_t nFeeDelta = 0;
230 mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
13fc83c7 231 if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
d247a5d1
JG
232 continue;
233
2a72d459 234 // Prioritise by fee once past the priority size or we run out of high-priority
d247a5d1
JG
235 // transactions:
236 if (!fSortedByFee &&
237 ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority)))
238 {
239 fSortedByFee = true;
240 comparer = TxPriorityCompare(fSortedByFee);
241 std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
242 }
243
244 if (!view.HaveInputs(tx))
245 continue;
246
0733c1bd 247 int64_t nTxFees = view.GetValueIn(tx)-tx.GetValueOut();
d247a5d1
JG
248
249 nTxSigOps += GetP2SHSigOpCount(tx, view);
250 if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
251 continue;
252
68f7d1d7
PT
253 // Note that flags: we don't want to set mempool/IsStandard()
254 // policy here, but we still have to ensure that the block we
255 // create only contains transactions that are valid in new blocks.
d247a5d1 256 CValidationState state;
68f7d1d7 257 if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS))
d247a5d1
JG
258 continue;
259
260 CTxUndo txundo;
d38da59b 261 UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1);
d247a5d1
JG
262
263 // Added
264 pblock->vtx.push_back(tx);
265 pblocktemplate->vTxFees.push_back(nTxFees);
266 pblocktemplate->vTxSigOps.push_back(nTxSigOps);
267 nBlockSize += nTxSize;
268 ++nBlockTx;
269 nBlockSigOps += nTxSigOps;
270 nFees += nTxFees;
271
272 if (fPrintPriority)
273 {
c6cb21d1 274 LogPrintf("priority %.1f fee %s txid %s\n",
0655fac0 275 dPriority, feeRate.ToString(), tx.GetHash().ToString());
d247a5d1
JG
276 }
277
278 // Add transactions that depend on this one to the priority queue
279 if (mapDependers.count(hash))
280 {
281 BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
282 {
283 if (!porphan->setDependsOn.empty())
284 {
285 porphan->setDependsOn.erase(hash);
286 if (porphan->setDependsOn.empty())
287 {
c6cb21d1 288 vecPriority.push_back(TxPriority(porphan->dPriority, porphan->feeRate, porphan->ptx));
d247a5d1
JG
289 std::push_heap(vecPriority.begin(), vecPriority.end(), comparer);
290 }
291 }
292 }
293 }
294 }
295
296 nLastBlockTx = nBlockTx;
297 nLastBlockSize = nBlockSize;
f48742c2 298 LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize);
d247a5d1 299
4949004d
PW
300 // Compute final coinbase transaction.
301 txNew.vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
302 txNew.vin[0].scriptSig = CScript() << OP_0 << OP_0;
303 pblock->vtx[0] = txNew;
d247a5d1
JG
304 pblocktemplate->vTxFees[0] = -nFees;
305
306 // Fill in header
307 pblock->hashPrevBlock = pindexPrev->GetBlockHash();
308 UpdateTime(*pblock, pindexPrev);
309 pblock->nBits = GetNextWorkRequired(pindexPrev, pblock);
310 pblock->nNonce = 0;
d247a5d1
JG
311 pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
312
313 CBlockIndex indexDummy(*pblock);
314 indexDummy.pprev = pindexPrev;
315 indexDummy.nHeight = pindexPrev->nHeight + 1;
316 CCoinsViewCache viewNew(*pcoinsTip, true);
317 CValidationState state;
318 if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true))
319 throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
320 }
321
322 return pblocktemplate.release();
323}
324
d247a5d1
JG
325void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
326{
327 // Update nExtraNonce
328 static uint256 hashPrevBlock;
329 if (hashPrevBlock != pblock->hashPrevBlock)
330 {
331 nExtraNonce = 0;
332 hashPrevBlock = pblock->hashPrevBlock;
333 }
334 ++nExtraNonce;
335 unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
4949004d
PW
336 CMutableTransaction txCoinbase(pblock->vtx[0]);
337 txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
338 assert(txCoinbase.vin[0].scriptSig.size() <= 100);
d247a5d1 339
4949004d 340 pblock->vtx[0] = txCoinbase;
d247a5d1
JG
341 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
342}
343
4a85e067 344#ifdef ENABLE_WALLET
acfa0333
WL
345//////////////////////////////////////////////////////////////////////////////
346//
347// Internal miner
348//
349double dHashesPerSec = 0.0;
350int64_t nHPSTimerStart = 0;
351
352//
353// ScanHash scans nonces looking for a hash with at least some zero bits.
85aab2a0
PW
354// The nonce is usually preserved between calls, but periodically or if the
355// nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at
356// zero.
acfa0333 357//
0655fac0
PK
358bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash)
359{
85aab2a0
PW
360 // Write the first 76 bytes of the block header to a double-SHA256 state.
361 CHash256 hasher;
362 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
363 ss << *pblock;
364 assert(ss.size() == 80);
365 hasher.Write((unsigned char*)&ss[0], 76);
366
0655fac0 367 while (true) {
acfa0333 368 nNonce++;
85aab2a0
PW
369
370 // Write the last 4 bytes of the block header (the nonce) to a copy of
371 // the double-SHA256 state, and compute the result.
372 CHash256(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)phash);
acfa0333
WL
373
374 // Return the nonce if the hash has at least some zero bits,
375 // caller will check if it has enough to reach the target
85aab2a0
PW
376 if (((uint16_t*)phash)[15] == 0)
377 return true;
acfa0333
WL
378
379 // If nothing found after trying for a while, return -1
380 if ((nNonce & 0xffff) == 0)
85aab2a0 381 return false;
acfa0333
WL
382 if ((nNonce & 0xfff) == 0)
383 boost::this_thread::interruption_point();
384 }
385}
386
387CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey)
388{
389 CPubKey pubkey;
390 if (!reservekey.GetReservedKey(pubkey))
391 return NULL;
392
393 CScript scriptPubKey = CScript() << pubkey << OP_CHECKSIG;
394 return CreateNewBlock(scriptPubKey);
395}
396
f0c2915f 397bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
d247a5d1 398{
81212588 399 LogPrintf("%s\n", pblock->ToString());
7d9d134b 400 LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue));
d247a5d1
JG
401
402 // Found a solution
403 {
404 LOCK(cs_main);
4c6d41b8 405 if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash())
d247a5d1 406 return error("BitcoinMiner : generated block is stale");
18e72167 407 }
d247a5d1 408
18e72167
PW
409 // Remove key from key pool
410 reservekey.KeepKey();
d247a5d1 411
18e72167
PW
412 // Track how many getdata requests this block gets
413 {
414 LOCK(wallet.cs_wallet);
415 wallet.mapRequestCount[pblock->GetHash()] = 0;
d247a5d1
JG
416 }
417
18e72167
PW
418 // Process this block the same as if we had received it from another node
419 CValidationState state;
420 if (!ProcessBlock(state, NULL, pblock))
421 return error("BitcoinMiner : ProcessBlock, block not accepted");
422
d247a5d1
JG
423 return true;
424}
425
426void static BitcoinMiner(CWallet *pwallet)
427{
881a85a2 428 LogPrintf("BitcoinMiner started\n");
d247a5d1
JG
429 SetThreadPriority(THREAD_PRIORITY_LOWEST);
430 RenameThread("bitcoin-miner");
431
432 // Each thread has its own key and counter
433 CReserveKey reservekey(pwallet);
434 unsigned int nExtraNonce = 0;
435
0655fac0
PK
436 try {
437 while (true) {
438 if (Params().MiningRequiresPeers()) {
439 // Busy-wait for the network to come online so we don't waste time mining
440 // on an obsolete chain. In regtest mode we expect to fly solo.
441 while (vNodes.empty())
442 MilliSleep(1000);
443 }
d247a5d1 444
0655fac0
PK
445 //
446 // Create new block
447 //
448 unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
449 CBlockIndex* pindexPrev = chainActive.Tip();
450
451 auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
452 if (!pblocktemplate.get())
6c37f7fd
WL
453 {
454 LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
0655fac0 455 return;
6c37f7fd 456 }
0655fac0
PK
457 CBlock *pblock = &pblocktemplate->block;
458 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
459
460 LogPrintf("Running BitcoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
461 ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
462
463 //
464 // Search
465 //
466 int64_t nStart = GetTime();
467 uint256 hashTarget = uint256().SetCompact(pblock->nBits);
468 uint256 hash;
469 uint32_t nNonce = 0;
470 uint32_t nOldNonce = 0;
471 while (true) {
472 bool fFound = ScanHash(pblock, nNonce, &hash);
473 uint32_t nHashesDone = nNonce - nOldNonce;
474 nOldNonce = nNonce;
475
476 // Check if something found
477 if (fFound)
d247a5d1 478 {
0655fac0
PK
479 if (hash <= hashTarget)
480 {
481 // Found a solution
482 pblock->nNonce = nNonce;
483 assert(hash == pblock->GetHash());
d247a5d1 484
0655fac0 485 SetThreadPriority(THREAD_PRIORITY_NORMAL);
f0c2915f 486 LogPrintf("BitcoinMiner:\n");
487 LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex());
488 ProcessBlockFound(pblock, *pwallet, reservekey);
0655fac0 489 SetThreadPriority(THREAD_PRIORITY_LOWEST);
d247a5d1 490
0655fac0
PK
491 // In regression test mode, stop mining after a block is found.
492 if (Params().MineBlocksOnDemand())
493 throw boost::thread_interrupted();
d247a5d1 494
0655fac0
PK
495 break;
496 }
d247a5d1 497 }
d247a5d1 498
0655fac0
PK
499 // Meter hashes/sec
500 static int64_t nHashCounter;
501 if (nHPSTimerStart == 0)
d247a5d1 502 {
0655fac0
PK
503 nHPSTimerStart = GetTimeMillis();
504 nHashCounter = 0;
505 }
506 else
507 nHashCounter += nHashesDone;
508 if (GetTimeMillis() - nHPSTimerStart > 4000)
509 {
510 static CCriticalSection cs;
d247a5d1 511 {
0655fac0
PK
512 LOCK(cs);
513 if (GetTimeMillis() - nHPSTimerStart > 4000)
d247a5d1 514 {
0655fac0
PK
515 dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
516 nHPSTimerStart = GetTimeMillis();
517 nHashCounter = 0;
518 static int64_t nLogTime;
519 if (GetTime() - nLogTime > 30 * 60)
520 {
521 nLogTime = GetTime();
522 LogPrintf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0);
523 }
d247a5d1
JG
524 }
525 }
526 }
d247a5d1 527
0655fac0
PK
528 // Check for stop or if block needs to be rebuilt
529 boost::this_thread::interruption_point();
530 // Regtest mode doesn't require peers
531 if (vNodes.empty() && Params().MiningRequiresPeers())
532 break;
533 if (nNonce >= 0xffff0000)
534 break;
535 if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
536 break;
537 if (pindexPrev != chainActive.Tip())
538 break;
539
540 // Update nTime every few seconds
541 UpdateTime(*pblock, pindexPrev);
542 if (Params().AllowMinDifficultyBlocks())
543 {
544 // Changing pblock->nTime can change work required on testnet:
545 hashTarget.SetCompact(pblock->nBits);
546 }
d247a5d1
JG
547 }
548 }
0655fac0 549 }
d247a5d1
JG
550 catch (boost::thread_interrupted)
551 {
881a85a2 552 LogPrintf("BitcoinMiner terminated\n");
d247a5d1
JG
553 throw;
554 }
555}
556
c8b74258 557void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
d247a5d1
JG
558{
559 static boost::thread_group* minerThreads = NULL;
560
d247a5d1 561 if (nThreads < 0) {
2595b9ac 562 // In regtest threads defaults to 1
563 if (Params().DefaultMinerThreads())
564 nThreads = Params().DefaultMinerThreads();
d247a5d1
JG
565 else
566 nThreads = boost::thread::hardware_concurrency();
567 }
568
569 if (minerThreads != NULL)
570 {
571 minerThreads->interrupt_all();
572 delete minerThreads;
573 minerThreads = NULL;
574 }
575
576 if (nThreads == 0 || !fGenerate)
577 return;
578
579 minerThreads = new boost::thread_group();
580 for (int i = 0; i < nThreads; i++)
581 minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet));
582}
583
0655fac0 584#endif // ENABLE_WALLET
This page took 0.172989 seconds and 4 git commands to generate.