aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp351
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())