From 84674082b0c4cfcdd54fb97a29bc841aa7f691c2 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 5 Nov 2013 02:27:39 +0100 Subject: Make CCoinsView use block hashes instead of indices --- src/main.cpp | 57 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 26 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 2a133b3ea..5b330536f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -236,9 +236,9 @@ CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const { bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) { return false; } bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; } bool CCoinsView::HaveCoins(const uint256 &txid) { return false; } -CBlockIndex *CCoinsView::GetBestBlock() { return NULL; } -bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; } -bool CCoinsView::BatchWrite(const std::map &mapCoins, CBlockIndex *pindex) { return false; } +uint256 CCoinsView::GetBestBlock() { return uint256(0); } +bool CCoinsView::SetBestBlock(const uint256 &hashBlock) { return false; } +bool CCoinsView::BatchWrite(const std::map &mapCoins, const uint256 &hashBlock) { return false; } bool CCoinsView::GetStats(CCoinsStats &stats) { return false; } @@ -246,13 +246,13 @@ CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { } bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) { return base->GetCoins(txid, coins); } bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); } bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(txid); } -CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); } -bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); } +uint256 CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); } +bool CCoinsViewBacked::SetBestBlock(const uint256 &hashBlock) { return base->SetBestBlock(hashBlock); } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } -bool CCoinsViewBacked::BatchWrite(const std::map &mapCoins, CBlockIndex *pindex) { return base->BatchWrite(mapCoins, pindex); } +bool CCoinsViewBacked::BatchWrite(const std::map &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stats); } -CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { } +CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), hashBlock(0) { } bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) { if (cacheCoins.count(txid)) { @@ -293,26 +293,26 @@ bool CCoinsViewCache::HaveCoins(const uint256 &txid) { return FetchCoins(txid) != cacheCoins.end(); } -CBlockIndex *CCoinsViewCache::GetBestBlock() { - if (pindexTip == NULL) - pindexTip = base->GetBestBlock(); - return pindexTip; +uint256 CCoinsViewCache::GetBestBlock() { + if (hashBlock == uint256(0)) + hashBlock = base->GetBestBlock(); + return hashBlock; } -bool CCoinsViewCache::SetBestBlock(CBlockIndex *pindex) { - pindexTip = pindex; +bool CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { + hashBlock = hashBlockIn; return true; } -bool CCoinsViewCache::BatchWrite(const std::map &mapCoins, CBlockIndex *pindex) { +bool CCoinsViewCache::BatchWrite(const std::map &mapCoins, const uint256 &hashBlockIn) { for (std::map::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++) cacheCoins[it->first] = it->second; - pindexTip = pindex; + hashBlock = hashBlockIn; return true; } bool CCoinsViewCache::Flush() { - bool fOk = base->BatchWrite(cacheCoins, pindexTip); + bool fOk = base->BatchWrite(cacheCoins, hashBlock); if (fOk) cacheCoins.clear(); return fOk; @@ -1498,7 +1498,8 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach // While checking, GetBestBlock() refers to the parent block. // This is also true for mempool checks. - int nSpendHeight = inputs.GetBestBlock()->nHeight + 1; + CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; + int nSpendHeight = pindexPrev->nHeight + 1; int64_t nValueIn = 0; int64_t nFees = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) @@ -1568,7 +1569,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean) { - assert(pindex == view.GetBestBlock()); + assert(pindex->GetBlockHash() == view.GetBestBlock()); if (pfClean) *pfClean = false; @@ -1644,7 +1645,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex } // move best block pointer to prevout block - view.SetBestBlock(pindex->pprev); + view.SetBestBlock(pindex->pprev->GetBlockHash()); if (pfClean) { *pfClean = fClean; @@ -1693,12 +1694,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C return false; // verify that the view's current state corresponds to the previous block - assert(pindex->pprev == view.GetBestBlock()); + uint256 hashPrevBlock = pindex->pprev == NULL ? uint256(0) : pindex->pprev->GetBlockHash(); + assert(hashPrevBlock == view.GetBestBlock()); // Special case for the genesis block, skipping connection of its transactions // (its coinbase is unspendable) if (block.GetHash() == Params().HashGenesisBlock()) { - view.SetBestBlock(pindex); + view.SetBestBlock(pindex->GetBlockHash()); return true; } @@ -1828,7 +1830,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C return state.Abort(_("Failed to write transaction index")); // add this block to the view's block chain - assert(view.SetBestBlock(pindex)); + assert(view.SetBestBlock(pindex->GetBlockHash())); // Watch for transactions paying to me for (unsigned int i = 0; i < block.vtx.size(); i++) @@ -1846,7 +1848,9 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) CCoinsViewCache view(*pcoinsTip, true); // Find the fork (typically, there is none) - CBlockIndex* pfork = view.GetBestBlock(); + std::map::iterator it = mapBlockIndex.find(view.GetBestBlock()); + CBlockIndex* ptip = (it != mapBlockIndex.end()) ? it->second : NULL; + CBlockIndex* pfork = ptip; CBlockIndex* plonger = pindexNew; while (pfork && pfork != plonger) { @@ -1862,7 +1866,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) // List of what to disconnect (typically nothing) vector vDisconnect; - for (CBlockIndex* pindex = view.GetBestBlock(); pindex != pfork; pindex = pindex->pprev) + for (CBlockIndex* pindex = ptip; pindex != pfork; pindex = pindex->pprev) vDisconnect.push_back(pindex); // List of what to connect (typically only pindexNew) @@ -2687,9 +2691,10 @@ bool static LoadBlockIndexDB() LogPrintf("LoadBlockIndexDB(): transaction index %s\n", fTxIndex ? "enabled" : "disabled"); // Load pointer to end of best chain - chainActive.SetTip(pcoinsTip->GetBestBlock()); - if (chainActive.Tip() == NULL) + std::map::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); + if (it == mapBlockIndex.end()) return true; + chainActive.SetTip(it->second); LogPrintf("LoadBlockIndexDB(): hashBestChain=%s height=%d date=%s\n", chainActive.Tip()->GetBlockHash().ToString().c_str(), chainActive.Height(), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()).c_str()); -- cgit v1.2.3 From a0fa20a12b69717636050dd8742713b1d82ae524 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 5 Nov 2013 02:47:07 +0100 Subject: Move CCoins-related logic to coins.{cpp.h} --- src/main.cpp | 170 ++--------------------------------------------------------- 1 file changed, 4 insertions(+), 166 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 5b330536f..3c4b108c8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -228,128 +228,6 @@ CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const { return Genesis(); } -////////////////////////////////////////////////////////////////////////////// -// -// CCoinsView implementations -// - -bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) { return false; } -bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; } -bool CCoinsView::HaveCoins(const uint256 &txid) { return false; } -uint256 CCoinsView::GetBestBlock() { return uint256(0); } -bool CCoinsView::SetBestBlock(const uint256 &hashBlock) { return false; } -bool CCoinsView::BatchWrite(const std::map &mapCoins, const uint256 &hashBlock) { return false; } -bool CCoinsView::GetStats(CCoinsStats &stats) { return false; } - - -CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { } -bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) { return base->GetCoins(txid, coins); } -bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); } -bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(txid); } -uint256 CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); } -bool CCoinsViewBacked::SetBestBlock(const uint256 &hashBlock) { return base->SetBestBlock(hashBlock); } -void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } -bool CCoinsViewBacked::BatchWrite(const std::map &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } -bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stats); } - -CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), hashBlock(0) { } - -bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) { - if (cacheCoins.count(txid)) { - coins = cacheCoins[txid]; - return true; - } - if (base->GetCoins(txid, coins)) { - cacheCoins[txid] = coins; - return true; - } - return false; -} - -std::map::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) { - std::map::iterator it = cacheCoins.lower_bound(txid); - if (it != cacheCoins.end() && it->first == txid) - return it; - CCoins tmp; - if (!base->GetCoins(txid,tmp)) - return cacheCoins.end(); - std::map::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins())); - tmp.swap(ret->second); - return ret; -} - -CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) { - std::map::iterator it = FetchCoins(txid); - assert(it != cacheCoins.end()); - return it->second; -} - -bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) { - cacheCoins[txid] = coins; - return true; -} - -bool CCoinsViewCache::HaveCoins(const uint256 &txid) { - return FetchCoins(txid) != cacheCoins.end(); -} - -uint256 CCoinsViewCache::GetBestBlock() { - if (hashBlock == uint256(0)) - hashBlock = base->GetBestBlock(); - return hashBlock; -} - -bool CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { - hashBlock = hashBlockIn; - return true; -} - -bool CCoinsViewCache::BatchWrite(const std::map &mapCoins, const uint256 &hashBlockIn) { - for (std::map::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++) - cacheCoins[it->first] = it->second; - hashBlock = hashBlockIn; - return true; -} - -bool CCoinsViewCache::Flush() { - bool fOk = base->BatchWrite(cacheCoins, hashBlock); - if (fOk) - cacheCoins.clear(); - return fOk; -} - -unsigned int CCoinsViewCache::GetCacheSize() { - return cacheCoins.size(); -} - -/** Helper; lookup from tip (used calling mempool.check() - NOTE: code calling this MUST hold the cs_main lock so - another thread doesn't modify pcoinsTip. When we switch - to C++11 this should be replaced by lambda expressions... - **/ -static CCoins &LookupFromTip(const uint256& hash) { - return pcoinsTip->GetCoins(hash); -} - -/** CCoinsView that brings transactions from a memorypool into view. - It does not check for spendings by memory pool transactions. */ -CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } - -bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) { - if (base->GetCoins(txid, coins)) - return true; - CTransaction tx; - if (mempool.lookup(txid, tx)) { - coins = CCoins(tx, MEMPOOL_HEIGHT); - return true; - } - return false; -} - -bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) { - return mempool.exists(txid) || base->HaveCoins(txid); -} - CCoinsViewCache *pcoinsTip = NULL; CBlockTreeDB *pblocktree = NULL; @@ -1416,25 +1294,6 @@ void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev) -const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) -{ - const CCoins &coins = GetCoins(input.prevout.hash); - assert(coins.IsAvailable(input.prevout.n)); - return coins.vout[input.prevout.n]; -} - -int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx) -{ - if (tx.IsCoinBase()) - return 0; - - int64_t nResult = 0; - for (unsigned int i = 0; i < tx.vin.size(); i++) - nResult += GetOutputFor(tx.vin[i]).nValue; - - return nResult; -} - void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash) { // mark inputs spent @@ -1451,27 +1310,6 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach assert(inputs.SetCoins(txhash, CCoins(tx, nHeight))); } -bool CCoinsViewCache::HaveInputs(const CTransaction& tx) -{ - if (!tx.IsCoinBase()) { - // first check whether information about the prevout hash is available - for (unsigned int i = 0; i < tx.vin.size(); i++) { - const COutPoint &prevout = tx.vin[i].prevout; - if (!HaveCoins(prevout.hash)) - return false; - } - - // then check whether the actual outputs are available - for (unsigned int i = 0; i < tx.vin.size(); i++) { - const COutPoint &prevout = tx.vin[i].prevout; - const CCoins &coins = GetCoins(prevout.hash); - if (!coins.IsAvailable(prevout.n)) - return false; - } - } - return true; -} - bool CScriptCheck::operator()() const { const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; if (!VerifyScript(scriptSig, scriptPubKey, *ptxTo, nIn, nFlags, nHashType)) @@ -1841,7 +1679,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) { - mempool.check(&LookupFromTip); + mempool.check(pcoinsTip); // All modifications to the coin state will be done in this cache. // Only when all have succeeded, we push it to pcoinsTip. @@ -1966,7 +1804,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) mempool.removeConflicts(tx); } - mempool.check(&LookupFromTip); + mempool.check(pcoinsTip); // Update best block in wallet (so we can detect restored wallets) if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0)) @@ -3540,7 +3378,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CValidationState state; if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) { - mempool.check(&LookupFromTip); + mempool.check(pcoinsTip); RelayTransaction(tx, inv.hash); mapAlreadyAskedFor.erase(inv); vWorkQueue.push_back(inv.hash); @@ -3576,7 +3414,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vEraseQueue.push_back(orphanHash); LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString().c_str()); } - mempool.check(&LookupFromTip); + mempool.check(pcoinsTip); } } -- cgit v1.2.3