Bypass reloading blocks from disk

pull/196/head
Pieter Wuille 10 years ago
parent 49f954f154
commit 92bb6f2f17

@ -1975,15 +1975,19 @@ static int64_t nTimeFlush = 0;
static int64_t nTimeChainState = 0; static int64_t nTimeChainState = 0;
static int64_t nTimePostConnect = 0; static int64_t nTimePostConnect = 0;
// Connect a new block to chainActive. // Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { // corresponding to pindexNew, to bypass loading it again from disk.
bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) {
assert(pindexNew->pprev == chainActive.Tip()); assert(pindexNew->pprev == chainActive.Tip());
mempool.check(pcoinsTip); mempool.check(pcoinsTip);
// Read block from disk. // Read block from disk.
int64_t nTime1 = GetTimeMicros(); int64_t nTime1 = GetTimeMicros();
CBlock block; CBlock block;
if (!pblock) {
if (!ReadBlockFromDisk(block, pindexNew)) if (!ReadBlockFromDisk(block, pindexNew))
return state.Abort(_("Failed to read block")); return state.Abort(_("Failed to read block"));
pblock = █
}
// Apply the block atomically to the chain state. // Apply the block atomically to the chain state.
int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1; int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1;
int64_t nTime3; int64_t nTime3;
@ -1991,7 +1995,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
{ {
CCoinsViewCache view(*pcoinsTip, true); CCoinsViewCache view(*pcoinsTip, true);
CInv inv(MSG_BLOCK, pindexNew->GetBlockHash()); CInv inv(MSG_BLOCK, pindexNew->GetBlockHash());
if (!ConnectBlock(block, state, pindexNew, view)) { if (!ConnectBlock(*pblock, state, pindexNew, view)) {
if (state.IsInvalid()) if (state.IsInvalid())
InvalidBlockFound(pindexNew, state); InvalidBlockFound(pindexNew, state);
return error("ConnectTip() : ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); return error("ConnectTip() : ConnectBlock %s failed", pindexNew->GetBlockHash().ToString());
@ -2010,7 +2014,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001);
// Remove conflicting transactions from the mempool. // Remove conflicting transactions from the mempool.
list<CTransaction> txConflicted; list<CTransaction> txConflicted;
mempool.removeForBlock(block.vtx, pindexNew->nHeight, txConflicted); mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted);
mempool.check(pcoinsTip); mempool.check(pcoinsTip);
// Update chainActive & related variables. // Update chainActive & related variables.
UpdateTip(pindexNew); UpdateTip(pindexNew);
@ -2020,8 +2024,8 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
SyncWithWallets(tx, NULL); SyncWithWallets(tx, NULL);
} }
// ... and about transactions that got confirmed: // ... and about transactions that got confirmed:
BOOST_FOREACH(const CTransaction &tx, block.vtx) { BOOST_FOREACH(const CTransaction &tx, pblock->vtx) {
SyncWithWallets(tx, &block); SyncWithWallets(tx, pblock);
} }
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001);
@ -2070,7 +2074,8 @@ static CBlockIndex* FindMostWorkChain() {
} }
// Try to make some progress towards making pindexMostWork the active block. // Try to make some progress towards making pindexMostWork the active block.
static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork) { // pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, CBlock *pblock) {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
bool fInvalidFound = false; bool fInvalidFound = false;
const CBlockIndex *pindexOldTip = chainActive.Tip(); const CBlockIndex *pindexOldTip = chainActive.Tip();
@ -2085,14 +2090,15 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
// Build list of new blocks to connect. // Build list of new blocks to connect.
std::vector<CBlockIndex*> vpindexToConnect; std::vector<CBlockIndex*> vpindexToConnect;
vpindexToConnect.reserve(pindexMostWork->nHeight - (pindexFork ? pindexFork->nHeight : -1)); vpindexToConnect.reserve(pindexMostWork->nHeight - (pindexFork ? pindexFork->nHeight : -1));
while (pindexMostWork && pindexMostWork != pindexFork) { CBlockIndex *pindexIter = pindexMostWork;
vpindexToConnect.push_back(pindexMostWork); while (pindexIter && pindexIter != pindexFork) {
pindexMostWork = pindexMostWork->pprev; vpindexToConnect.push_back(pindexIter);
pindexIter = pindexIter->pprev;
} }
// Connect new blocks. // Connect new blocks.
BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {
if (!ConnectTip(state, pindexConnect)) { if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) {
if (state.IsInvalid()) { if (state.IsInvalid()) {
// The block violates a consensus rule. // The block violates a consensus rule.
if (!state.CorruptionPossible()) if (!state.CorruptionPossible())
@ -2133,7 +2139,10 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
return true; return true;
} }
bool ActivateBestChain(CValidationState &state) { // Make the best chain active, in multiple steps. The result is either failure
// or an activated best chain. pblock is either NULL or a pointer to a block
// that is already loaded (to avoid loading it again from disk).
bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
CBlockIndex *pindexNewTip = NULL; CBlockIndex *pindexNewTip = NULL;
CBlockIndex *pindexMostWork = NULL; CBlockIndex *pindexMostWork = NULL;
do { do {
@ -2148,7 +2157,7 @@ bool ActivateBestChain(CValidationState &state) {
if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip())
return true; return true;
if (!ActivateBestChainStep(state, pindexMostWork)) if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL))
return false; return false;
pindexNewTip = chainActive.Tip(); pindexNewTip = chainActive.Tip();
@ -2696,7 +2705,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
} }
if (!ActivateBestChain(state)) if (!ActivateBestChain(state, pblock))
return error("ProcessBlock() : ActivateBestChain failed"); return error("ProcessBlock() : ActivateBestChain failed");
return true; return true;
@ -3136,7 +3145,7 @@ bool InitBlockIndex() {
CBlockIndex *pindex = AddToBlockIndex(block); CBlockIndex *pindex = AddToBlockIndex(block);
if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
return error("LoadBlockIndex() : genesis block not accepted"); return error("LoadBlockIndex() : genesis block not accepted");
if (!ActivateBestChain(state)) if (!ActivateBestChain(state, &block))
return error("LoadBlockIndex() : genesis block cannot be activated"); return error("LoadBlockIndex() : genesis block cannot be activated");
} catch(std::runtime_error &e) { } catch(std::runtime_error &e) {
return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); return error("LoadBlockIndex() : failed to initialize block database: %s", e.what());

@ -160,7 +160,7 @@ std::string GetWarnings(std::string strFor);
/** Retrieve a transaction (from memory pool, or from disk, if possible) */ /** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false); bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false);
/** Find the best known block, and make it the tip of the block chain */ /** Find the best known block, and make it the tip of the block chain */
bool ActivateBestChain(CValidationState &state); bool ActivateBestChain(CValidationState &state, CBlock *pblock = NULL);
int64_t GetBlockValue(int nHeight, int64_t nFees); int64_t GetBlockValue(int nHeight, int64_t nFees);
void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev); void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev);

Loading…
Cancel
Save