mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-18 22:35:39 +01:00
Prepare database format for multi-stage block processing
This commit adds a status field and a transaction counter to the block indexes.
This commit is contained in:
112
src/main.cpp
112
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 = █
|
||||
}
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user