Skip to content

Commit

Permalink
Make SetBestChain() atomic
Browse files Browse the repository at this point in the history
In case a reorganisation fails, the internal state could become
inconsistent (memory only). Previously, a cache per block connect
or disconnect action was used, so blocks could not be applied in
a partial way. Extend this to a cache for the entire reorganisation,
making it atomic entirely. This also simplifies the code a bit.
  • Loading branch information
sipa authored and mikegogulski committed Dec 26, 2012
1 parent 2334194 commit 0a94022
Showing 1 changed file with 11 additions and 11 deletions.
22 changes: 11 additions & 11 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1671,7 +1671,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust

bool SetBestChain(CBlockIndex* pindexNew)
{
CCoinsViewCache &view = *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);

// special case for attaching the genesis block
// note that no ConnectBlock is called, so its coinbase output is non-spendable
Expand Down Expand Up @@ -1724,11 +1726,8 @@ bool SetBestChain(CBlockIndex* pindexNew)
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("SetBestBlock() : ReadFromDisk for disconnect failed");
CCoinsViewCache viewTemp(view, true);
if (!block.DisconnectBlock(pindex, viewTemp))
if (!block.DisconnectBlock(pindex, view))
return error("SetBestBlock() : DisconnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str());
if (!viewTemp.Flush())
return error("SetBestBlock() : Cache flush failed after disconnect");

// Queue memory transactions to resurrect.
// We only do this for blocks after the last checkpoint (reorganisation before that
Expand All @@ -1744,26 +1743,27 @@ bool SetBestChain(CBlockIndex* pindexNew)
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("SetBestBlock() : ReadFromDisk for connect failed");
CCoinsViewCache viewTemp(view, true);
if (!block.ConnectBlock(pindex, viewTemp)) {
if (!block.ConnectBlock(pindex, view)) {
InvalidChainFound(pindexNew);
InvalidBlockFound(pindex);
return error("SetBestBlock() : ConnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str());
}
if (!viewTemp.Flush())
return error("SetBestBlock() : Cache flush failed after connect");

// Queue memory transactions to delete
BOOST_FOREACH(const CTransaction& tx, block.vtx)
vDelete.push_back(tx);
}

// Flush changes to global coin state
if (!view.Flush())
return error("SetBestBlock() : unable to modify coin state");

// Make sure it's successfully written to disk before changing memory structure
bool fIsInitialDownload = IsInitialBlockDownload();
if (!fIsInitialDownload || view.GetCacheSize() > nCoinCacheSize) {
if (!fIsInitialDownload || pcoinsTip->GetCacheSize() > nCoinCacheSize) {
FlushBlockFile();
pblocktree->Sync();
if (!view.Flush())
if (!pcoinsTip->Flush())
return false;
}

Expand Down

0 comments on commit 0a94022

Please sign in to comment.