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