aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp114
1 files changed, 89 insertions, 25 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 42f70c023c..b077eb9d6e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -37,6 +37,7 @@ CBigNum bnBestChainWork = 0;
CBigNum bnBestInvalidWork = 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;
bool fImporting = false;
@@ -1156,6 +1157,62 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
printf("InvalidChainFound: Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n");
}
+void static InvalidBlockFound(CBlockIndex *pindex) {
+ pindex->nStatus |= BLOCK_FAILED_VALID;
+ CChainDB().WriteBlockIndex(CDiskBlockIndex(pindex));
+ setBlockIndexValid.erase(pindex);
+ InvalidChainFound(pindex);
+ if (pindex->pnext)
+ ConnectBestBlock(); // reorganise away from the failed block
+}
+
+bool ConnectBestBlock() {
+ do {
+ CBlockIndex *pindexNewBest;
+
+ {
+ std::set<CBlockIndex*,CBlockIndexWorkComparator>::reverse_iterator it = setBlockIndexValid.rbegin();
+ if (it == setBlockIndexValid.rend())
+ return true;
+ pindexNewBest = *it;
+ }
+
+ if (pindexNewBest == pindexBest)
+ return true; // nothing to do
+
+ // check ancestry
+ CBlockIndex *pindexTest = pindexNewBest;
+ std::vector<CBlockIndex*> vAttach;
+ do {
+ if (pindexTest->nStatus & BLOCK_FAILED_MASK) {
+ // mark descendants failed
+ CChainDB chaindb;
+ CBlockIndex *pindexFailed = pindexNewBest;
+ while (pindexTest != pindexFailed) {
+ pindexFailed->nStatus |= BLOCK_FAILED_CHILD;
+ setBlockIndexValid.erase(pindexFailed);
+ chaindb.WriteBlockIndex(CDiskBlockIndex(pindexFailed));
+ pindexFailed = pindexFailed->pprev;
+ }
+ InvalidChainFound(pindexNewBest);
+ break;
+ }
+
+ if (pindexBest == NULL || pindexTest->bnChainWork > pindexBest->bnChainWork)
+ vAttach.push_back(pindexTest);
+
+ if (pindexTest->pprev == NULL || pindexTest->pnext != NULL) {
+ reverse(vAttach.begin(), vAttach.end());
+ BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach)
+ if (!SetBestChain(pindexSwitch))
+ return false;
+ return true;
+ }
+ pindexTest = pindexTest->pprev;
+ } while(true);
+ } while(true);
+}
+
void CBlock::UpdateTime(const CBlockIndex* pindexPrev)
{
nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
@@ -1522,17 +1579,24 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
return true;
// Write undo information to disk
- if (pindex->GetUndoPos().IsNull())
+ if (pindex->GetUndoPos().IsNull() || (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS)
{
CChainDB chaindb;
- CDiskBlockPos pos;
- if (!FindUndoPos(chaindb, pindex->pos.nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 8))
- return error("ConnectBlock() : FindUndoPos failed");
- if (!blockundo.WriteToDisk(pos))
- return error("ConnectBlock() : CBlockUndo::WriteToDisk failed");
-
- // update nUndoPos in block index
- pindex->nUndoPos = pos.nPos + 1;
+
+ if (pindex->GetUndoPos().IsNull()) {
+ CDiskBlockPos pos;
+ if (!FindUndoPos(chaindb, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 8))
+ return error("ConnectBlock() : FindUndoPos failed");
+ if (!blockundo.WriteToDisk(pos))
+ return error("ConnectBlock() : CBlockUndo::WriteToDisk failed");
+
+ // update nUndoPos in block index
+ pindex->nUndoPos = pos.nPos;
+ pindex->nStatus |= BLOCK_HAVE_UNDO;
+ }
+
+ pindex->nStatus = (pindex->nStatus & ~BLOCK_VALID_MASK) | BLOCK_VALID_SCRIPTS;
+
CDiskBlockIndex blockindex(pindex);
if (!chaindb.WriteBlockIndex(blockindex))
return error("ConnectBlock() : WriteBlockIndex failed");
@@ -1549,7 +1613,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
return true;
}
-bool CBlock::SetBestChain(CBlockIndex* pindexNew)
+bool SetBestChain(CBlockIndex* pindexNew)
{
CCoinsViewCache &view = *pcoinsTip;
@@ -1620,24 +1684,19 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
vector<CTransaction> vDelete;
BOOST_FOREACH(CBlockIndex *pindex, vConnect) {
CBlock block;
- CBlock *pblock;
- if (pindex == pindexNew) // connecting *this block
- pblock = this;
- else { // other block; read it from disk
- if (!block.ReadFromDisk(pindex))
- return error("SetBestBlock() : ReadFromDisk for connect failed");
- pblock = &block;
- }
+ if (!block.ReadFromDisk(pindex))
+ return error("SetBestBlock() : ReadFromDisk for connect failed");
CCoinsViewCache viewTemp(view, true);
- if (!pblock->ConnectBlock(pindex, viewTemp)) {
+ if (!block.ConnectBlock(pindex, viewTemp)) {
InvalidChainFound(pindexNew);
+ InvalidBlockFound(pindex);
return error("SetBestBlock() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
}
if (!viewTemp.Flush())
return error("SetBestBlock() : Cache flush failed after connect");
// Queue memory transactions to delete
- BOOST_FOREACH(const CTransaction& tx, pblock->vtx)
+ BOOST_FOREACH(const CTransaction& tx, block.vtx)
vDelete.push_back(tx);
}
@@ -1683,8 +1742,8 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
bnBestChainWork = pindexNew->bnChainWork;
nTimeBestReceived = GetTime();
nTransactionsUpdated++;
- printf("SetBestChain: new best=%s height=%d work=%s date=%s\n",
- hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(),
+ printf("SetBestChain: new best=%s height=%d work=%s tx=%lu date=%s\n",
+ hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), (unsigned long)pindexNew->nChainTx,
DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
// Check the version of the last 100 blocks to see if we need to upgrade:
@@ -1736,9 +1795,14 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
pindexNew->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
}
+ pindexNew->nTx = vtx.size();
pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();
- pindexNew->pos = pos;
+ pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx;
+ pindexNew->nFile = pos.nFile;
+ pindexNew->nDataPos = pos.nPos;
pindexNew->nUndoPos = 0;
+ pindexNew->nStatus = BLOCK_VALID_TRANSACTIONS | BLOCK_HAVE_DATA;
+ setBlockIndexValid.insert(pindexNew);
CChainDB chaindb;
if (!chaindb.TxnBegin())
@@ -1747,8 +1811,8 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
if (!chaindb.TxnCommit())
return false;
- // New best
- if (!SetBestChain(pindexNew))
+ // New best?
+ if (!ConnectBestBlock())
return false;
if (pindexNew == pindexBest)