diff options
Diffstat (limited to 'src/main.cpp')
| -rw-r--r-- | src/main.cpp | 351 |
1 files changed, 226 insertions, 125 deletions
diff --git a/src/main.cpp b/src/main.cpp index c4d619485..83a640d7f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,53 +74,54 @@ const string strMessageMagic = "Bitcoin Signed Message:\n"; // Internal stuff namespace { -struct CBlockIndexWorkComparator -{ - bool operator()(CBlockIndex *pa, CBlockIndex *pb) { - // First sort by most total work, ... - if (pa->nChainWork > pb->nChainWork) return false; - if (pa->nChainWork < pb->nChainWork) return true; + struct CBlockIndexWorkComparator + { + bool operator()(CBlockIndex *pa, CBlockIndex *pb) { + // First sort by most total work, ... + if (pa->nChainWork > pb->nChainWork) return false; + if (pa->nChainWork < pb->nChainWork) return true; - // ... then by earliest time received, ... - if (pa->nSequenceId < pb->nSequenceId) return false; - if (pa->nSequenceId > pb->nSequenceId) return true; + // ... then by earliest time received, ... + if (pa->nSequenceId < pb->nSequenceId) return false; + if (pa->nSequenceId > pb->nSequenceId) return true; - // Use pointer address as tie breaker (should only happen with blocks - // loaded from disk, as those all have id 0). - if (pa < pb) return false; - if (pa > pb) return true; + // Use pointer address as tie breaker (should only happen with blocks + // loaded from disk, as those all have id 0). + if (pa < pb) return false; + if (pa > pb) return true; - // Identical blocks. - return false; - } -}; - -CBlockIndex *pindexBestInvalid; -set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; // may contain all CBlockIndex*'s that have validness >=BLOCK_VALID_TRANSACTIONS, and must contain those who aren't failed - -CCriticalSection cs_LastBlockFile; -CBlockFileInfo infoLastBlockFile; -int nLastBlockFile = 0; - -// Every received block is assigned a unique and increasing identifier, so we -// know which one to give priority in case of a fork. -CCriticalSection cs_nBlockSequenceId; -// Blocks loaded from disk are assigned id 0, so start the counter at 1. -uint32_t nBlockSequenceId = 1; - -// Sources of received blocks, to be able to send them reject messages or ban -// them, if processing happens afterwards. Protected by cs_main. -map<uint256, NodeId> mapBlockSource; - -// Blocks that are in flight, and that are in the queue to be downloaded. -// Protected by cs_main. -struct QueuedBlock { - uint256 hash; - int64_t nTime; // Time of "getdata" request in microseconds. - int nQueuedBefore; // Number of blocks in flight at the time of request. -}; -map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight; -map<uint256, pair<NodeId, list<uint256>::iterator> > mapBlocksToDownload; + // Identical blocks. + return false; + } + }; + + CBlockIndex *pindexBestInvalid; + // may contain all CBlockIndex*'s that have validness >=BLOCK_VALID_TRANSACTIONS, and must contain those who aren't failed + set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; + + CCriticalSection cs_LastBlockFile; + CBlockFileInfo infoLastBlockFile; + int nLastBlockFile = 0; + + // Every received block is assigned a unique and increasing identifier, so we + // know which one to give priority in case of a fork. + CCriticalSection cs_nBlockSequenceId; + // Blocks loaded from disk are assigned id 0, so start the counter at 1. + uint32_t nBlockSequenceId = 1; + + // Sources of received blocks, to be able to send them reject messages or ban + // them, if processing happens afterwards. Protected by cs_main. + map<uint256, NodeId> mapBlockSource; + + // Blocks that are in flight, and that are in the queue to be downloaded. + // Protected by cs_main. + struct QueuedBlock { + uint256 hash; + int64_t nTime; // Time of "getdata" request in microseconds. + int nQueuedBefore; // Number of blocks in flight at the time of request. + }; + map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight; + map<uint256, pair<NodeId, list<uint256>::iterator> > mapBlocksToDownload; } ////////////////////////////////////////////////////////////////////////////// @@ -474,6 +475,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) bool IsStandardTx(const CTransaction& tx, string& reason) { + AssertLockHeld(cs_main); if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) { reason = "version"; return false; @@ -556,6 +558,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason) bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) { + AssertLockHeld(cs_main); // Time based nLockTime implemented in 0.1.6 if (tx.nLockTime == 0) return true; @@ -667,6 +670,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& inputs) int CMerkleTx::SetMerkleBranch(const CBlock* pblock) { + AssertLockHeld(cs_main); CBlock blockTmp; if (pblock == NULL) { @@ -813,6 +817,7 @@ int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree, bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, bool* pfMissingInputs, bool fRejectInsaneFee) { + AssertLockHeld(cs_main); if (pfMissingInputs) *pfMissingInputs = false; @@ -958,6 +963,7 @@ int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const { if (hashBlock == 0 || nIndex == -1) return 0; + AssertLockHeld(cs_main); // Find the block it claims to be in map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock); @@ -981,6 +987,7 @@ int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const { + AssertLockHeld(cs_main); int nResult = GetDepthInMainChainINTERNAL(pindexRet); if (nResult == 0 && !mempool.exists(GetHash())) return -1; // Not in chain, not in mempool @@ -1026,11 +1033,11 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock fseek(file, postx.nTxOffset, SEEK_CUR); file >> txOut; } catch (std::exception &e) { - return error("%s : Deserialize or I/O error - %s", __PRETTY_FUNCTION__, e.what()); + return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } hashBlock = header.GetHash(); if (txOut.GetHash() != hash) - return error("%s : txid mismatch", __PRETTY_FUNCTION__); + return error("%s : txid mismatch", __func__); return true; } } @@ -1114,7 +1121,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) filein >> block; } catch (std::exception &e) { - return error("%s : Deserialize or I/O error - %s", __PRETTY_FUNCTION__, e.what()); + return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } // Check the header @@ -1304,6 +1311,7 @@ int GetNumBlocksOfPeers() bool IsInitialBlockDownload() { + LOCK(cs_main); if (fImporting || fReindex || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate()) return true; static int64_t nLastUpdate; @@ -1323,6 +1331,7 @@ CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL; void CheckForkWarningConditions() { + AssertLockHeld(cs_main); // 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()) @@ -1368,6 +1377,7 @@ void CheckForkWarningConditions() void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) { + AssertLockHeld(cs_main); // If we are on a fork that is sufficiently large, set a warning flag CBlockIndex* pfork = pindexNewForkTip; CBlockIndex* plonger = chainActive.Tip(); @@ -1718,6 +1728,7 @@ void ThreadScriptCheck() { bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) { + AssertLockHeld(cs_main); // Check it again in case a previous version let a bad block in if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) return false; @@ -1839,8 +1850,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C if (fJustCheck) return true; + // Correct transaction counts. + pindex->nTx = block.vtx.size(); + if (pindex->pprev) + pindex->nChainTx = pindex->pprev->nChainTx + block.vtx.size(); + // Write undo information to disk - if (pindex->GetUndoPos().IsNull() || (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) + if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) { if (pindex->GetUndoPos().IsNull()) { CDiskBlockPos pos; @@ -1854,7 +1870,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C pindex->nStatus |= BLOCK_HAVE_UNDO; } - pindex->nStatus = (pindex->nStatus & ~BLOCK_VALID_MASK) | BLOCK_VALID_SCRIPTS; + pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); CDiskBlockIndex blockindex(pindex); if (!pblocktree->WriteBlockIndex(blockindex)) @@ -2048,10 +2064,11 @@ void static FindMostWorkChain() { CBlockIndex *pindexTest = pindexNew; bool fInvalidAncestor = false; while (pindexTest && !chainActive.Contains(pindexTest)) { - if (pindexTest->nStatus & BLOCK_FAILED_MASK) { + if (!pindexTest->IsValid(BLOCK_VALID_TRANSACTIONS) || !(pindexTest->nStatus & BLOCK_HAVE_DATA)) { // Candidate has an invalid ancestor, remove entire chain from the set. if (pindexBestInvalid == NULL || pindexNew->nChainWork > pindexBestInvalid->nChainWork) - pindexBestInvalid = pindexNew; CBlockIndex *pindexFailed = pindexNew; + pindexBestInvalid = pindexNew; + CBlockIndex *pindexFailed = pindexNew; while (pindexTest != pindexFailed) { pindexFailed->nStatus |= BLOCK_FAILED_CHILD; setBlockIndexValid.erase(pindexFailed); @@ -2078,6 +2095,7 @@ void static FindMostWorkChain() { // Try to activate to the most-work chain (thereby connecting it). bool ActivateBestChain(CValidationState &state) { + LOCK(cs_main); CBlockIndex *pindexOldTip = chainActive.Tip(); bool fComplete = false; while (!fComplete) { @@ -2124,12 +2142,14 @@ bool ActivateBestChain(CValidationState &state) { return true; } -bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos) + +CBlockIndex* AddToBlockIndex(CBlockHeader& block) { // Check for duplicate uint256 hash = block.GetHash(); - if (mapBlockIndex.count(hash)) - return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString()), 0, "duplicate"); + std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hash); + if (it != mapBlockIndex.end()) + return it->second; // Construct new block index object CBlockIndex* pindexNew = new CBlockIndex(block); @@ -2146,14 +2166,38 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos pindexNew->pprev = (*miPrev).second; pindexNew->nHeight = pindexNew->pprev->nHeight + 1; } - pindexNew->nTx = block.vtx.size(); pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256(); - pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx; + pindexNew->RaiseValidity(BLOCK_VALID_TREE); + + return pindexNew; +} + + +// Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). +bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos) +{ + pindexNew->nTx = block.vtx.size(); + if (pindexNew->pprev) { + // Not the genesis block. + if (pindexNew->pprev->nChainTx) { + // This parent's block's total number transactions is known, so compute outs. + pindexNew->nChainTx = pindexNew->pprev->nChainTx + pindexNew->nTx; + } else { + // The total number of transactions isn't known yet. + // We will compute it when the block is connected. + pindexNew->nChainTx = 0; + } + } else { + // Genesis block. + pindexNew->nChainTx = pindexNew->nTx; + } pindexNew->nFile = pos.nFile; pindexNew->nDataPos = pos.nPos; pindexNew->nUndoPos = 0; - pindexNew->nStatus = BLOCK_VALID_TRANSACTIONS | BLOCK_HAVE_DATA; - setBlockIndexValid.insert(pindexNew); + pindexNew->nStatus |= BLOCK_HAVE_DATA; + + if (pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS)) + setBlockIndexValid.insert(pindexNew); if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew))) return state.Abort(_("Failed to write block index")); @@ -2162,6 +2206,7 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos if (!ActivateBestChain(state)) return false; + LOCK(cs_main); if (pindexNew == chainActive.Tip()) { // Clear fork warning if its no longer applicable @@ -2276,26 +2321,55 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne } +bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW) +{ + // Check proof of work matches claimed amount + if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits)) + return state.DoS(50, error("CheckBlockHeader() : proof of work failed"), + REJECT_INVALID, "high-hash"); + + // Check timestamp + if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) + return state.Invalid(error("CheckBlockHeader() : block timestamp too far in the future"), + REJECT_INVALID, "time-too-new"); + + CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); + if (pcheckpoint && block.hashPrevBlock != (chainActive.Tip() ? chainActive.Tip()->GetBlockHash() : uint256(0))) + { + // Extra checks to prevent "fill up memory by spamming with bogus blocks" + int64_t deltaTime = block.GetBlockTime() - pcheckpoint->nTime; + if (deltaTime < 0) + { + return state.DoS(100, error("CheckBlockHeader() : block with timestamp before last checkpoint"), + REJECT_CHECKPOINT, "time-too-old"); + } + CBigNum bnNewBlock; + bnNewBlock.SetCompact(block.nBits); + CBigNum bnRequired; + bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); + if (bnNewBlock > bnRequired) + { + return state.DoS(100, error("CheckBlockHeader() : block with too little proof-of-work"), + REJECT_INVALID, "bad-diffbits"); + } + } + + return true; +} + bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot) { // These are checks that are independent of context // that can be verified before saving an orphan block. + if (!CheckBlockHeader(block, state, fCheckPOW)) + return false; + // Size limits if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return state.DoS(100, error("CheckBlock() : size limits failed"), REJECT_INVALID, "bad-blk-length"); - // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits)) - return state.DoS(50, error("CheckBlock() : proof of work failed"), - REJECT_INVALID, "high-hash"); - - // Check timestamp - if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) - return state.Invalid(error("CheckBlock() : block timestamp too far in the future"), - REJECT_INVALID, "time-too-new"); - // First transaction must be coinbase, the rest must not be if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) return state.DoS(100, error("CheckBlock() : first tx is not coinbase"), @@ -2342,12 +2416,18 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo return true; } -bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) +bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex) { + AssertLockHeld(cs_main); // Check for duplicate uint256 hash = block.GetHash(); - if (mapBlockIndex.count(hash)) - return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex"), 0, "duplicate"); + std::map<uint256, CBlockIndex*>::iterator miSelf = mapBlockIndex.find(hash); + CBlockIndex *pindex = NULL; + if (miSelf != mapBlockIndex.end()) { + pindex = miSelf->second; + if (pindex->nStatus & BLOCK_FAILED_MASK) + return state.Invalid(error("AcceptBlock() : block is marked invalid"), 0, "duplicate"); + } // Get prev block index CBlockIndex* pindexPrev = NULL; @@ -2369,12 +2449,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) return state.Invalid(error("AcceptBlock() : block's timestamp is too early"), REJECT_INVALID, "time-too-old"); - // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, block.vtx) - if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) - return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"), - REJECT_INVALID, "bad-txns-nonfinal"); - // Check that the block chain matches the known block chain up to a checkpoint if (!Checkpoints::CheckBlock(nHeight, hash)) return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight), @@ -2395,18 +2469,57 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) REJECT_OBSOLETE, "bad-version"); } } - // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height - if (block.nVersion >= 2) + } + + if (pindex == NULL) + pindex = AddToBlockIndex(block); + + if (ppindex) + *ppindex = pindex; + + return true; +} + +bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp) +{ + AssertLockHeld(cs_main); + + CBlockIndex *&pindex = *ppindex; + + if (!AcceptBlockHeader(block, state, &pindex)) + return false; + + if (!CheckBlock(block, state)) { + if (state.Invalid() && !state.CorruptionPossible()) { + pindex->nStatus |= BLOCK_FAILED_VALID; + } + return false; + } + + int nHeight = pindex->nHeight; + uint256 hash = pindex->GetBlockHash(); + + // Check that all transactions are finalized + BOOST_FOREACH(const CTransaction& tx, block.vtx) + if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) { + pindex->nStatus |= BLOCK_FAILED_VALID; + return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"), + REJECT_INVALID, "bad-txns-nonfinal"); + } + + // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height + if (block.nVersion >= 2) + { + // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): + if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindex->pprev, 750, 1000)) || + (TestNet() && CBlockIndex::IsSuperMajority(2, pindex->pprev, 51, 100))) { - // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): - if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) || - (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100))) - { - CScript expect = CScript() << nHeight; - 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"), - REJECT_INVALID, "bad-cb-height"); + CScript expect = CScript() << nHeight; + if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || + !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { + pindex->nStatus |= BLOCK_FAILED_VALID; + return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"), + REJECT_INVALID, "bad-cb-height"); } } } @@ -2422,8 +2535,8 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) if (dbp == NULL) if (!WriteBlockToDisk(block, blockPos)) return state.Abort(_("Failed to write block")); - if (!AddToBlockIndex(block, state, blockPos)) - return error("AcceptBlock() : AddToBlockIndex failed"); + if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) + return error("AcceptBlock() : ReceivedBlockTransactions failed"); } catch(std::runtime_error &e) { return state.Abort(_("System error: ") + e.what()); } @@ -2455,6 +2568,7 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns int64_t CBlockIndex::GetMedianTime() const { + AssertLockHeld(cs_main); const CBlockIndex* pindex = this; for (int i = 0; i < nMedianTimeSpan/2; i++) { @@ -2467,6 +2581,7 @@ int64_t CBlockIndex::GetMedianTime() const void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd) { + AssertLockHeld(cs_main); // Filter out duplicate requests if (pindexBegin == pnode->pindexLastGetBlocksBegin && hashEnd == pnode->hashLastGetBlocksEnd) return; @@ -2491,30 +2606,9 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl if (!CheckBlock(*pblock, state)) return error("ProcessBlock() : CheckBlock FAILED"); - CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); - if (pcheckpoint && pblock->hashPrevBlock != (chainActive.Tip() ? chainActive.Tip()->GetBlockHash() : uint256(0))) - { - // Extra checks to prevent "fill up memory by spamming with bogus blocks" - int64_t deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime; - if (deltaTime < 0) - { - return state.DoS(100, error("ProcessBlock() : block with timestamp before last checkpoint"), - REJECT_CHECKPOINT, "time-too-old"); - } - CBigNum bnNewBlock; - bnNewBlock.SetCompact(pblock->nBits); - CBigNum bnRequired; - bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); - if (bnNewBlock > bnRequired) - { - return state.DoS(100, error("ProcessBlock() : block with too little proof-of-work"), - REJECT_INVALID, "bad-diffbits"); - } - } - - - // 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)) + // If we don't already have its previous block (with full data), shunt it off to holding area until we get it + std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(pblock->hashPrevBlock); + if (pblock->hashPrevBlock != 0 && (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA))) { LogPrintf("ProcessBlock: ORPHAN BLOCK %lu, prev=%s\n", (unsigned long)mapOrphanBlocks.size(), pblock->hashPrevBlock.ToString()); @@ -2539,7 +2633,9 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl } // Store to disk - if (!AcceptBlock(*pblock, state, dbp)) + CBlockIndex *pindex = NULL; + bool ret = AcceptBlock(*pblock, state, &pindex, dbp); + if (!ret) return error("ProcessBlock() : AcceptBlock FAILED"); // Recursively process any orphan blocks that depended on this one @@ -2560,7 +2656,8 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl block.BuildMerkleTree(); // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned) CValidationState stateDummy; - if (AcceptBlock(block, stateDummy)) + CBlockIndex *pindexChild = NULL; + if (AcceptBlock(block, stateDummy, &pindexChild)) vWorkQueue.push_back(mi->second->hashBlock); mapOrphanBlocks.erase(mi->second->hashBlock); delete mi->second; @@ -2823,7 +2920,7 @@ bool static LoadBlockIndexDB() CBlockIndex* pindex = item.second; pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + pindex->GetBlockWork().getuint256(); pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx; - if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS && !(pindex->nStatus & BLOCK_FAILED_MASK)) + if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) setBlockIndexValid.insert(pindex); if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork)) pindexBestInvalid = pindex; @@ -2859,6 +2956,7 @@ bool static LoadBlockIndexDB() bool VerifyDB(int nCheckLevel, int nCheckDepth) { + LOCK(cs_main); if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL) return true; @@ -2948,6 +3046,7 @@ bool LoadBlockIndex() bool InitBlockIndex() { + LOCK(cs_main); // Check whether we're already initialized if (chainActive.Genesis() != NULL) return true; @@ -2969,7 +3068,8 @@ bool InitBlockIndex() { return error("LoadBlockIndex() : FindBlockPos failed"); if (!WriteBlockToDisk(block, blockPos)) return error("LoadBlockIndex() : writing genesis block to disk failed"); - if (!AddToBlockIndex(block, state, blockPos)) + CBlockIndex *pindex = AddToBlockIndex(block); + if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("LoadBlockIndex() : genesis block not accepted"); } catch(std::runtime_error &e) { return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); @@ -2983,6 +3083,7 @@ bool InitBlockIndex() { void PrintBlockTree() { + AssertLockHeld(cs_main); // pre-compute tree structure map<CBlockIndex*, vector<CBlockIndex*> > mapNext; for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi) @@ -3075,11 +3176,11 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) unsigned int nSize = 0; try { // locate a header - unsigned char buf[4]; + unsigned char buf[MESSAGE_START_SIZE]; blkdat.FindByte(Params().MessageStart()[0]); nRewind = blkdat.GetPos()+1; blkdat >> FLATDATA(buf); - if (memcmp(buf, Params().MessageStart(), 4)) + if (memcmp(buf, Params().MessageStart(), MESSAGE_START_SIZE)) continue; // read size blkdat >> nSize; @@ -3109,7 +3210,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) break; } } catch (std::exception &e) { - LogPrintf("%s : Deserialize or I/O error - %s", __PRETTY_FUNCTION__, e.what()); + LogPrintf("%s : Deserialize or I/O error - %s", __func__, e.what()); } } fclose(fileIn); @@ -4186,6 +4287,10 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } } + TRY_LOCK(cs_main, lockMain); // Acquire cs_main for IsInitialBlockDownload() and CNodeState() + if (!lockMain) + return true; + // Address refresh broadcast static int64_t nLastRebroadcast; if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) @@ -4236,10 +4341,6 @@ bool SendMessages(CNode* pto, bool fSendTrickle) pto->PushMessage("addr", vAddr); } - TRY_LOCK(cs_main, lockMain); - if (!lockMain) - return true; - CNodeState &state = *State(pto->GetId()); if (state.fShouldBan) { if (pto->addr.IsLocal()) |