diff --git a/src/coins.cpp b/src/coins.cpp index 6137b51c5..7bfb84ef3 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -52,30 +52,30 @@ bool CCoins::Spend(int nPos) { } -bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) { return false; } +bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { 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::HaveCoins(const uint256 &txid) const { return false; } +uint256 CCoinsView::GetBestBlock() const { return uint256(0); } bool CCoinsView::SetBestBlock(const uint256 &hashBlock) { return false; } bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; } -bool CCoinsView::GetStats(CCoinsStats &stats) { return false; } +bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; } CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { } -bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) { return base->GetCoins(txid, coins); } +bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { 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::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); } +uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); } bool CCoinsViewBacked::SetBestBlock(const uint256 &hashBlock) { return base->SetBestBlock(hashBlock); } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } -bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stats); } +bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); } CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {} CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), hashBlock(0) { } -bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) { +bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const { if (cacheCoins.count(txid)) { coins = cacheCoins[txid]; return true; @@ -99,19 +99,29 @@ CCoinsMap::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) { return ret; } +CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const { + /* Avoid redundant implementation with the const-cast. */ + return const_cast(this)->FetchCoins(txid); +} + CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) { CCoinsMap::iterator it = FetchCoins(txid); assert(it != cacheCoins.end()); return it->second; } +const CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) const { + /* Avoid redundant implementation with the const-cast. */ + return const_cast(this)->GetCoins(txid); +} + bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) { cacheCoins[txid] = coins; return true; } -bool CCoinsViewCache::HaveCoins(const uint256 &txid) { - CCoinsMap::iterator it = FetchCoins(txid); +bool CCoinsViewCache::HaveCoins(const uint256 &txid) const { + CCoinsMap::const_iterator it = FetchCoins(txid); // We're using vtx.empty() instead of IsPruned here for performance reasons, // as we only care about the case where an transaction was replaced entirely // in a reorganization (which wipes vout entirely, as opposed to spending @@ -119,7 +129,7 @@ bool CCoinsViewCache::HaveCoins(const uint256 &txid) { return (it != cacheCoins.end() && !it->second.vout.empty()); } -uint256 CCoinsViewCache::GetBestBlock() { +uint256 CCoinsViewCache::GetBestBlock() const { if (hashBlock == uint256(0)) hashBlock = base->GetBestBlock(); return hashBlock; @@ -146,18 +156,18 @@ bool CCoinsViewCache::Flush() { return fOk; } -unsigned int CCoinsViewCache::GetCacheSize() { +unsigned int CCoinsViewCache::GetCacheSize() const { return cacheCoins.size(); } -const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) +const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const { 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) +int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx) const { if (tx.IsCoinBase()) return 0; @@ -169,7 +179,7 @@ int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx) return nResult; } -bool CCoinsViewCache::HaveInputs(const CTransaction& tx) +bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const { if (!tx.IsCoinBase()) { // first check whether information about the prevout hash is available @@ -190,7 +200,7 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) return true; } -double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) +double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const { if (tx.IsCoinBase()) return 0.0; diff --git a/src/coins.h b/src/coins.h index 2b657299e..08913531d 100644 --- a/src/coins.h +++ b/src/coins.h @@ -276,17 +276,17 @@ class CCoinsView { public: // Retrieve the CCoins (unspent transaction outputs) for a given txid - virtual bool GetCoins(const uint256 &txid, CCoins &coins); + virtual bool GetCoins(const uint256 &txid, CCoins &coins) const; // Modify the CCoins for a given txid virtual bool SetCoins(const uint256 &txid, const CCoins &coins); // Just check whether we have data for a given txid. // This may (but cannot always) return true for fully spent transactions - virtual bool HaveCoins(const uint256 &txid); + virtual bool HaveCoins(const uint256 &txid) const; // Retrieve the block hash whose state this CCoinsView currently represents - virtual uint256 GetBestBlock(); + virtual uint256 GetBestBlock() const; // Modify the currently active block hash virtual bool SetBestBlock(const uint256 &hashBlock); @@ -296,7 +296,7 @@ public: virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); // Calculate statistics about the unspent transaction output set - virtual bool GetStats(CCoinsStats &stats); + virtual bool GetStats(CCoinsStats &stats) const; // As we use CCoinsViews polymorphically, have a virtual destructor virtual ~CCoinsView() {} @@ -311,14 +311,14 @@ protected: public: CCoinsViewBacked(CCoinsView &viewIn); - bool GetCoins(const uint256 &txid, CCoins &coins); + bool GetCoins(const uint256 &txid, CCoins &coins) const; bool SetCoins(const uint256 &txid, const CCoins &coins); - bool HaveCoins(const uint256 &txid); - uint256 GetBestBlock(); + bool HaveCoins(const uint256 &txid) const; + uint256 GetBestBlock() const; bool SetBestBlock(const uint256 &hashBlock); void SetBackend(CCoinsView &viewIn); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); - bool GetStats(CCoinsStats &stats); + bool GetStats(CCoinsStats &stats) const; }; @@ -326,17 +326,20 @@ public: class CCoinsViewCache : public CCoinsViewBacked { protected: - uint256 hashBlock; - CCoinsMap cacheCoins; + + /* Make mutable so that we can "fill the cache" even from Get-methods + declared as "const". */ + mutable uint256 hashBlock; + mutable CCoinsMap cacheCoins; public: CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false); // Standard CCoinsView methods - bool GetCoins(const uint256 &txid, CCoins &coins); + bool GetCoins(const uint256 &txid, CCoins &coins) const; bool SetCoins(const uint256 &txid, const CCoins &coins); - bool HaveCoins(const uint256 &txid); - uint256 GetBestBlock(); + bool HaveCoins(const uint256 &txid) const; + uint256 GetBestBlock() const; bool SetBestBlock(const uint256 &hashBlock); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); @@ -344,6 +347,7 @@ public: // Many methods explicitly require a CCoinsViewCache because of this method, to reduce // copying. CCoins &GetCoins(const uint256 &txid); + const CCoins &GetCoins(const uint256 &txid) const; // Push the modifications applied to this cache to its base. // Failure to call this method before destruction will cause the changes to be forgotten. @@ -351,7 +355,7 @@ public: bool Flush(); // Calculate the size of the cache (in number of transactions) - unsigned int GetCacheSize(); + unsigned int GetCacheSize() const; /** Amount of bitcoins coming in to a transaction Note that lightweight clients may not know anything besides the hash of previous transactions, @@ -360,18 +364,19 @@ public: @param[in] tx transaction for which we are checking input total @return Sum of value of all inputs (scriptSigs) */ - int64_t GetValueIn(const CTransaction& tx); + int64_t GetValueIn(const CTransaction& tx) const; // Check whether all prevouts of the transaction are present in the UTXO set represented by this view - bool HaveInputs(const CTransaction& tx); + bool HaveInputs(const CTransaction& tx) const; // Return priority of tx at height nHeight - double GetPriority(const CTransaction &tx, int nHeight); + double GetPriority(const CTransaction &tx, int nHeight) const; - const CTxOut &GetOutputFor(const CTxIn& input); + const CTxOut &GetOutputFor(const CTxIn& input) const; private: CCoinsMap::iterator FetchCoins(const uint256 &txid); + CCoinsMap::const_iterator FetchCoins(const uint256 &txid) const; }; #endif diff --git a/src/txdb.cpp b/src/txdb.cpp index 7c0683aaf..2349514de 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -27,7 +27,7 @@ void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) { CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) { } -bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) { +bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const { return db.Read(make_pair('c', txid), coins); } @@ -37,11 +37,11 @@ bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) { return db.WriteBatch(batch); } -bool CCoinsViewDB::HaveCoins(const uint256 &txid) { +bool CCoinsViewDB::HaveCoins(const uint256 &txid) const { return db.Exists(make_pair('c', txid)); } -uint256 CCoinsViewDB::GetBestBlock() { +uint256 CCoinsViewDB::GetBestBlock() const { uint256 hashBestChain; if (!db.Read('B', hashBestChain)) return uint256(0); @@ -105,8 +105,11 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) { return Read('l', nFile); } -bool CCoinsViewDB::GetStats(CCoinsStats &stats) { - boost::scoped_ptr pcursor(db.NewIterator()); +bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { + /* It seems that there are no "const iterators" for LevelDB. Since we + only need read operations on it, use a const-cast to get around + that restriction. */ + leveldb::Iterator *pcursor = const_cast(&db)->NewIterator(); pcursor->SeekToFirst(); CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); diff --git a/src/txdb.h b/src/txdb.h index 099f15177..f0b6b9e1d 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -32,13 +32,13 @@ protected: public: CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); - bool GetCoins(const uint256 &txid, CCoins &coins); + bool GetCoins(const uint256 &txid, CCoins &coins) const; bool SetCoins(const uint256 &txid, const CCoins &coins); - bool HaveCoins(const uint256 &txid); - uint256 GetBestBlock(); + bool HaveCoins(const uint256 &txid) const; + uint256 GetBestBlock() const; bool SetBestBlock(const uint256 &hashBlock); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); - bool GetStats(CCoinsStats &stats); + bool GetStats(CCoinsStats &stats) const; }; /** Access to the block database (blocks/index/) */ diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 80cae6824..3845a35b3 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -625,7 +625,7 @@ void CTxMemPool::ClearPrioritisation(const uint256 hash) CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } -bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) { +bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const { // If an entry in the mempool exists, always return that one, as it's guaranteed to never // conflict with the underlying cache, and it cannot have pruned entries (as it contains full) // transactions. First checking the underlying cache risks returning a pruned entry instead. @@ -637,7 +637,7 @@ bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) { return (base->GetCoins(txid, coins) && !coins.IsPruned()); } -bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) { +bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { return mempool.exists(txid) || base->HaveCoins(txid); } diff --git a/src/txmempool.h b/src/txmempool.h index 2577397bc..074c35507 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -143,8 +143,8 @@ protected: public: CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn); - bool GetCoins(const uint256 &txid, CCoins &coins); - bool HaveCoins(const uint256 &txid); + bool GetCoins(const uint256 &txid, CCoins &coins) const; + bool HaveCoins(const uint256 &txid) const; }; #endif /* BITCOIN_TXMEMPOOL_H */