aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp1511
1 files changed, 512 insertions, 999 deletions
diff --git a/src/main.cpp b/src/main.cpp
index d35891440..a5a0f031a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2012 The Bitcoin developers
+// Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -32,13 +32,8 @@ CTxMemPool mempool;
unsigned int nTransactionsUpdated = 0;
map<uint256, CBlockIndex*> mapBlockIndex;
-std::vector<CBlockIndex*> vBlockIndexByHeight;
-CBlockIndex* pindexGenesisBlock = NULL;
-int nBestHeight = -1;
-uint256 nBestChainWork = 0;
+CChain chainActive;
uint256 nBestInvalidWork = 0;
-uint256 hashBestChain = 0;
-CBlockIndex* pindexBest = NULL;
set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; // may contain all CBlockIndex*'s that have validness >=BLOCK_VALID_TRANSACTIONS, and must contain those who aren't failed
int64 nTimeBestReceived = 0;
int nScriptCheckThreads = 0;
@@ -59,17 +54,14 @@ CMedianFilter<int> cPeerBlockCounts(8, 0); // Amount of blocks that other nodes
map<uint256, CBlock*> mapOrphanBlocks;
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
-map<uint256, CDataStream*> mapOrphanTransactions;
-map<uint256, map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
+map<uint256, CTransaction> mapOrphanTransactions;
+map<uint256, set<uint256> > mapOrphanTransactionsByPrev;
// Constant stuff for coinbase transactions we create:
CScript COINBASE_FLAGS;
const string strMessageMagic = "Bitcoin Signed Message:\n";
-double dHashesPerSec = 0.0;
-int64 nHPSTimerStart = 0;
-
// Settings
int64 nTransactionFee = 0;
@@ -176,106 +168,83 @@ void static ResendWalletTransactions()
// Registration of network node signals.
//
+int static GetHeight()
+{
+ LOCK(cs_main);
+ return chainActive.Height();
+}
+
void RegisterNodeSignals(CNodeSignals& nodeSignals)
{
+ nodeSignals.GetHeight.connect(&GetHeight);
nodeSignals.ProcessMessages.connect(&ProcessMessages);
nodeSignals.SendMessages.connect(&SendMessages);
}
void UnregisterNodeSignals(CNodeSignals& nodeSignals)
{
+ nodeSignals.GetHeight.disconnect(&GetHeight);
nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
nodeSignals.SendMessages.disconnect(&SendMessages);
}
//////////////////////////////////////////////////////////////////////////////
//
-// CBlockLocator implementation
+// CChain implementation
//
-CBlockLocator::CBlockLocator(uint256 hashBlock)
-{
- std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
- if (mi != mapBlockIndex.end())
- Set((*mi).second);
+CBlockIndex *CChain::SetTip(CBlockIndex *pindex) {
+ if (pindex == NULL) {
+ vChain.clear();
+ return NULL;
+ }
+ vChain.resize(pindex->nHeight + 1);
+ while (pindex && vChain[pindex->nHeight] != pindex) {
+ vChain[pindex->nHeight] = pindex;
+ pindex = pindex->pprev;
+ }
+ return pindex;
}
-void CBlockLocator::Set(const CBlockIndex* pindex)
-{
- vHave.clear();
+CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
int nStep = 1;
- while (pindex)
- {
- vHave.push_back(pindex->GetBlockHash());
+ std::vector<uint256> vHave;
+ vHave.reserve(32);
- // Exponentially larger steps back
- for (int i = 0; pindex && i < nStep; i++)
+ if (!pindex)
+ pindex = Tip();
+ while (pindex) {
+ vHave.push_back(pindex->GetBlockHash());
+ // Stop when we have added the genesis block.
+ if (pindex->nHeight == 0)
+ break;
+ // Exponentially larger steps back, plus the genesis block.
+ int nHeight = std::max(pindex->nHeight - nStep, 0);
+ // In case pindex is not in this chain, iterate pindex->pprev to find blocks.
+ while (pindex->nHeight > nHeight && !Contains(pindex))
pindex = pindex->pprev;
+ // If pindex is in this chain, use direct height-based access.
+ if (pindex->nHeight > nHeight)
+ pindex = (*this)[nHeight];
if (vHave.size() > 10)
nStep *= 2;
}
- vHave.push_back(Params().HashGenesisBlock());
-}
-int CBlockLocator::GetDistanceBack()
-{
- // Retrace how far back it was in the sender's branch
- int nDistance = 0;
- int nStep = 1;
- BOOST_FOREACH(const uint256& hash, vHave)
- {
- std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
- if (mi != mapBlockIndex.end())
- {
- CBlockIndex* pindex = (*mi).second;
- if (pindex->IsInMainChain())
- return nDistance;
- }
- nDistance += nStep;
- if (nDistance > 10)
- nStep *= 2;
- }
- return nDistance;
+ return CBlockLocator(vHave);
}
-CBlockIndex *CBlockLocator::GetBlockIndex()
-{
+CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const {
// Find the first block the caller has in the main chain
- BOOST_FOREACH(const uint256& hash, vHave)
- {
+ BOOST_FOREACH(const uint256& hash, locator.vHave) {
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
- if (pindex->IsInMainChain())
+ if (Contains(pindex))
return pindex;
}
}
- return pindexGenesisBlock;
-}
-
-uint256 CBlockLocator::GetBlockHash()
-{
- // Find the first block the caller has in the main chain
- BOOST_FOREACH(const uint256& hash, vHave)
- {
- std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
- if (mi != mapBlockIndex.end())
- {
- CBlockIndex* pindex = (*mi).second;
- if (pindex->IsInMainChain())
- return hash;
- }
- }
- return Params().HashGenesisBlock();
-}
-
-int CBlockLocator::GetHeight()
-{
- CBlockIndex* pindex = GetBlockIndex();
- if (!pindex)
- return 0;
- return pindex->nHeight;
+ return Genesis();
}
//////////////////////////////////////////////////////////////////////////////
@@ -399,16 +368,12 @@ CBlockTreeDB *pblocktree = NULL;
// mapOrphanTransactions
//
-bool AddOrphanTx(const CDataStream& vMsg)
+bool AddOrphanTx(const CTransaction& tx)
{
- CTransaction tx;
- CDataStream(vMsg) >> tx;
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
return false;
- CDataStream* pvMsg = new CDataStream(vMsg);
-
// Ignore big transactions, to avoid a
// send-big-orphans memory exhaustion attack. If a peer has a legitimate
// large transaction with a missing parent then we assume
@@ -416,18 +381,18 @@ bool AddOrphanTx(const CDataStream& vMsg)
// have been mined or received.
// 10,000 orphans, each of which is at most 5,000 bytes big is
// at most 500 megabytes of orphans:
- if (pvMsg->size() > 5000)
+ unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
+ if (sz > 5000)
{
- printf("ignoring large orphan tx (size: %"PRIszu", hash: %s)\n", pvMsg->size(), hash.ToString().c_str());
- delete pvMsg;
+ LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString().c_str());
return false;
}
- mapOrphanTransactions[hash] = pvMsg;
+ mapOrphanTransactions[hash] = tx;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
- mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg));
+ mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash);
- printf("stored orphan tx %s (mapsz %"PRIszu")\n", hash.ToString().c_str(),
+ LogPrint("mempool", "stored orphan tx %s (mapsz %"PRIszu")\n", hash.ToString().c_str(),
mapOrphanTransactions.size());
return true;
}
@@ -436,16 +401,13 @@ void static EraseOrphanTx(uint256 hash)
{
if (!mapOrphanTransactions.count(hash))
return;
- const CDataStream* pvMsg = mapOrphanTransactions[hash];
- CTransaction tx;
- CDataStream(*pvMsg) >> tx;
+ const CTransaction& tx = mapOrphanTransactions[hash];
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash);
if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty())
mapOrphanTransactionsByPrev.erase(txin.prevout.hash);
}
- delete pvMsg;
mapOrphanTransactions.erase(hash);
}
@@ -456,7 +418,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
{
// Evict a random orphan:
uint256 randomhash = GetRandHash();
- map<uint256, CDataStream*>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
+ map<uint256, CTransaction>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
if (it == mapOrphanTransactions.end())
it = mapOrphanTransactions.begin();
EraseOrphanTx(it->first);
@@ -473,7 +435,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
bool IsStandardTx(const CTransaction& tx, string& reason)
{
- if (tx.nVersion > CTransaction::CURRENT_VERSION) {
+ if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) {
reason = "version";
return false;
}
@@ -527,7 +489,7 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64 nBlockTime)
if (tx.nLockTime == 0)
return true;
if (nBlockHeight == 0)
- nBlockHeight = nBestHeight;
+ nBlockHeight = chainActive.Height();
if (nBlockTime == 0)
nBlockTime = GetAdjustedTime();
if ((int64)tx.nLockTime < ((int64)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
@@ -654,7 +616,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
if (pblock == NULL) {
CCoins coins;
if (pcoinsTip->GetCoins(GetHash(), coins)) {
- CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
+ CBlockIndex *pindex = chainActive[coins.nHeight];
if (pindex) {
if (!ReadBlockFromDisk(blockTmp, pindex))
return 0;
@@ -675,7 +637,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
{
vMerkleBranch.clear();
nIndex = -1;
- printf("ERROR: SetMerkleBranch() : couldn't find tx in block\n");
+ LogPrintf("ERROR: SetMerkleBranch() : couldn't find tx in block\n");
return 0;
}
@@ -688,10 +650,10 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
- if (!pindex || !pindex->IsInMainChain())
+ if (!pindex || !chainActive.Contains(pindex))
return 0;
- return pindexBest->nHeight - pindex->nHeight + 1;
+ return chainActive.Height() - pindex->nHeight + 1;
}
@@ -760,15 +722,18 @@ int64 GetMinFee(const CTransaction& tx, bool fAllowFree, enum GetMinFee_mode mod
{
// There is a free transaction area in blocks created by most miners,
// * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000
- // to be considered to fall into this category
- // * If we are creating a transaction we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 17000
- // (= 10000) to be considered safe and assume they can likely make it into this section
- if (nBytes < (mode == GMF_SEND ? (DEFAULT_BLOCK_PRIORITY_SIZE - 17000) : (DEFAULT_BLOCK_PRIORITY_SIZE - 1000)))
+ // to be considered to fall into this category. We don't want to encourage sending
+ // multiple transactions instead of one big transaction to avoid fees.
+ // * If we are creating a transaction we allow transactions up to 1,000 bytes
+ // to be considered safe and assume they can likely make it into this section.
+ if (nBytes < (mode == GMF_SEND ? 1000 : (DEFAULT_BLOCK_PRIORITY_SIZE - 1000)))
nMinFee = 0;
}
- // To limit dust spam, require base fee if any output is less than 0.01
- if (nMinFee < nBaseFee)
+ // This code can be removed after enough miners have upgraded to version 0.9.
+ // Until then, be safe when sending and require a fee if any output
+ // is less than CENT:
+ if (nMinFee < nBaseFee && mode == GMF_SEND)
{
BOOST_FOREACH(const CTxOut& txout, tx.vout)
if (txout.nValue < CENT)
@@ -793,8 +758,8 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
}
}
-bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs)
+bool CTxMemPool::accept(CValidationState &state, const CTransaction &tx, bool fLimitFree,
+ bool* pfMissingInputs, bool fRejectInsaneFee)
{
if (pfMissingInputs)
*pfMissingInputs = false;
@@ -810,9 +775,9 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
if ((int64)tx.nLockTime > std::numeric_limits<int>::max())
return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");
- // Rather not work on nonstandard transactions (unless -testnet)
+ // Rather not work on nonstandard transactions (unless -testnet/-regtest)
string reason;
- if (!TestNet() && !IsStandardTx(tx, reason))
+ if (Params().NetworkID() == CChainParams::MAIN && !IsStandardTx(tx, reason))
return error("CTxMemPool::accept() : nonstandard transaction: %s",
reason.c_str());
@@ -888,7 +853,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
}
// Check for non-standard pay-to-script-hash in inputs
- if (!TestNet() && !AreInputsStandard(tx, view))
+ if (Params().NetworkID() == CChainParams::MAIN && !AreInputsStandard(tx, view))
return error("CTxMemPool::accept() : nonstandard transaction input");
// Note: if you modify this code to accept non-standard transactions, then
@@ -924,10 +889,15 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
return error("CTxMemPool::accept() : free transaction rejected by rate limiter");
if (fDebug)
- printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
+ LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize;
}
+ if (fRejectInsaneFee && nFees > CTransaction::nMinRelayTxFee * 10000)
+ return error("CTxMemPool::accept() : insane fees %s, %"PRI64d" > %"PRI64d,
+ hash.ToString().c_str(),
+ nFees, CTransaction::nMinRelayTxFee * 10000);
+
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC))
@@ -941,7 +911,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
LOCK(cs);
if (ptxOld)
{
- printf("CTxMemPool::accept() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
+ LogPrint("mempool", "CTxMemPool::accept() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
remove(*ptxOld);
}
addUnchecked(hash, tx);
@@ -953,14 +923,14 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
EraseFromWallets(ptxOld->GetHash());
SyncWithWallets(hash, tx, NULL, true);
- printf("CTxMemPool::accept() : accepted %s (poolsz %"PRIszu")\n",
+ LogPrint("mempool", "CTxMemPool::accept() : accepted %s (poolsz %"PRIszu")\n",
hash.ToString().c_str(),
mapTx.size());
return true;
}
-bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
+bool CTxMemPool::addUnchecked(const uint256& hash, const CTransaction &tx)
{
// Add to memory pool without checking anything. Don't call this directly,
// call CTxMemPool::accept to properly check the transaction first.
@@ -980,15 +950,15 @@ bool CTxMemPool::remove(const CTransaction &tx, bool fRecursive)
{
LOCK(cs);
uint256 hash = tx.GetHash();
+ if (fRecursive) {
+ for (unsigned int i = 0; i < tx.vout.size(); i++) {
+ std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(hash, i));
+ if (it != mapNextTx.end())
+ remove(*it->second.ptx, true);
+ }
+ }
if (mapTx.count(hash))
{
- if (fRecursive) {
- for (unsigned int i = 0; i < tx.vout.size(); i++) {
- std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(hash, i));
- if (it != mapNextTx.end())
- remove(*it->second.ptx, true);
- }
- }
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapNextTx.erase(txin.prevout);
mapTx.erase(hash);
@@ -1021,6 +991,45 @@ void CTxMemPool::clear()
++nTransactionsUpdated;
}
+bool CTxMemPool::fChecks = false;
+
+void CTxMemPool::check(CCoinsViewCache *pcoins) const
+{
+ if (!fChecks)
+ return;
+
+ LogPrintf("Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());
+
+ LOCK(cs);
+ for (std::map<uint256, CTransaction>::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
+ unsigned int i = 0;
+ BOOST_FOREACH(const CTxIn &txin, it->second.vin) {
+ // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
+ std::map<uint256, CTransaction>::const_iterator it2 = mapTx.find(txin.prevout.hash);
+ if (it2 != mapTx.end()) {
+ assert(it2->second.vout.size() > txin.prevout.n && !it2->second.vout[txin.prevout.n].IsNull());
+ } else {
+ CCoins &coins = pcoins->GetCoins(txin.prevout.hash);
+ assert(coins.IsAvailable(txin.prevout.n));
+ }
+ // Check whether its inputs are marked in mapNextTx.
+ std::map<COutPoint, CInPoint>::const_iterator it3 = mapNextTx.find(txin.prevout);
+ assert(it3 != mapNextTx.end());
+ assert(it3->second.ptx == &it->second);
+ assert(it3->second.n == i);
+ i++;
+ }
+ }
+ for (std::map<COutPoint, CInPoint>::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) {
+ uint256 hash = it->second.ptx->GetHash();
+ std::map<uint256, CTransaction>::const_iterator it2 = mapTx.find(hash);
+ assert(it2 != mapTx.end());
+ assert(&it2->second == it->second.ptx);
+ assert(it2->second.vin.size() > it->second.n);
+ assert(it->first == it->second.ptx->vin[it->second.n].prevout);
+ }
+}
+
void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
{
vtxid.clear();
@@ -1044,7 +1053,7 @@ int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
- if (!pindex || !pindex->IsInMainChain())
+ if (!pindex || !chainActive.Contains(pindex))
return 0;
// Make sure the merkle branch connects to this block
@@ -1056,7 +1065,7 @@ int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
}
pindexRet = pindex;
- return pindexBest->nHeight - pindex->nHeight + 1;
+ return chainActive.Height() - pindex->nHeight + 1;
}
@@ -1064,7 +1073,7 @@ int CMerkleTx::GetBlocksToMaturity() const
{
if (!IsCoinBase())
return 0;
- return max(0, (COINBASE_MATURITY+20) - GetDepthInMainChain());
+ return max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain());
}
@@ -1139,7 +1148,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
nHeight = coins.nHeight;
}
if (nHeight > 0)
- pindexSlow = FindBlockByHeight(nHeight);
+ pindexSlow = chainActive[nHeight];
}
}
@@ -1169,14 +1178,6 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
// CBlock and CBlockIndex
//
-static CBlockIndex* pblockindexFBBHLast;
-CBlockIndex* FindBlockByHeight(int nHeight)
-{
- if (nHeight >= (int)vBlockIndexByHeight.size())
- return NULL;
- return vBlockIndexByHeight[nHeight];
-}
-
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos)
{
// Open history file to append
@@ -1244,7 +1245,7 @@ uint256 static GetOrphanRoot(const CBlockHeader* pblock)
return pblock->GetHash();
}
-int64 static GetBlockValue(int nHeight, int64 nFees)
+int64 GetBlockValue(int nHeight, int64 nFees)
{
int64 nSubsidy = 50 * COIN;
@@ -1284,7 +1285,7 @@ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
return bnResult.GetCompact();
}
-unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
+unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact();
@@ -1322,7 +1323,7 @@ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBl
// Limit adjustment step
int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
- printf(" nActualTimespan = %"PRI64d" before bounds\n", nActualTimespan);
+ LogPrintf(" nActualTimespan = %"PRI64d" before bounds\n", nActualTimespan);
if (nActualTimespan < nTargetTimespan/4)
nActualTimespan = nTargetTimespan/4;
if (nActualTimespan > nTargetTimespan*4)
@@ -1338,10 +1339,10 @@ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBl
bnNew = Params().ProofOfWorkLimit();
/// debug print
- printf("GetNextWorkRequired RETARGET\n");
- printf("nTargetTimespan = %"PRI64d" nActualTimespan = %"PRI64d"\n", nTargetTimespan, nActualTimespan);
- printf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str());
- printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str());
+ LogPrintf("GetNextWorkRequired RETARGET\n");
+ LogPrintf("nTargetTimespan = %"PRI64d" nActualTimespan = %"PRI64d"\n", nTargetTimespan, nActualTimespan);
+ LogPrintf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str());
+ LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str());
return bnNew.GetCompact();
}
@@ -1370,17 +1371,98 @@ int GetNumBlocksOfPeers()
bool IsInitialBlockDownload()
{
- if (pindexBest == NULL || fImporting || fReindex || nBestHeight < Checkpoints::GetTotalBlocksEstimate())
+ if (fImporting || fReindex || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate())
return true;
static int64 nLastUpdate;
static CBlockIndex* pindexLastBest;
- if (pindexBest != pindexLastBest)
+ if (chainActive.Tip() != pindexLastBest)
{
- pindexLastBest = pindexBest;
+ pindexLastBest = chainActive.Tip();
nLastUpdate = GetTime();
}
return (GetTime() - nLastUpdate < 10 &&
- pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
+ chainActive.Tip()->GetBlockTime() < GetTime() - 24 * 60 * 60);
+}
+
+bool fLargeWorkForkFound = false;
+bool fLargeWorkInvalidChainFound = false;
+CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL;
+
+void CheckForkWarningConditions()
+{
+ // Before we get past initial download, we cannot reliably alert about forks
+ // (we assume we don't get stuck on a fork before the last checkpoint)
+ if (IsInitialBlockDownload())
+ return;
+
+ // If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it)
+ // of our head, drop it
+ if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72)
+ pindexBestForkTip = NULL;
+
+ if (pindexBestForkTip || nBestInvalidWork > chainActive.Tip()->nChainWork + (chainActive.Tip()->GetBlockWork() * 6).getuint256())
+ {
+ if (!fLargeWorkForkFound)
+ {
+ std::string strCmd = GetArg("-alertnotify", "");
+ if (!strCmd.empty())
+ {
+ std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
+ pindexBestForkBase->phashBlock->ToString() + std::string("'");
+ boost::replace_all(strCmd, "%s", warning);
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
+ }
+ if (pindexBestForkTip)
+ {
+ LogPrintf("CheckForkWarningConditions: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n",
+ pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString().c_str(),
+ pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString().c_str());
+ fLargeWorkForkFound = true;
+ }
+ else
+ {
+ LogPrintf("CheckForkWarningConditions: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n");
+ fLargeWorkInvalidChainFound = true;
+ }
+ }
+ else
+ {
+ fLargeWorkForkFound = false;
+ fLargeWorkInvalidChainFound = false;
+ }
+}
+
+void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
+{
+ // If we are on a fork that is sufficiently large, set a warning flag
+ CBlockIndex* pfork = pindexNewForkTip;
+ CBlockIndex* plonger = chainActive.Tip();
+ while (pfork && pfork != plonger)
+ {
+ while (plonger && plonger->nHeight > pfork->nHeight)
+ plonger = plonger->pprev;
+ if (pfork == plonger)
+ break;
+ pfork = pfork->pprev;
+ }
+
+ // We define a condition which we should warn the user about as a fork of at least 7 blocks
+ // who's tip is within 72 blocks (+/- 12 hours if no one mines it) of ours
+ // We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network
+ // hash rate operating on the fork.
+ // or a chain that is entirely longer than ours and invalid (note that this should be detected by both)
+ // We define it this way because it allows us to only store the highest fork tip (+ base) which meets
+ // the 7-block condition and from this always have the most-likely-to-cause-warning fork
+ if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) &&
+ pindexNewForkTip->nChainWork - pfork->nChainWork > (pfork->GetBlockWork() * 7).getuint256() &&
+ chainActive.Height() - pindexNewForkTip->nHeight < 72)
+ {
+ pindexBestForkTip = pindexNewForkTip;
+ pindexBestForkBase = pfork;
+ }
+
+ CheckForkWarningConditions();
}
void static InvalidChainFound(CBlockIndex* pindexNew)
@@ -1391,15 +1473,14 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
pblocktree->WriteBestInvalidWork(CBigNum(nBestInvalidWork));
uiInterface.NotifyBlocksChanged();
}
- printf("InvalidChainFound: invalid block=%s height=%d log2_work=%.8g date=%s\n",
+ LogPrintf("InvalidChainFound: invalid block=%s height=%d log2_work=%.8g date=%s\n",
pindexNew->GetBlockHash().ToString().c_str(), pindexNew->nHeight,
log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S",
pindexNew->GetBlockTime()).c_str());
- printf("InvalidChainFound: current best=%s height=%d log2_work=%.8g date=%s\n",
- hashBestChain.ToString().c_str(), nBestHeight, log(nBestChainWork.getdouble())/log(2.0),
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexBest->GetBlockTime()).c_str());
- if (pindexBest && nBestInvalidWork > nBestChainWork + (pindexBest->GetBlockWork() * 6).getuint256())
- printf("InvalidChainFound: Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n");
+ LogPrintf("InvalidChainFound: current best=%s height=%d log2_work=%.8g date=%s\n",
+ chainActive.Tip()->GetBlockHash().ToString().c_str(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0),
+ DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()).c_str());
+ CheckForkWarningConditions();
}
void static InvalidBlockFound(CBlockIndex *pindex) {
@@ -1407,7 +1488,7 @@ void static InvalidBlockFound(CBlockIndex *pindex) {
pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex));
setBlockIndexValid.erase(pindex);
InvalidChainFound(pindex);
- if (pindex->GetNextInMainChain()) {
+ if (chainActive.Next(pindex)) {
CValidationState stateDummy;
ConnectBestBlock(stateDummy); // reorganise away from the failed block
}
@@ -1424,7 +1505,7 @@ bool ConnectBestBlock(CValidationState &state) {
pindexNewBest = *it;
}
- if (pindexNewBest == pindexBest || (pindexBest && pindexNewBest->nChainWork == pindexBest->nChainWork))
+ if (pindexNewBest == chainActive.Tip() || (chainActive.Tip() && pindexNewBest->nChainWork == chainActive.Tip()->nChainWork))
return true; // nothing to do
// check ancestry
@@ -1444,10 +1525,10 @@ bool ConnectBestBlock(CValidationState &state) {
break;
}
- if (pindexBest == NULL || pindexTest->nChainWork > pindexBest->nChainWork)
+ if (chainActive.Tip() == NULL || pindexTest->nChainWork > chainActive.Tip()->nChainWork)
vAttach.push_back(pindexTest);
- if (pindexTest->pprev == NULL || pindexTest->GetNextInMainChain()) {
+ if (pindexTest->pprev == NULL || chainActive.Next(pindexTest)) {
reverse(vAttach.begin(), vAttach.end());
BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) {
boost::this_thread::interruption_point();
@@ -1664,8 +1745,14 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
view.SetCoins(hash, CCoins());
}
CCoins &outs = view.GetCoins(hash);
+ outs.ClearUnspendable();
CCoins outsBlock = CCoins(tx, pindex->nHeight);
+ // The CCoins serialization does not serialize negative numbers.
+ // No network rules currently depend on the version here, so an inconsistency is harmless
+ // but it must be corrected before txout nversion ever influences a network rule.
+ if (outsBlock.nVersion < 0)
+ outs.nVersion = outsBlock.nVersion;
if (outs != outsBlock)
fClean = fClean && error("DisconnectBlock() : added transaction mismatch? database corrupted");
@@ -1761,7 +1848,6 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
// (its coinbase is unspendable)
if (block.GetHash() == Params().HashGenesisBlock()) {
view.SetBestBlock(pindex);
- pindexGenesisBlock = pindex;
return true;
}
@@ -1850,7 +1936,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
}
int64 nTime = GetTimeMicros() - nStart;
if (fBenchmark)
- printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)block.vtx.size(), 0.001 * nTime, 0.001 * nTime / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
+ LogPrintf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)block.vtx.size(), 0.001 * nTime, 0.001 * nTime / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
if (GetValueOut(block.vtx[0]) > GetBlockValue(pindex->nHeight, nFees))
return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(block.vtx[0]), GetBlockValue(pindex->nHeight, nFees)));
@@ -1859,7 +1945,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
return state.DoS(100, false);
int64 nTime2 = GetTimeMicros() - nStart;
if (fBenchmark)
- printf("- Verify %u txins: %.2fms (%.3fms/txin)\n", nInputs - 1, 0.001 * nTime2, nInputs <= 1 ? 0 : 0.001 * nTime2 / (nInputs-1));
+ LogPrintf("- Verify %u txins: %.2fms (%.3fms/txin)\n", nInputs - 1, 0.001 * nTime2, nInputs <= 1 ? 0 : 0.001 * nTime2 / (nInputs-1));
if (fJustCheck)
return true;
@@ -1902,6 +1988,8 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
{
+ mempool.check(pcoinsTip);
+
// All modifications to the coin state will be done in this cache.
// Only when all have succeeded, we push it to pcoinsTip.
CCoinsViewCache view(*pcoinsTip, true);
@@ -1933,12 +2021,12 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
reverse(vConnect.begin(), vConnect.end());
if (vDisconnect.size() > 0) {
- printf("REORGANIZE: Disconnect %"PRIszu" blocks; %s..\n", vDisconnect.size(), pfork->GetBlockHash().ToString().c_str());
- printf("REORGANIZE: Connect %"PRIszu" blocks; ..%s\n", vConnect.size(), pindexNew->GetBlockHash().ToString().c_str());
+ LogPrintf("REORGANIZE: Disconnect %"PRIszu" blocks; %s...\n", vDisconnect.size(), pfork->GetBlockHash().ToString().c_str());
+ LogPrintf("REORGANIZE: Connect %"PRIszu" blocks; ...%s\n", vConnect.size(), pindexNew->GetBlockHash().ToString().c_str());
}
// Disconnect shorter branch
- vector<CTransaction> vResurrect;
+ list<CTransaction> vResurrect;
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
CBlock block;
if (!ReadBlockFromDisk(block, pindex))
@@ -1947,14 +2035,14 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
if (!DisconnectBlock(block, state, pindex, view))
return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str());
if (fBenchmark)
- printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
+ LogPrintf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
// Queue memory transactions to resurrect.
// We only do this for blocks after the last checkpoint (reorganisation before that
// point should only happen with -reindex/-loadblock, or a misbehaving peer.
- BOOST_FOREACH(const CTransaction& tx, block.vtx)
+ BOOST_REVERSE_FOREACH(const CTransaction& tx, block.vtx)
if (!tx.IsCoinBase() && pindex->nHeight > Checkpoints::GetTotalBlocksEstimate())
- vResurrect.push_back(tx);
+ vResurrect.push_front(tx);
}
// Connect longer branch
@@ -1972,7 +2060,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
return error("SetBestBlock() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().c_str());
}
if (fBenchmark)
- printf("- Connect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
+ LogPrintf("- Connect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
// Queue memory transactions to delete
BOOST_FOREACH(const CTransaction& tx, block.vtx)
@@ -1985,7 +2073,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
assert(view.Flush());
int64 nTime = GetTimeMicros() - nStart;
if (fBenchmark)
- printf("- Flush %i transactions: %.2fms (%.4fms/tx)\n", nModified, 0.001 * nTime, 0.001 * nTime / nModified);
+ LogPrintf("- Flush %i transactions: %.2fms (%.4fms/tx)\n", nModified, 0.001 * nTime, 0.001 * nTime / nModified);
// Make sure it's successfully written to disk before changing memory structure
bool fIsInitialDownload = IsInitialBlockDownload();
@@ -2007,15 +2095,14 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
// Proceed by updating the memory structures.
// Register new best chain
- vBlockIndexByHeight.resize(pindexNew->nHeight + 1);
- BOOST_FOREACH(CBlockIndex* pindex, vConnect)
- vBlockIndexByHeight[pindex->nHeight] = pindex;
+ chainActive.SetTip(pindexNew);
// Resurrect memory transactions that were in the disconnected branch
BOOST_FOREACH(CTransaction& tx, vResurrect) {
// ignore validation errors in resurrected transactions
CValidationState stateDummy;
- mempool.accept(stateDummy, tx, false, NULL);
+ if (!mempool.accept(stateDummy, tx, false, NULL))
+ mempool.remove(tx, true);
}
// Delete redundant memory transactions that are in the connected branch
@@ -2024,31 +2111,25 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
mempool.removeConflicts(tx);
}
+ mempool.check(pcoinsTip);
+
// Update best block in wallet (so we can detect restored wallets)
if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0))
- {
- const CBlockLocator locator(pindexNew);
- ::SetBestChain(locator);
- }
+ ::SetBestChain(chainActive.GetLocator(pindexNew));
// New best block
- hashBestChain = pindexNew->GetBlockHash();
- pindexBest = pindexNew;
- pblockindexFBBHLast = NULL;
- nBestHeight = pindexBest->nHeight;
- nBestChainWork = pindexNew->nChainWork;
nTimeBestReceived = GetTime();
nTransactionsUpdated++;
- printf("SetBestChain: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f\n",
- hashBestChain.ToString().c_str(), nBestHeight, log(nBestChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx,
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexBest->GetBlockTime()).c_str(),
- Checkpoints::GuessVerificationProgress(pindexBest));
+ LogPrintf("SetBestChain: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f\n",
+ chainActive.Tip()->GetBlockHash().ToString().c_str(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx,
+ DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()).c_str(),
+ Checkpoints::GuessVerificationProgress(chainActive.Tip()));
// Check the version of the last 100 blocks to see if we need to upgrade:
if (!fIsInitialDownload)
{
int nUpgraded = 0;
- const CBlockIndex* pindex = pindexBest;
+ const CBlockIndex* pindex = chainActive.Tip();
for (int i = 0; i < 100 && pindex != NULL; i++)
{
if (pindex->nVersion > CBlock::CURRENT_VERSION)
@@ -2056,7 +2137,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
pindex = pindex->pprev;
}
if (nUpgraded > 0)
- printf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, CBlock::CURRENT_VERSION);
+ LogPrintf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, CBlock::CURRENT_VERSION);
if (nUpgraded > 100/2)
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
strMiscWarning = _("Warning: This version is obsolete, upgrade required!");
@@ -2066,7 +2147,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
if (!fIsInitialDownload && !strCmd.empty())
{
- boost::replace_all(strCmd, "%s", hashBestChain.GetHex());
+ boost::replace_all(strCmd, "%s", chainActive.Tip()->GetBlockHash().GetHex());
boost::thread t(runCommand, strCmd); // thread runs free
}
@@ -2108,13 +2189,16 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos
if (!ConnectBestBlock(state))
return false;
- if (pindexNew == pindexBest)
+ if (pindexNew == chainActive.Tip())
{
+ // Clear fork warning if its no longer applicable
+ CheckForkWarningConditions();
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase;
UpdatedTransaction(hashPrevBestCoinBase);
hashPrevBestCoinBase = block.GetTxHash(0);
- }
+ } else
+ CheckForkWarningConditionsOnNewFork(pindexNew);
if (!pblocktree->Flush())
return state.Abort(_("Failed to sync block index"));
@@ -2139,7 +2223,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd
}
} else {
while (infoLastBlockFile.nSize + nAddSize >= MAX_BLOCKFILE_SIZE) {
- printf("Leaving block file %i: %s\n", nLastBlockFile, infoLastBlockFile.ToString().c_str());
+ LogPrintf("Leaving block file %i: %s\n", nLastBlockFile, infoLastBlockFile.ToString().c_str());
FlushBlockFile(true);
nLastBlockFile++;
infoLastBlockFile.SetNull();
@@ -2160,7 +2244,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd
if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos)) {
FILE *file = OpenBlockFile(pos);
if (file) {
- printf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile);
+ LogPrintf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile);
AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos);
fclose(file);
}
@@ -2206,7 +2290,7 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) {
FILE *file = OpenUndoFile(pos);
if (file) {
- printf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile);
+ LogPrintf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile);
AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos);
fclose(file);
}
@@ -2271,7 +2355,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
// Check merkle root
- if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree())
+ if (fCheckMerkleRoot && block.hashMerkleRoot != block.vMerkleTree.back())
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
return true;
@@ -2328,7 +2412,8 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100)))
{
CScript expect = CScript() << nHeight;
- if (!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin()))
+ if (block.vtx[0].vin[0].scriptSig.size() < expect.size() ||
+ !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin()))
return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"));
}
}
@@ -2353,11 +2438,11 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
// Relay inventory, but don't relay old inventory during initial block download
int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
- if (hashBestChain == hash)
+ if (chainActive.Tip()->GetBlockHash() == hash)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
- if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
+ if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
pnode->PushInventory(CInv(MSG_BLOCK, hash));
}
@@ -2376,6 +2461,18 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns
return (nFound >= nRequired);
}
+int64 CBlockIndex::GetMedianTime() const
+{
+ const CBlockIndex* pindex = this;
+ for (int i = 0; i < nMedianTimeSpan/2; i++)
+ {
+ if (!chainActive.Next(pindex))
+ return GetBlockTime();
+ pindex = chainActive.Next(pindex);
+ }
+ return pindex->GetMedianTimePast();
+}
+
void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
{
// Filter out duplicate requests
@@ -2384,7 +2481,7 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
pnode->pindexLastGetBlocksBegin = pindexBegin;
pnode->hashLastGetBlocksEnd = hashEnd;
- pnode->PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
+ pnode->PushMessage("getblocks", chainActive.GetLocator(pindexBegin), hashEnd);
}
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
@@ -2401,7 +2498,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
return error("ProcessBlock() : CheckBlock FAILED");
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
- if (pcheckpoint && pblock->hashPrevBlock != hashBestChain)
+ if (pcheckpoint && pblock->hashPrevBlock != (chainActive.Tip() ? chainActive.Tip()->GetBlockHash() : uint256(0)))
{
// Extra checks to prevent "fill up memory by spamming with bogus blocks"
int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
@@ -2423,7 +2520,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
// If we don't already have its previous block, shunt it off to holding area until we get it
if (pblock->hashPrevBlock != 0 && !mapBlockIndex.count(pblock->hashPrevBlock))
{
- printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().c_str());
+ LogPrintf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().c_str());
// Accept orphans as long as there is a node to request its parents from
if (pfrom) {
@@ -2432,7 +2529,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2));
// Ask this guy to fill in what we're missing
- PushGetBlocks(pfrom, pindexBest, GetOrphanRoot(pblock2));
+ PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(pblock2));
}
return true;
}
@@ -2462,7 +2559,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
mapOrphanBlocksByPrev.erase(hashPrev);
}
- printf("ProcessBlock: ACCEPTED\n");
+ LogPrintf("ProcessBlock: ACCEPTED\n");
return true;
}
@@ -2628,7 +2725,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
bool AbortNode(const std::string &strMessage) {
strMiscWarning = strMessage;
- printf("*** %s\n", strMessage.c_str());
+ LogPrintf("*** %s\n", strMessage.c_str());
uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_ERROR);
StartShutdown();
return false;
@@ -2659,12 +2756,12 @@ FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly)
if (!file && !fReadOnly)
file = fopen(path.string().c_str(), "wb+");
if (!file) {
- printf("Unable to open file %s\n", path.string().c_str());
+ LogPrintf("Unable to open file %s\n", path.string().c_str());
return NULL;
}
if (pos.nPos) {
if (fseek(file, pos.nPos, SEEK_SET)) {
- printf("Unable to seek to position %u of %s\n", pos.nPos, path.string().c_str());
+ LogPrintf("Unable to seek to position %u of %s\n", pos.nPos, path.string().c_str());
fclose(file);
return NULL;
}
@@ -2727,9 +2824,9 @@ bool static LoadBlockIndexDB()
// Load block file info
pblocktree->ReadLastBlockFile(nLastBlockFile);
- printf("LoadBlockIndexDB(): last block file = %i\n", nLastBlockFile);
+ LogPrintf("LoadBlockIndexDB(): last block file = %i\n", nLastBlockFile);
if (pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile))
- printf("LoadBlockIndexDB(): last block file info: %s\n", infoLastBlockFile.ToString().c_str());
+ LogPrintf("LoadBlockIndexDB(): last block file info: %s\n", infoLastBlockFile.ToString().c_str());
// Load nBestInvalidWork, OK if it doesn't exist
CBigNum bnBestInvalidWork;
@@ -2743,51 +2840,42 @@ bool static LoadBlockIndexDB()
// Check whether we have a transaction index
pblocktree->ReadFlag("txindex", fTxIndex);
- printf("LoadBlockIndexDB(): transaction index %s\n", fTxIndex ? "enabled" : "disabled");
+ LogPrintf("LoadBlockIndexDB(): transaction index %s\n", fTxIndex ? "enabled" : "disabled");
// Load hashBestChain pointer to end of best chain
- pindexBest = pcoinsTip->GetBestBlock();
- if (pindexBest == NULL)
+ chainActive.SetTip(pcoinsTip->GetBestBlock());
+ if (chainActive.Tip() == NULL)
return true;
- hashBestChain = pindexBest->GetBlockHash();
- nBestHeight = pindexBest->nHeight;
- nBestChainWork = pindexBest->nChainWork;
// register best chain
- CBlockIndex *pindex = pindexBest;
- vBlockIndexByHeight.resize(pindexBest->nHeight + 1);
- while(pindex != NULL) {
- vBlockIndexByHeight[pindex->nHeight] = pindex;
- pindex = pindex->pprev;
- }
- printf("LoadBlockIndexDB(): hashBestChain=%s height=%d date=%s\n",
- hashBestChain.ToString().c_str(), nBestHeight,
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexBest->GetBlockTime()).c_str());
+ LogPrintf("LoadBlockIndexDB(): hashBestChain=%s height=%d date=%s\n",
+ chainActive.Tip()->GetBlockHash().ToString().c_str(), chainActive.Height(),
+ DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()).c_str());
return true;
}
bool VerifyDB(int nCheckLevel, int nCheckDepth)
{
- if (pindexBest == NULL || pindexBest->pprev == NULL)
+ if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL)
return true;
// Verify blocks in the best chain
if (nCheckDepth <= 0)
nCheckDepth = 1000000000; // suffices until the year 19000
- if (nCheckDepth > nBestHeight)
- nCheckDepth = nBestHeight;
+ if (nCheckDepth > chainActive.Height())
+ nCheckDepth = chainActive.Height();
nCheckLevel = std::max(0, std::min(4, nCheckLevel));
- printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
+ LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
CCoinsViewCache coins(*pcoinsTip, true);
- CBlockIndex* pindexState = pindexBest;
+ CBlockIndex* pindexState = chainActive.Tip();
CBlockIndex* pindexFailure = NULL;
int nGoodTransactions = 0;
CValidationState state;
- for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
+ for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)
{
boost::this_thread::interruption_point();
- if (pindex->nHeight < nBestHeight-nCheckDepth)
+ if (pindex->nHeight < chainActive.Height()-nCheckDepth)
break;
CBlock block;
// check level 0: read from disk
@@ -2819,14 +2907,14 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
}
}
if (pindexFailure)
- return error("VerifyDB() : *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", pindexBest->nHeight - pindexFailure->nHeight + 1, nGoodTransactions);
+ return error("VerifyDB() : *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions);
// check level 4: try reconnecting blocks
if (nCheckLevel >= 4) {
CBlockIndex *pindex = pindexState;
- while (pindex != pindexBest) {
+ while (pindex != chainActive.Tip()) {
boost::this_thread::interruption_point();
- pindex = pindex->GetNextInMainChain();
+ pindex = chainActive.Next(pindex);
CBlock block;
if (!ReadBlockFromDisk(block, pindex))
return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
@@ -2835,7 +2923,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
}
}
- printf("No coin database inconsistencies in last %i blocks (%i transactions)\n", pindexBest->nHeight - pindexState->nHeight, nGoodTransactions);
+ LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->nHeight, nGoodTransactions);
return true;
}
@@ -2844,12 +2932,8 @@ void UnloadBlockIndex()
{
mapBlockIndex.clear();
setBlockIndexValid.clear();
- pindexGenesisBlock = NULL;
- nBestHeight = 0;
- nBestChainWork = 0;
+ chainActive.SetTip(NULL);
nBestInvalidWork = 0;
- hashBestChain = 0;
- pindexBest = NULL;
}
bool LoadBlockIndex()
@@ -2863,13 +2947,13 @@ bool LoadBlockIndex()
bool InitBlockIndex() {
// Check whether we're already initialized
- if (pindexGenesisBlock != NULL)
+ if (chainActive.Genesis() != NULL)
return true;
// Use the provided setting for -txindex in the new database
fTxIndex = GetBoolArg("-txindex", false);
pblocktree->WriteFlag("txindex", fTxIndex);
- printf("Initializing databases...\n");
+ LogPrintf("Initializing databases...\n");
// Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
if (!fReindex) {
@@ -2909,7 +2993,7 @@ void PrintBlockTree()
}
vector<pair<int, CBlockIndex*> > vStack;
- vStack.push_back(make_pair(0, pindexGenesisBlock));
+ vStack.push_back(make_pair(0, chainActive.Genesis()));
int nPrevCol = 0;
while (!vStack.empty())
@@ -2922,25 +3006,25 @@ void PrintBlockTree()
if (nCol > nPrevCol)
{
for (int i = 0; i < nCol-1; i++)
- printf("| ");
- printf("|\\\n");
+ LogPrintf("| ");
+ LogPrintf("|\\\n");
}
else if (nCol < nPrevCol)
{
for (int i = 0; i < nCol; i++)
- printf("| ");
- printf("|\n");
+ LogPrintf("| ");
+ LogPrintf("|\n");
}
nPrevCol = nCol;
// print columns
for (int i = 0; i < nCol; i++)
- printf("| ");
+ LogPrintf("| ");
// print item
CBlock block;
ReadBlockFromDisk(block, pindex);
- printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"",
+ LogPrintf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"",
pindex->nHeight,
pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos,
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", block.GetBlockTime()).c_str(),
@@ -2952,7 +3036,7 @@ void PrintBlockTree()
vector<CBlockIndex*>& vNext = mapNext[pindex];
for (unsigned int i = 0; i < vNext.size(); i++)
{
- if (vNext[i]->GetNextInMainChain())
+ if (chainActive.Next(vNext[i]))
{
swap(vNext[0], vNext[i]);
break;
@@ -3025,7 +3109,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
break;
}
} catch (std::exception &e) {
- printf("%s() : Deserialize or I/O error caught during load\n", __PRETTY_FUNCTION__);
+ LogPrintf("%s() : Deserialize or I/O error caught during load\n", __PRETTY_FUNCTION__);
}
}
fclose(fileIn);
@@ -3033,7 +3117,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
AbortNode(_("Error: system error: ") + e.what());
}
if (nLoaded > 0)
- printf("Loaded %i blocks from external file in %"PRI64d"ms\n", nLoaded, GetTimeMillis() - nStart);
+ LogPrintf("Loaded %i blocks from external file in %"PRI64d"ms\n", nLoaded, GetTimeMillis() - nStart);
return nLoaded > 0;
}
@@ -3073,11 +3157,15 @@ string GetWarnings(string strFor)
strStatusBar = strMiscWarning;
}
- // Longer invalid proof-of-work chain
- if (pindexBest && nBestInvalidWork > nBestChainWork + (pindexBest->GetBlockWork() * 6).getuint256())
+ if (fLargeWorkForkFound)
+ {
+ nPriority = 2000;
+ strStatusBar = strRPC = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
+ }
+ else if (fLargeWorkInvalidChainFound)
{
nPriority = 2000;
- strStatusBar = strRPC = _("Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.");
+ strStatusBar = strRPC = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
}
// Alerts
@@ -3146,6 +3234,8 @@ void static ProcessGetData(CNode* pfrom)
vector<CInv> vNotFound;
+ LOCK(cs_main);
+
while (it != pfrom->vRecvGetData.end()) {
// Don't bother if send buffer is too full to respond anyway
if (pfrom->nSendSize >= SendBufferSize())
@@ -3195,7 +3285,7 @@ void static ProcessGetData(CNode* pfrom)
// and we want it right after the last block so they don't
// wait for other stuff first.
vector<CInv> vInv;
- vInv.push_back(CInv(MSG_BLOCK, hashBestChain));
+ vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash()));
pfrom->PushMessage("inv", vInv);
pfrom->hashContinue = 0;
}
@@ -3251,11 +3341,10 @@ void static ProcessGetData(CNode* pfrom)
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
RandAddSeedPerfmon();
- if (fDebug)
- printf("received: %s (%"PRIszu" bytes)\n", strCommand.c_str(), vRecv.size());
+ LogPrint("net", "received: %s (%"PRIszu" bytes)\n", strCommand.c_str(), vRecv.size());
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
- printf("dropmessagestest DROPPING RECV MESSAGE\n");
+ LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n");
return true;
}
@@ -3281,7 +3370,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
// Since February 20, 2012, the protocol is initiated at version 209,
// and earlier versions are no longer supported
- printf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion);
+ LogPrintf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion);
pfrom->fDisconnect = true;
return false;
}
@@ -3308,7 +3397,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1)
{
- printf("connected to self at %s, disconnecting\n", pfrom->addr.ToString().c_str());
+ LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString().c_str());
pfrom->fDisconnect = true;
return true;
}
@@ -3319,7 +3408,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
- AddTimeData(pfrom->addr, nTime);
// Change version
pfrom->PushMessage("verack");
@@ -3359,8 +3447,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fSuccessfullyConnected = true;
- printf("receive version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str());
+ LogPrintf("receive version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str());
+ LOCK(cs_main);
+ AddTimeData(pfrom->addr, nTime);
cPeerBlockCounts.input(pfrom->nStartingHeight);
}
@@ -3464,6 +3554,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
break;
}
}
+
+ LOCK(cs_main);
+
for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
{
const CInv &inv = vInv[nInv];
@@ -3472,21 +3565,20 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->AddInventoryKnown(inv);
bool fAlreadyHave = AlreadyHave(inv);
- if (fDebug)
- printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
+ LogPrint("net", " got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
if (!fAlreadyHave) {
if (!fImporting && !fReindex)
pfrom->AskFor(inv);
} else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
- PushGetBlocks(pfrom, pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
+ PushGetBlocks(pfrom, chainActive.Tip(), GetOrphanRoot(mapOrphanBlocks[inv.hash]));
} else if (nInv == nLastBlock) {
// In case we are on a very long side-chain, it is possible that we already have
// the last block in an inv bundle sent in response to getblocks. Try to detect
// this situation and push another getblocks to continue.
PushGetBlocks(pfrom, mapBlockIndex[inv.hash], uint256(0));
if (fDebug)
- printf("force request: %s\n", inv.ToString().c_str());
+ LogPrintf("force request: %s\n", inv.ToString().c_str());
}
// Track requests for our stuff
@@ -3506,10 +3598,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
if (fDebugNet || (vInv.size() != 1))
- printf("received getdata (%"PRIszu" invsz)\n", vInv.size());
+ LogPrint("net", "received getdata (%"PRIszu" invsz)\n", vInv.size());
if ((fDebugNet && vInv.size() > 0) || (vInv.size() == 1))
- printf("received getdata for: %s\n", vInv[0].ToString().c_str());
+ LogPrint("net", "received getdata for: %s\n", vInv[0].ToString().c_str());
pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end());
ProcessGetData(pfrom);
@@ -3522,19 +3614,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
uint256 hashStop;
vRecv >> locator >> hashStop;
+ LOCK(cs_main);
+
// Find the last block the caller has in the main chain
- CBlockIndex* pindex = locator.GetBlockIndex();
+ CBlockIndex* pindex = chainActive.FindFork(locator);
// Send the rest of the chain
if (pindex)
- pindex = pindex->GetNextInMainChain();
+ pindex = chainActive.Next(pindex);
int nLimit = 500;
- printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str(), nLimit);
- for (; pindex; pindex = pindex->GetNextInMainChain())
+ LogPrint("net", "getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str(), nLimit);
+ for (; pindex; pindex = chainActive.Next(pindex))
{
if (pindex->GetBlockHash() == hashStop)
{
- printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
+ LogPrint("net", " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
break;
}
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
@@ -3542,7 +3636,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
// When this block is requested, we'll send an inv that'll make them
// getblocks the next batch of inventory.
- printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
+ LogPrint("net", " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
pfrom->hashContinue = pindex->GetBlockHash();
break;
}
@@ -3556,6 +3650,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
uint256 hashStop;
vRecv >> locator >> hashStop;
+ LOCK(cs_main);
+
CBlockIndex* pindex = NULL;
if (locator.IsNull())
{
@@ -3568,16 +3664,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else
{
// Find the last block the caller has in the main chain
- pindex = locator.GetBlockIndex();
+ pindex = chainActive.FindFork(locator);
if (pindex)
- pindex = pindex->GetNextInMainChain();
+ pindex = chainActive.Next(pindex);
}
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
vector<CBlock> vHeaders;
int nLimit = 2000;
- printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str());
- for (; pindex; pindex = pindex->GetNextInMainChain())
+ LogPrint("net", "getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str());
+ for (; pindex; pindex = chainActive.Next(pindex))
{
vHeaders.push_back(pindex->GetBlockHeader());
if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
@@ -3591,28 +3687,20 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
vector<uint256> vWorkQueue;
vector<uint256> vEraseQueue;
- CDataStream vMsg(vRecv);
CTransaction tx;
vRecv >> tx;
CInv inv(MSG_TX, tx.GetHash());
pfrom->AddInventoryKnown(inv);
- // Truncate messages to the size of the tx in them
- unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
- unsigned int oldSize = vMsg.size();
- if (nSize < oldSize) {
- vMsg.resize(nSize);
- printf("truncating oversized TX %s (%u -> %u)\n",
- tx.GetHash().ToString().c_str(),
- oldSize, nSize);
- }
+ LOCK(cs_main);
bool fMissingInputs = false;
CValidationState state;
if (mempool.accept(state, tx, true, &fMissingInputs))
{
- RelayTransaction(tx, inv.hash, vMsg);
+ mempool.check(pcoinsTip);
+ RelayTransaction(tx, inv.hash);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
vEraseQueue.push_back(inv.hash);
@@ -3621,32 +3709,33 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
for (unsigned int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hashPrev = vWorkQueue[i];
- for (map<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin();
+ for (set<uint256>::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin();
mi != mapOrphanTransactionsByPrev[hashPrev].end();
++mi)
{
- const CDataStream& vMsg = *((*mi).second);
- CTransaction tx;
- CDataStream(vMsg) >> tx;
- CInv inv(MSG_TX, tx.GetHash());
+ const uint256& orphanHash = *mi;
+ const CTransaction& orphanTx = mapOrphanTransactions[orphanHash];
bool fMissingInputs2 = false;
- // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get anyone relaying LegitTxX banned)
+ // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
+ // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
+ // anyone relaying LegitTxX banned)
CValidationState stateDummy;
- if (mempool.accept(stateDummy, tx, true, &fMissingInputs2))
+ if (mempool.accept(stateDummy, orphanTx, true, &fMissingInputs2))
{
- printf(" accepted orphan tx %s\n", inv.hash.ToString().c_str());
- RelayTransaction(tx, inv.hash, vMsg);
- mapAlreadyAskedFor.erase(inv);
- vWorkQueue.push_back(inv.hash);
- vEraseQueue.push_back(inv.hash);
+ LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString().c_str());
+ RelayTransaction(orphanTx, orphanHash);
+ mapAlreadyAskedFor.erase(CInv(MSG_TX, orphanHash));
+ vWorkQueue.push_back(orphanHash);
+ vEraseQueue.push_back(orphanHash);
}
else if (!fMissingInputs2)
{
// invalid or too-little-fee orphan
- vEraseQueue.push_back(inv.hash);
- printf(" removed orphan tx %s\n", inv.hash.ToString().c_str());
+ vEraseQueue.push_back(orphanHash);
+ LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString().c_str());
}
+ mempool.check(pcoinsTip);
}
}
@@ -3655,16 +3744,17 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
else if (fMissingInputs)
{
- AddOrphanTx(vMsg);
+ AddOrphanTx(tx);
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded
unsigned int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS);
if (nEvicted > 0)
- printf("mapOrphan overflow, removed %u tx\n", nEvicted);
+ LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted);
}
- int nDoS;
+ int nDoS = 0;
if (state.IsInvalid(nDoS))
- pfrom->Misbehaving(nDoS);
+ if (nDoS > 0)
+ pfrom->Misbehaving(nDoS);
}
@@ -3673,18 +3763,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CBlock block;
vRecv >> block;
- printf("received block %s\n", block.GetHash().ToString().c_str());
+ LogPrint("net", "received block %s\n", block.GetHash().ToString().c_str());
// block.print();
CInv inv(MSG_BLOCK, block.GetHash());
pfrom->AddInventoryKnown(inv);
+ LOCK(cs_main);
+
CValidationState state;
if (ProcessBlock(state, pfrom, &block))
mapAlreadyAskedFor.erase(inv);
- int nDoS;
+ int nDoS = 0;
if (state.IsInvalid(nDoS))
- pfrom->Misbehaving(nDoS);
+ if (nDoS > 0)
+ pfrom->Misbehaving(nDoS);
}
@@ -3699,6 +3792,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else if (strCommand == "mempool")
{
+ LOCK(cs_main);
+
std::vector<uint256> vtxid;
LOCK2(mempool.cs, pfrom->cs_filter);
mempool.queryHashes(vtxid);
@@ -3738,6 +3833,63 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
+ else if (strCommand == "pong")
+ {
+ int64 pingUsecEnd = GetTimeMicros();
+ uint64 nonce = 0;
+ size_t nAvail = vRecv.in_avail();
+ bool bPingFinished = false;
+ std::string sProblem;
+
+ if (nAvail >= sizeof(nonce)) {
+ vRecv >> nonce;
+
+ // Only process pong message if there is an outstanding ping (old ping without nonce should never pong)
+ if (pfrom->nPingNonceSent != 0) {
+ if (nonce == pfrom->nPingNonceSent) {
+ // Matching pong received, this ping is no longer outstanding
+ bPingFinished = true;
+ int64 pingUsecTime = pingUsecEnd - pfrom->nPingUsecStart;
+ if (pingUsecTime > 0) {
+ // Successful ping time measurement, replace previous
+ pfrom->nPingUsecTime = pingUsecTime;
+ } else {
+ // This should never happen
+ sProblem = "Timing mishap";
+ }
+ } else {
+ // Nonce mismatches are normal when pings are overlapping
+ sProblem = "Nonce mismatch";
+ if (nonce == 0) {
+ // This is most likely a bug in another implementation somewhere, cancel this ping
+ bPingFinished = true;
+ sProblem = "Nonce zero";
+ }
+ }
+ } else {
+ sProblem = "Unsolicited pong without ping";
+ }
+ } else {
+ // This is most likely a bug in another implementation somewhere, cancel this ping
+ bPingFinished = true;
+ sProblem = "Short payload";
+ }
+
+ if (!(sProblem.empty())) {
+ LogPrint("net", "pong %s %s: %s, %"PRI64x" expected, %"PRI64x" received, %"PRIszu" bytes\n",
+ pfrom->addr.ToString().c_str(),
+ pfrom->strSubVer.c_str(),
+ sProblem.c_str(),
+ pfrom->nPingNonceSent,
+ nonce,
+ nAvail);
+ }
+ if (bPingFinished) {
+ pfrom->nPingNonceSent = 0;
+ }
+ }
+
+
else if (strCommand == "alert")
{
CAlert alert;
@@ -3782,6 +3934,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
LOCK(pfrom->cs_filter);
delete pfrom->pfilter;
pfrom->pfilter = new CBloomFilter(filter);
+ pfrom->pfilter->UpdateEmptyFull();
}
pfrom->fRelayTxes = true;
}
@@ -3811,7 +3964,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
LOCK(pfrom->cs_filter);
delete pfrom->pfilter;
- pfrom->pfilter = NULL;
+ pfrom->pfilter = new CBloomFilter();
pfrom->fRelayTxes = true;
}
@@ -3835,7 +3988,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
bool ProcessMessages(CNode* pfrom)
{
//if (fDebug)
- // printf("ProcessMessages(%zu messages)\n", pfrom->vRecvMsg.size());
+ // LogPrintf("ProcessMessages(%"PRIszu" messages)\n", pfrom->vRecvMsg.size());
//
// Message format
@@ -3860,7 +4013,7 @@ bool ProcessMessages(CNode* pfrom)
CNetMessage& msg = *it;
//if (fDebug)
- // printf("ProcessMessages(message %u msgsz, %zu bytes, complete:%s)\n",
+ // LogPrintf("ProcessMessages(message %u msgsz, %"PRIszu" bytes, complete:%s)\n",
// msg.hdr.nMessageSize, msg.vRecv.size(),
// msg.complete() ? "Y" : "N");
@@ -3873,7 +4026,7 @@ bool ProcessMessages(CNode* pfrom)
// Scan for message start
if (memcmp(msg.hdr.pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0) {
- printf("\n\nPROCESSMESSAGE: INVALID MESSAGESTART\n\n");
+ LogPrintf("\n\nPROCESSMESSAGE: INVALID MESSAGESTART\n\n");
fOk = false;
break;
}
@@ -3882,7 +4035,7 @@ bool ProcessMessages(CNode* pfrom)
CMessageHeader& hdr = msg.hdr;
if (!hdr.IsValid())
{
- printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());
+ LogPrintf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());
continue;
}
string strCommand = hdr.GetCommand();
@@ -3897,7 +4050,7 @@ bool ProcessMessages(CNode* pfrom)
memcpy(&nChecksum, &hash, sizeof(nChecksum));
if (nChecksum != hdr.nChecksum)
{
- printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
+ LogPrintf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
continue;
}
@@ -3906,10 +4059,7 @@ bool ProcessMessages(CNode* pfrom)
bool fRet = false;
try
{
- {
- LOCK(cs_main);
- fRet = ProcessMessage(pfrom, strCommand, vRecv);
- }
+ fRet = ProcessMessage(pfrom, strCommand, vRecv);
boost::this_thread::interruption_point();
}
catch (std::ios_base::failure& e)
@@ -3917,12 +4067,12 @@ bool ProcessMessages(CNode* pfrom)
if (strstr(e.what(), "end of data"))
{
// Allow exceptions from under-length message on vRecv
- printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
+ LogPrintf("ProcessMessages(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
}
else if (strstr(e.what(), "size too large"))
{
// Allow exceptions from over-long size
- printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
+ LogPrintf("ProcessMessages(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
}
else
{
@@ -3939,7 +4089,7 @@ bool ProcessMessages(CNode* pfrom)
}
if (!fRet)
- printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize);
+ LogPrintf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize);
}
// In case the connection got shut down, its receive buffer was wiped
@@ -3952,34 +4102,39 @@ bool ProcessMessages(CNode* pfrom)
bool SendMessages(CNode* pto, bool fSendTrickle)
{
- TRY_LOCK(cs_main, lockMain);
- if (lockMain) {
+ {
// Don't send anything until we get their version message
if (pto->nVersion == 0)
return true;
- // Keep-alive ping. We send a nonce of zero because we don't use it anywhere
- // right now.
+ //
+ // Message: ping
+ //
+ bool pingSend = false;
+ if (pto->fPingQueued) {
+ // RPC ping request by user
+ pingSend = true;
+ }
if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSendMsg.empty()) {
+ // Ping automatically sent as a keepalive
+ pingSend = true;
+ }
+ if (pingSend) {
uint64 nonce = 0;
- if (pto->nVersion > BIP0031_VERSION)
+ while (nonce == 0) {
+ RAND_bytes((unsigned char*)&nonce, sizeof(nonce));
+ }
+ pto->nPingNonceSent = nonce;
+ pto->fPingQueued = false;
+ if (pto->nVersion > BIP0031_VERSION) {
+ // Take timestamp as close as possible before transmitting ping
+ pto->nPingUsecStart = GetTimeMicros();
pto->PushMessage("ping", nonce);
- else
+ } else {
+ // Peer is too old to support ping command with nonce, pong will never arrive, disable timing
+ pto->nPingUsecStart = 0;
pto->PushMessage("ping");
- }
-
- // Start block sync
- if (pto->fStartSync && !fImporting && !fReindex) {
- pto->fStartSync = false;
- PushGetBlocks(pto, pindexBest, uint256(0));
- }
-
- // Resend wallet transactions that haven't gotten in a block yet
- // Except during reindex, importing and IBD, when old wallet
- // transactions become unconfirmed and spams other nodes.
- if (!fReindex && !fImporting && !IsInitialBlockDownload())
- {
- ResendWalletTransactions();
+ }
}
// Address refresh broadcast
@@ -4032,6 +4187,23 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pto->PushMessage("addr", vAddr);
}
+ TRY_LOCK(cs_main, lockMain);
+ if (!lockMain)
+ return true;
+
+ // Start block sync
+ if (pto->fStartSync && !fImporting && !fReindex) {
+ pto->fStartSync = false;
+ PushGetBlocks(pto, chainActive.Tip(), uint256(0));
+ }
+
+ // Resend wallet transactions that haven't gotten in a block yet
+ // Except during reindex, importing and IBD, when old wallet
+ // transactions become unconfirmed and spams other nodes.
+ if (!fReindex && !fImporting && !IsInitialBlockDownload())
+ {
+ ResendWalletTransactions();
+ }
//
// Message: inventory
@@ -4102,7 +4274,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if (!AlreadyHave(inv))
{
if (fDebugNet)
- printf("sending getdata: %s\n", inv.ToString().c_str());
+ LogPrint("net", "sending getdata: %s\n", inv.ToString().c_str());
vGetData.push_back(inv);
if (vGetData.size() >= 1000)
{
@@ -4124,662 +4296,6 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
-
-
-
-
-
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// BitcoinMiner
-//
-
-int static FormatHashBlocks(void* pbuffer, unsigned int len)
-{
- unsigned char* pdata = (unsigned char*)pbuffer;
- unsigned int blocks = 1 + ((len + 8) / 64);
- unsigned char* pend = pdata + 64 * blocks;
- memset(pdata + len, 0, 64 * blocks - len);
- pdata[len] = 0x80;
- unsigned int bits = len * 8;
- pend[-1] = (bits >> 0) & 0xff;
- pend[-2] = (bits >> 8) & 0xff;
- pend[-3] = (bits >> 16) & 0xff;
- pend[-4] = (bits >> 24) & 0xff;
- return blocks;
-}
-
-static const unsigned int pSHA256InitState[8] =
-{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
-
-void SHA256Transform(void* pstate, void* pinput, const void* pinit)
-{
- SHA256_CTX ctx;
- unsigned char data[64];
-
- SHA256_Init(&ctx);
-
- for (int i = 0; i < 16; i++)
- ((uint32_t*)data)[i] = ByteReverse(((uint32_t*)pinput)[i]);
-
- for (int i = 0; i < 8; i++)
- ctx.h[i] = ((uint32_t*)pinit)[i];
-
- SHA256_Update(&ctx, data, sizeof(data));
- for (int i = 0; i < 8; i++)
- ((uint32_t*)pstate)[i] = ctx.h[i];
-}
-
-//
-// ScanHash scans nonces looking for a hash with at least some zero bits.
-// It operates on big endian data. Caller does the byte reversing.
-// All input buffers are 16-byte aligned. nNonce is usually preserved
-// between calls, but periodically or if nNonce is 0xffff0000 or above,
-// the block is rebuilt and nNonce starts over at zero.
-//
-unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone)
-{
- unsigned int& nNonce = *(unsigned int*)(pdata + 12);
- for (;;)
- {
- // Crypto++ SHA256
- // Hash pdata using pmidstate as the starting state into
- // pre-formatted buffer phash1, then hash phash1 into phash
- nNonce++;
- SHA256Transform(phash1, pdata, pmidstate);
- SHA256Transform(phash, phash1, pSHA256InitState);
-
- // Return the nonce if the hash has at least some zero bits,
- // caller will check if it has enough to reach the target
- if (((unsigned short*)phash)[14] == 0)
- return nNonce;
-
- // If nothing found after trying for a while, return -1
- if ((nNonce & 0xffff) == 0)
- {
- nHashesDone = 0xffff+1;
- return (unsigned int) -1;
- }
- if ((nNonce & 0xfff) == 0)
- boost::this_thread::interruption_point();
- }
-}
-
-// Some explaining would be appreciated
-class COrphan
-{
-public:
- CTransaction* ptx;
- set<uint256> setDependsOn;
- double dPriority;
- double dFeePerKb;
-
- COrphan(CTransaction* ptxIn)
- {
- ptx = ptxIn;
- dPriority = dFeePerKb = 0;
- }
-
- void print() const
- {
- printf("COrphan(hash=%s, dPriority=%.1f, dFeePerKb=%.1f)\n",
- ptx->GetHash().ToString().c_str(), dPriority, dFeePerKb);
- BOOST_FOREACH(uint256 hash, setDependsOn)
- printf(" setDependsOn %s\n", hash.ToString().c_str());
- }
-};
-
-
-uint64 nLastBlockTx = 0;
-uint64 nLastBlockSize = 0;
-
-// We want to sort transactions by priority and fee, so:
-typedef boost::tuple<double, double, CTransaction*> TxPriority;
-class TxPriorityCompare
-{
- bool byFee;
-public:
- TxPriorityCompare(bool _byFee) : byFee(_byFee) { }
- bool operator()(const TxPriority& a, const TxPriority& b)
- {
- if (byFee)
- {
- if (a.get<1>() == b.get<1>())
- return a.get<0>() < b.get<0>();
- return a.get<1>() < b.get<1>();
- }
- else
- {
- if (a.get<0>() == b.get<0>())
- return a.get<1>() < b.get<1>();
- return a.get<0>() < b.get<0>();
- }
- }
-};
-
-CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
-{
- // Create new block
- auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
- if(!pblocktemplate.get())
- return NULL;
- CBlock *pblock = &pblocktemplate->block; // pointer for convenience
-
- // Create coinbase tx
- CTransaction txNew;
- txNew.vin.resize(1);
- txNew.vin[0].prevout.SetNull();
- txNew.vout.resize(1);
- CPubKey pubkey;
- if (!reservekey.GetReservedKey(pubkey))
- return NULL;
- txNew.vout[0].scriptPubKey << pubkey << OP_CHECKSIG;
-
- // Add our coinbase tx as first transaction
- pblock->vtx.push_back(txNew);
- pblocktemplate->vTxFees.push_back(-1); // updated at end
- pblocktemplate->vTxSigOps.push_back(-1); // updated at end
-
- // Largest block you're willing to create:
- unsigned int nBlockMaxSize = GetArg("-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));
-
- // How much of the block should be dedicated to high-priority transactions,
- // included regardless of the fees they pay
- unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE);
- 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);
- nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize);
-
- // Collect memory pool transactions into the block
- int64 nFees = 0;
- {
- LOCK2(cs_main, mempool.cs);
- CBlockIndex* pindexPrev = pindexBest;
- CCoinsViewCache view(*pcoinsTip, true);
-
- // Priority order to process transactions
- list<COrphan> vOrphan; // list memory doesn't move
- map<uint256, vector<COrphan*> > mapDependers;
- bool fPrintPriority = GetBoolArg("-printpriority", false);
-
- // This vector will be sorted into a priority queue:
- vector<TxPriority> vecPriority;
- vecPriority.reserve(mempool.mapTx.size());
- for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi)
- {
- CTransaction& tx = (*mi).second;
- if (tx.IsCoinBase() || !IsFinalTx(tx))
- continue;
-
- COrphan* porphan = NULL;
- double dPriority = 0;
- int64 nTotalIn = 0;
- bool fMissingInputs = false;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- // Read prev transaction
- if (!view.HaveCoins(txin.prevout.hash))
- {
- // This should never happen; all transactions in the memory
- // pool should connect to either transactions in the chain
- // or other transactions in the memory pool.
- if (!mempool.mapTx.count(txin.prevout.hash))
- {
- printf("ERROR: mempool transaction missing input\n");
- if (fDebug) assert("mempool transaction missing input" == 0);
- fMissingInputs = true;
- if (porphan)
- vOrphan.pop_back();
- break;
- }
-
- // Has to wait for dependencies
- if (!porphan)
- {
- // Use list for automatic deletion
- vOrphan.push_back(COrphan(&tx));
- porphan = &vOrphan.back();
- }
- mapDependers[txin.prevout.hash].push_back(porphan);
- porphan->setDependsOn.insert(txin.prevout.hash);
- nTotalIn += mempool.mapTx[txin.prevout.hash].vout[txin.prevout.n].nValue;
- continue;
- }
- const CCoins &coins = view.GetCoins(txin.prevout.hash);
-
- int64 nValueIn = coins.vout[txin.prevout.n].nValue;
- nTotalIn += nValueIn;
-
- int nConf = pindexPrev->nHeight - coins.nHeight + 1;
-
- dPriority += (double)nValueIn * nConf;
- }
- if (fMissingInputs) continue;
-
- // Priority is sum(valuein * age) / txsize
- unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
- dPriority /= nTxSize;
-
- // This is a more accurate fee-per-kilobyte than is used by the client code, because the
- // client code rounds up the size to the nearest 1K. That's good, because it gives an
- // incentive to create smaller transactions.
- double dFeePerKb = double(nTotalIn-GetValueOut(tx)) / (double(nTxSize)/1000.0);
-
- if (porphan)
- {
- porphan->dPriority = dPriority;
- porphan->dFeePerKb = dFeePerKb;
- }
- else
- vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &(*mi).second));
- }
-
- // Collect transactions into block
- uint64 nBlockSize = 1000;
- uint64 nBlockTx = 0;
- int nBlockSigOps = 100;
- bool fSortedByFee = (nBlockPrioritySize <= 0);
-
- TxPriorityCompare comparer(fSortedByFee);
- std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
-
- while (!vecPriority.empty())
- {
- // Take highest priority transaction off the priority queue:
- double dPriority = vecPriority.front().get<0>();
- double dFeePerKb = vecPriority.front().get<1>();
- CTransaction& tx = *(vecPriority.front().get<2>());
-
- std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
- vecPriority.pop_back();
-
- // Size limits
- unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
- if (nBlockSize + nTxSize >= nBlockMaxSize)
- continue;
-
- // Legacy limits on sigOps:
- unsigned int nTxSigOps = GetLegacySigOpCount(tx);
- if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
- continue;
-
- // Skip free transactions if we're past the minimum block size:
- if (fSortedByFee && (dFeePerKb < CTransaction::nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
- continue;
-
- // Prioritize by fee once past the priority size or we run out of high-priority
- // transactions:
- if (!fSortedByFee &&
- ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority)))
- {
- fSortedByFee = true;
- comparer = TxPriorityCompare(fSortedByFee);
- std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
- }
-
- if (!view.HaveInputs(tx))
- continue;
-
- int64 nTxFees = view.GetValueIn(tx)-GetValueOut(tx);
-
- nTxSigOps += GetP2SHSigOpCount(tx, view);
- if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
- continue;
-
- CValidationState state;
- if (!CheckInputs(tx, state, view, true, SCRIPT_VERIFY_P2SH))
- continue;
-
- CTxUndo txundo;
- uint256 hash = tx.GetHash();
- UpdateCoins(tx, state, view, txundo, pindexPrev->nHeight+1, hash);
-
- // Added
- pblock->vtx.push_back(tx);
- pblocktemplate->vTxFees.push_back(nTxFees);
- pblocktemplate->vTxSigOps.push_back(nTxSigOps);
- nBlockSize += nTxSize;
- ++nBlockTx;
- nBlockSigOps += nTxSigOps;
- nFees += nTxFees;
-
- if (fPrintPriority)
- {
- printf("priority %.1f feeperkb %.1f txid %s\n",
- dPriority, dFeePerKb, tx.GetHash().ToString().c_str());
- }
-
- // Add transactions that depend on this one to the priority queue
- if (mapDependers.count(hash))
- {
- BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
- {
- if (!porphan->setDependsOn.empty())
- {
- porphan->setDependsOn.erase(hash);
- if (porphan->setDependsOn.empty())
- {
- vecPriority.push_back(TxPriority(porphan->dPriority, porphan->dFeePerKb, porphan->ptx));
- std::push_heap(vecPriority.begin(), vecPriority.end(), comparer);
- }
- }
- }
- }
- }
-
- nLastBlockTx = nBlockTx;
- nLastBlockSize = nBlockSize;
- printf("CreateNewBlock(): total size %"PRI64u"\n", nBlockSize);
-
- pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
- pblocktemplate->vTxFees[0] = -nFees;
-
- // Fill in header
- pblock->hashPrevBlock = pindexPrev->GetBlockHash();
- UpdateTime(*pblock, pindexPrev);
- pblock->nBits = GetNextWorkRequired(pindexPrev, pblock);
- pblock->nNonce = 0;
- pblock->vtx[0].vin[0].scriptSig = CScript() << OP_0 << OP_0;
- pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
-
- CBlockIndex indexDummy(*pblock);
- indexDummy.pprev = pindexPrev;
- indexDummy.nHeight = pindexPrev->nHeight + 1;
- CCoinsViewCache viewNew(*pcoinsTip, true);
- CValidationState state;
- if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true))
- throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
- }
-
- return pblocktemplate.release();
-}
-
-
-void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
-{
- // Update nExtraNonce
- static uint256 hashPrevBlock;
- if (hashPrevBlock != pblock->hashPrevBlock)
- {
- nExtraNonce = 0;
- hashPrevBlock = pblock->hashPrevBlock;
- }
- ++nExtraNonce;
- unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
- pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CBigNum(nExtraNonce)) + COINBASE_FLAGS;
- assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
-
- pblock->hashMerkleRoot = pblock->BuildMerkleTree();
-}
-
-
-void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1)
-{
- //
- // Pre-build hash buffers
- //
- struct
- {
- struct unnamed2
- {
- int nVersion;
- uint256 hashPrevBlock;
- uint256 hashMerkleRoot;
- unsigned int nTime;
- unsigned int nBits;
- unsigned int nNonce;
- }
- block;
- unsigned char pchPadding0[64];
- uint256 hash1;
- unsigned char pchPadding1[64];
- }
- tmp;
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.block.nVersion = pblock->nVersion;
- tmp.block.hashPrevBlock = pblock->hashPrevBlock;
- tmp.block.hashMerkleRoot = pblock->hashMerkleRoot;
- tmp.block.nTime = pblock->nTime;
- tmp.block.nBits = pblock->nBits;
- tmp.block.nNonce = pblock->nNonce;
-
- FormatHashBlocks(&tmp.block, sizeof(tmp.block));
- FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));
-
- // Byte swap all the input buffer
- for (unsigned int i = 0; i < sizeof(tmp)/4; i++)
- ((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]);
-
- // Precalc the first half of the first hash, which stays constant
- SHA256Transform(pmidstate, &tmp.block, pSHA256InitState);
-
- memcpy(pdata, &tmp.block, 128);
- memcpy(phash1, &tmp.hash1, 64);
-}
-
-
-bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
-{
- uint256 hash = pblock->GetHash();
- uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
-
- if (hash > hashTarget)
- return false;
-
- //// debug print
- printf("BitcoinMiner:\n");
- printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
- pblock->print();
- printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str());
-
- // Found a solution
- {
- LOCK(cs_main);
- if (pblock->hashPrevBlock != hashBestChain)
- 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;
- }
-
- // Process this block the same as if we had received it from another node
- CValidationState state;
- if (!ProcessBlock(state, NULL, pblock))
- return error("BitcoinMiner : ProcessBlock, block not accepted");
- }
-
- return true;
-}
-
-void static BitcoinMiner(CWallet *pwallet)
-{
- printf("BitcoinMiner started\n");
- SetThreadPriority(THREAD_PRIORITY_LOWEST);
- RenameThread("bitcoin-miner");
-
- // Each thread has its own key and counter
- CReserveKey reservekey(pwallet);
- unsigned int nExtraNonce = 0;
-
- try { loop {
- if (Params().NetworkID() != CChainParams::REGTEST) {
- // 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())
- MilliSleep(1000);
- }
-
- //
- // Create new block
- //
- unsigned int nTransactionsUpdatedLast = nTransactionsUpdated;
- CBlockIndex* pindexPrev = pindexBest;
-
- auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(reservekey));
- if (!pblocktemplate.get())
- return;
- CBlock *pblock = &pblocktemplate->block;
- IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
-
- printf("Running BitcoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(),
- ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
-
- //
- // Pre-build hash buffers
- //
- char pmidstatebuf[32+16]; char* pmidstate = alignup<16>(pmidstatebuf);
- char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf);
- char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf);
-
- FormatHashBuffers(pblock, pmidstate, pdata, phash1);
-
- unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4);
- unsigned int& nBlockBits = *(unsigned int*)(pdata + 64 + 8);
- unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12);
-
-
- //
- // Search
- //
- int64 nStart = GetTime();
- uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
- uint256 hashbuf[2];
- uint256& hash = *alignup<16>(hashbuf);
- loop
- {
- unsigned int nHashesDone = 0;
- unsigned int nNonceFound;
-
- // Crypto++ SHA256
- nNonceFound = ScanHash_CryptoPP(pmidstate, pdata + 64, phash1,
- (char*)&hash, nHashesDone);
-
- // Check if something found
- if (nNonceFound != (unsigned int) -1)
- {
- for (unsigned int i = 0; i < sizeof(hash)/4; i++)
- ((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]);
-
- if (hash <= hashTarget)
- {
- // Found a solution
- pblock->nNonce = ByteReverse(nNonceFound);
- assert(hash == pblock->GetHash());
-
- SetThreadPriority(THREAD_PRIORITY_NORMAL);
- CheckWork(pblock, *pwalletMain, reservekey);
- SetThreadPriority(THREAD_PRIORITY_LOWEST);
-
- // In regression test mode, stop mining after a block is found. This
- // allows developers to controllably generate a block on demand.
- if (Params().NetworkID() == CChainParams::REGTEST)
- throw boost::thread_interrupted();
-
- break;
- }
- }
-
- // Meter hashes/sec
- static int64 nHashCounter;
- if (nHPSTimerStart == 0)
- {
- nHPSTimerStart = GetTimeMillis();
- nHashCounter = 0;
- }
- else
- nHashCounter += nHashesDone;
- if (GetTimeMillis() - nHPSTimerStart > 4000)
- {
- static CCriticalSection cs;
- {
- LOCK(cs);
- if (GetTimeMillis() - nHPSTimerStart > 4000)
- {
- dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
- nHPSTimerStart = GetTimeMillis();
- nHashCounter = 0;
- static int64 nLogTime;
- if (GetTime() - nLogTime > 30 * 60)
- {
- nLogTime = GetTime();
- printf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0);
- }
- }
- }
- }
-
- // Check for stop or if block needs to be rebuilt
- boost::this_thread::interruption_point();
- if (vNodes.empty() && Params().NetworkID() != CChainParams::REGTEST)
- break;
- if (nBlockNonce >= 0xffff0000)
- break;
- if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)
- break;
- if (pindexPrev != pindexBest)
- break;
-
- // Update nTime every few seconds
- UpdateTime(*pblock, pindexPrev);
- nBlockTime = ByteReverse(pblock->nTime);
- if (TestNet())
- {
- // Changing pblock->nTime can change work required on testnet:
- nBlockBits = ByteReverse(pblock->nBits);
- hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
- }
- }
- } }
- catch (boost::thread_interrupted)
- {
- printf("BitcoinMiner terminated\n");
- throw;
- }
-}
-
-void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
-{
- static boost::thread_group* minerThreads = NULL;
-
- int nThreads = GetArg("-genproclimit", -1);
- if (nThreads < 0) {
- if (Params().NetworkID() == CChainParams::REGTEST)
- nThreads = 1;
- else
- nThreads = boost::thread::hardware_concurrency();
- }
-
- if (minerThreads != NULL)
- {
- minerThreads->interrupt_all();
- delete minerThreads;
- minerThreads = NULL;
- }
-
- if (nThreads == 0 || !fGenerate)
- return;
-
- minerThreads = new boost::thread_group();
- for (int i = 0; i < nThreads; i++)
- minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet));
-}
-
-
-
class CMainCleanup
{
public:
@@ -4798,9 +4314,6 @@ public:
mapOrphanBlocks.clear();
// orphan transactions
- std::map<uint256, CDataStream*>::iterator it3 = mapOrphanTransactions.begin();
- for (; it3 != mapOrphanTransactions.end(); it3++)
- delete (*it3).second;
mapOrphanTransactions.clear();
}
} instance_of_cmaincleanup;