aboutsummaryrefslogtreecommitdiff
path: root/src/miner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/miner.cpp')
-rw-r--r--src/miner.cpp116
1 files changed, 63 insertions, 53 deletions
diff --git a/src/miner.cpp b/src/miner.cpp
index 56a2c5828b..42c8bb970b 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -6,19 +6,23 @@
#include "miner.h"
#include "amount.h"
+#include "chain.h"
#include "chainparams.h"
+#include "coins.h"
#include "consensus/consensus.h"
+#include "consensus/validation.h"
#include "hash.h"
#include "main.h"
#include "net.h"
+#include "policy/policy.h"
#include "pow.h"
#include "primitives/transaction.h"
+#include "script/standard.h"
#include "timedata.h"
+#include "txmempool.h"
#include "util.h"
#include "utilmoneystr.h"
-#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
-#endif
+#include "validationinterface.h"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
@@ -80,17 +84,24 @@ public:
}
};
-void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
+int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
- pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+ int64_t nOldTime = pblock->nTime;
+ int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+
+ if (nOldTime < nNewTime)
+ pblock->nTime = nNewTime;
// Updating time can change work required on testnet:
if (consensusParams.fPowAllowMinDifficultyBlocks)
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
+
+ return nNewTime - nOldTime;
}
CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
{
+ const CChainParams& chainparams = Params();
// Create new block
auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
if(!pblocktemplate.get())
@@ -136,6 +147,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
LOCK2(cs_main, mempool.cs);
CBlockIndex* pindexPrev = chainActive.Tip();
const int nHeight = pindexPrev->nHeight + 1;
+ pblock->nTime = GetAdjustedTime();
CCoinsViewCache view(pcoinsTip);
// Priority order to process transactions
@@ -146,11 +158,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
// This vector will be sorted into a priority queue:
vector<TxPriority> vecPriority;
vecPriority.reserve(mempool.mapTx.size());
- for (map<uint256, CTxMemPoolEntry>::iterator mi = mempool.mapTx.begin();
+ for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
mi != mempool.mapTx.end(); ++mi)
{
- const CTransaction& tx = mi->second.GetTx();
- if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight))
+ const CTransaction& tx = mi->GetTx();
+ if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, pblock->nTime))
continue;
COrphan* porphan = NULL;
@@ -184,7 +196,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
}
mapDependers[txin.prevout.hash].push_back(porphan);
porphan->setDependsOn.insert(txin.prevout.hash);
- nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue;
+ nTotalIn += mempool.mapTx.find(txin.prevout.hash)->GetTx().vout[txin.prevout.n].nValue;
continue;
}
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
@@ -214,7 +226,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
porphan->feeRate = feeRate;
}
else
- vecPriority.push_back(TxPriority(dPriority, feeRate, &mi->second.GetTx()));
+ vecPriority.push_back(TxPriority(dPriority, feeRate, &(mi->GetTx())));
}
// Collect transactions into block
@@ -320,7 +332,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize);
// Compute final coinbase transaction.
- txNew.vout[0].nValue = GetBlockValue(nHeight, nFees);
+ txNew.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
pblock->vtx[0] = txNew;
pblocktemplate->vTxFees[0] = -nFees;
@@ -340,7 +352,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
return pblocktemplate.release();
}
-void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
+void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
{
// Update nExtraNonce
static uint256 hashPrevBlock;
@@ -356,10 +368,9 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
assert(txCoinbase.vin[0].scriptSig.size() <= 100);
pblock->vtx[0] = txCoinbase;
- pblock->hashMerkleRoot = pblock->BuildMerkleTree();
+ pblock->hashMerkleRoot = pblock->ComputeMerkleRoot();
}
-#ifdef ENABLE_WALLET
//////////////////////////////////////////////////////////////////////////////
//
// Internal miner
@@ -398,17 +409,7 @@ bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phas
}
}
-CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey)
-{
- CPubKey pubkey;
- if (!reservekey.GetReservedKey(pubkey))
- return NULL;
-
- CScript scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
- return CreateNewBlock(scriptPubKey);
-}
-
-static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
+static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams)
{
LogPrintf("%s\n", pblock->ToString());
LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue));
@@ -420,41 +421,49 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese
return error("BitcoinMiner: generated block is stale");
}
- // Remove key from key pool
- reservekey.KeepKey();
-
- // Track how many getdata requests this block gets
- {
- LOCK(wallet.cs_wallet);
- wallet.mapRequestCount[pblock->GetHash()] = 0;
- }
+ // Inform about the new block
+ GetMainSignals().BlockFound(pblock->GetHash());
// Process this block the same as if we had received it from another node
CValidationState state;
- if (!ProcessNewBlock(state, NULL, pblock))
+ if (!ProcessNewBlock(state, NULL, pblock, true, NULL))
return error("BitcoinMiner: ProcessNewBlock, block not accepted");
return true;
}
-void static BitcoinMiner(CWallet *pwallet)
+void static BitcoinMiner(const CChainParams& chainparams)
{
LogPrintf("BitcoinMiner started\n");
SetThreadPriority(THREAD_PRIORITY_LOWEST);
RenameThread("bitcoin-miner");
- const CChainParams& chainparams = Params();
- // Each thread has its own key and counter
- CReserveKey reservekey(pwallet);
unsigned int nExtraNonce = 0;
+ boost::shared_ptr<CReserveScript> coinbaseScript;
+ GetMainSignals().ScriptForMining(coinbaseScript);
+
try {
+ // Throw an error if no script was provided. This can happen
+ // due to some internal error but also if the keypool is empty.
+ // In the latter case, already the pointer is NULL.
+ if (!coinbaseScript || coinbaseScript->reserveScript.empty())
+ throw std::runtime_error("No coinbase script available (mining requires a wallet)");
+
while (true) {
if (chainparams.MiningRequiresPeers()) {
// Busy-wait for the network to come online so we don't waste time mining
// on an obsolete chain. In regtest mode we expect to fly solo.
- while (vNodes.empty())
+ do {
+ bool fvNodesEmpty;
+ {
+ LOCK(cs_vNodes);
+ fvNodesEmpty = vNodes.empty();
+ }
+ if (!fvNodesEmpty && !IsInitialBlockDownload())
+ break;
MilliSleep(1000);
+ } while (true);
}
//
@@ -463,7 +472,7 @@ void static BitcoinMiner(CWallet *pwallet)
unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrev = chainActive.Tip();
- auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
+ auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript));
if (!pblocktemplate.get())
{
LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
@@ -495,8 +504,9 @@ void static BitcoinMiner(CWallet *pwallet)
SetThreadPriority(THREAD_PRIORITY_NORMAL);
LogPrintf("BitcoinMiner:\n");
LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex());
- ProcessBlockFound(pblock, *pwallet, reservekey);
+ ProcessBlockFound(pblock, chainparams);
SetThreadPriority(THREAD_PRIORITY_LOWEST);
+ coinbaseScript->KeepScript();
// In regression test mode, stop mining after a block is found.
if (chainparams.MineBlocksOnDemand())
@@ -519,7 +529,9 @@ void static BitcoinMiner(CWallet *pwallet)
break;
// Update nTime every few seconds
- UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
+ if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0)
+ break; // Recreate the block if the clock has run backwards,
+ // so that we can use the correct time.
if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks)
{
// Changing pblock->nTime can change work required on testnet:
@@ -533,19 +545,19 @@ void static BitcoinMiner(CWallet *pwallet)
LogPrintf("BitcoinMiner terminated\n");
throw;
}
+ catch (const std::runtime_error &e)
+ {
+ LogPrintf("BitcoinMiner runtime error: %s\n", e.what());
+ return;
+ }
}
-void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
+void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams)
{
static boost::thread_group* minerThreads = NULL;
- if (nThreads < 0) {
- // In regtest threads defaults to 1
- if (Params().DefaultMinerThreads())
- nThreads = Params().DefaultMinerThreads();
- else
- nThreads = boost::thread::hardware_concurrency();
- }
+ if (nThreads < 0)
+ nThreads = GetNumCores();
if (minerThreads != NULL)
{
@@ -559,7 +571,5 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
minerThreads = new boost::thread_group();
for (int i = 0; i < nThreads; i++)
- minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet));
+ minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams)));
}
-
-#endif // ENABLE_WALLET