Changeset View
Changeset View
Standalone View
Standalone View
src/coins.cpp
// Copyright (c) 2012-2016 The Bitcoin Core developers | // Copyright (c) 2012-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "coins.h" | #include "coins.h" | ||||
#include "consensus/consensus.h" | #include "consensus/consensus.h" | ||||
#include "memusage.h" | #include "memusage.h" | ||||
#include "random.h" | #include "random.h" | ||||
#include "util.h" | |||||
#include <cassert> | #include <cassert> | ||||
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { | bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { | ||||
return false; | return false; | ||||
} | } | ||||
bool CCoinsView::HaveCoin(const COutPoint &outpoint) const { | bool CCoinsView::HaveCoin(const COutPoint &outpoint) const { | ||||
return false; | return false; | ||||
} | } | ||||
uint256 CCoinsView::GetBestBlock() const { | uint256 CCoinsView::GetBestBlock() const { | ||||
return uint256(); | return uint256(); | ||||
} | } | ||||
std::vector<uint256> CCoinsView::GetHeadBlocks() const { | std::vector<uint256> CCoinsView::GetHeadBlocks() const { | ||||
return std::vector<uint256>(); | return std::vector<uint256>(); | ||||
} | } | ||||
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { | bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { | ||||
return false; | return false; | ||||
} | } | ||||
CCoinsViewCursor *CCoinsView::Cursor() const { | CCoinsViewCursor *CCoinsView::Cursor() const { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
CUtxoCommit CCoinsView::GetCommitment() { | |||||
return CUtxoCommit(); | |||||
} | |||||
void CCoinsView::UpdateCommitment(CCoinsMap &mapCoins) {} | |||||
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) {} | CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) {} | ||||
bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { | bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { | ||||
return base->GetCoin(outpoint, coin); | return base->GetCoin(outpoint, coin); | ||||
} | } | ||||
bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { | bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { | ||||
return base->HaveCoin(outpoint); | return base->HaveCoin(outpoint); | ||||
} | } | ||||
uint256 CCoinsViewBacked::GetBestBlock() const { | uint256 CCoinsViewBacked::GetBestBlock() const { | ||||
Show All 11 Lines | |||||
} | } | ||||
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { | CCoinsViewCursor *CCoinsViewBacked::Cursor() const { | ||||
return base->Cursor(); | return base->Cursor(); | ||||
} | } | ||||
size_t CCoinsViewBacked::EstimateSize() const { | size_t CCoinsViewBacked::EstimateSize() const { | ||||
return base->EstimateSize(); | return base->EstimateSize(); | ||||
} | } | ||||
CUtxoCommit CCoinsViewBacked::GetCommitment() { | |||||
return base->GetCommitment(); | |||||
} | |||||
SaltedOutpointHasher::SaltedOutpointHasher() | SaltedOutpointHasher::SaltedOutpointHasher() | ||||
: k0(GetRand(std::numeric_limits<uint64_t>::max())), | : k0(GetRand(std::numeric_limits<uint64_t>::max())), | ||||
k1(GetRand(std::numeric_limits<uint64_t>::max())) {} | k1(GetRand(std::numeric_limits<uint64_t>::max())) {} | ||||
CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) | CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) | ||||
: CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {} | : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {} | ||||
size_t CCoinsViewCache::DynamicMemoryUsage() const { | size_t CCoinsViewCache::DynamicMemoryUsage() const { | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin coin, | ||||
if (!possible_overwrite) { | if (!possible_overwrite) { | ||||
if (!it->second.coin.IsSpent()) { | if (!it->second.coin.IsSpent()) { | ||||
throw std::logic_error( | throw std::logic_error( | ||||
"Adding new coin that replaces non-pruned entry"); | "Adding new coin that replaces non-pruned entry"); | ||||
} | } | ||||
fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY); | fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY); | ||||
} | } | ||||
it->second.coin = std::move(coin); | it->second.coin = std::move(coin); | ||||
it->second.flags |= | it->second.flags |= CCoinsCacheEntry::UNCOMMITED | CCoinsCacheEntry::DIRTY | | ||||
CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0); | (fresh ? CCoinsCacheEntry::FRESH : 0); | ||||
cachedCoinsUsage += it->second.coin.DynamicMemoryUsage(); | cachedCoinsUsage += it->second.coin.DynamicMemoryUsage(); | ||||
} | } | ||||
void AddCoins(CCoinsViewCache &cache, const CTransaction &tx, int nHeight, | void AddCoins(CCoinsViewCache &cache, const CTransaction &tx, int nHeight, | ||||
bool check) { | bool check) { | ||||
bool fCoinbase = tx.IsCoinBase(); | bool fCoinbase = tx.IsCoinBase(); | ||||
const uint256 &txid = tx.GetHash(); | const uint256 &txid = tx.GetHash(); | ||||
for (size_t i = 0; i < tx.vout.size(); ++i) { | for (size_t i = 0; i < tx.vout.size(); ++i) { | ||||
Show All 13 Lines | bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin *moveout) { | ||||
} | } | ||||
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); | cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); | ||||
if (moveout) { | if (moveout) { | ||||
*moveout = std::move(it->second.coin); | *moveout = std::move(it->second.coin); | ||||
} | } | ||||
if (it->second.flags & CCoinsCacheEntry::FRESH) { | if (it->second.flags & CCoinsCacheEntry::FRESH) { | ||||
cacheCoins.erase(it); | cacheCoins.erase(it); | ||||
} else { | } else { | ||||
it->second.flags |= CCoinsCacheEntry::DIRTY; | it->second.flags |= | ||||
CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::UNCOMMITED; | |||||
it->second.coin.Clear(); | it->second.coin.Clear(); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
static const Coin coinEmpty; | static const Coin coinEmpty; | ||||
const Coin &CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const { | const Coin &CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const { | ||||
Show All 37 Lines | for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { | ||||
if (!(it->second.flags & CCoinsCacheEntry::FRESH && | if (!(it->second.flags & CCoinsCacheEntry::FRESH && | ||||
it->second.coin.IsSpent())) { | it->second.coin.IsSpent())) { | ||||
// Otherwise we will need to create it in the parent and | // Otherwise we will need to create it in the parent and | ||||
// move the data up and mark it as dirty | // move the data up and mark it as dirty | ||||
CCoinsCacheEntry &entry = cacheCoins[it->first]; | CCoinsCacheEntry &entry = cacheCoins[it->first]; | ||||
entry.coin = std::move(it->second.coin); | entry.coin = std::move(it->second.coin); | ||||
cachedCoinsUsage += entry.coin.DynamicMemoryUsage(); | cachedCoinsUsage += entry.coin.DynamicMemoryUsage(); | ||||
entry.flags = CCoinsCacheEntry::DIRTY; | entry.flags = CCoinsCacheEntry::DIRTY; | ||||
// We can mark it FRESH in the parent if it was FRESH in the | // We can mark it FRESH in the parent if it was FRESH in the | ||||
// child. Otherwise it might have just been flushed from the | // child. Otherwise it might have just been flushed from the | ||||
// parent's cache and already exist in the grandparent | // parent's cache and already exist in the grandparent | ||||
if (it->second.flags & CCoinsCacheEntry::FRESH) | if (it->second.flags & CCoinsCacheEntry::FRESH) | ||||
entry.flags |= CCoinsCacheEntry::FRESH; | entry.flags |= CCoinsCacheEntry::FRESH; | ||||
if (it->second.flags & CCoinsCacheEntry::UNCOMMITED) | |||||
entry.flags |= CCoinsCacheEntry::UNCOMMITED; | |||||
} | } | ||||
} else { | } else { | ||||
// Assert that the child cache entry was not marked FRESH if the | // Assert that the child cache entry was not marked FRESH if the | ||||
// parent cache entry has unspent outputs. If this ever happens, | // parent cache entry has unspent outputs. If this ever happens, | ||||
// it means the FRESH flag was misapplied and there is a logic | // it means the FRESH flag was misapplied and there is a logic | ||||
// error in the calling code. | // error in the calling code. | ||||
if ((it->second.flags & CCoinsCacheEntry::FRESH) && | if ((it->second.flags & CCoinsCacheEntry::FRESH) && | ||||
!itUs->second.coin.IsSpent()) | !itUs->second.coin.IsSpent()) | ||||
Show All 15 Lines | for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { | ||||
itUs->second.coin = std::move(it->second.coin); | itUs->second.coin = std::move(it->second.coin); | ||||
cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage(); | cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage(); | ||||
itUs->second.flags |= CCoinsCacheEntry::DIRTY; | itUs->second.flags |= CCoinsCacheEntry::DIRTY; | ||||
// NOTE: It is possible the child has a FRESH flag here in | // NOTE: It is possible the child has a FRESH flag here in | ||||
// the event the entry we found in the parent is pruned. But | // the event the entry we found in the parent is pruned. But | ||||
// we must not copy that FRESH flag to the parent as that | // we must not copy that FRESH flag to the parent as that | ||||
// pruned state likely still needs to be communicated to the | // pruned state likely still needs to be communicated to the | ||||
// grandparent. | // grandparent. | ||||
if (it->second.flags & CCoinsCacheEntry::UNCOMMITED) | |||||
itUs->second.flags |= CCoinsCacheEntry::UNCOMMITED; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
CCoinsMap::iterator itOld = it++; | CCoinsMap::iterator itOld = it++; | ||||
mapCoins.erase(itOld); | mapCoins.erase(itOld); | ||||
} | } | ||||
hashBlock = hashBlockIn; | hashBlock = hashBlockIn; | ||||
return true; | return true; | ||||
} | } | ||||
void CCoinsViewCache::UpdateCommitment(CCoinsMap &mapCoins) { | |||||
base->UpdateCommitment(mapCoins); | |||||
} | |||||
bool CCoinsViewCache::Flush() { | bool CCoinsViewCache::Flush() { | ||||
bool fOk = base->BatchWrite(cacheCoins, hashBlock); | bool fOk = base->BatchWrite(cacheCoins, hashBlock); | ||||
cacheCoins.clear(); | cacheCoins.clear(); | ||||
cachedCoinsUsage = 0; | cachedCoinsUsage = 0; | ||||
return fOk; | return fOk; | ||||
} | } | ||||
CUtxoCommit CCoinsViewCache::GetCommitment() { | |||||
base->UpdateCommitment(cacheCoins); | |||||
return base->GetCommitment(); | |||||
} | |||||
void CCoinsViewCache::Uncache(const COutPoint &outpoint) { | void CCoinsViewCache::Uncache(const COutPoint &outpoint) { | ||||
CCoinsMap::iterator it = cacheCoins.find(outpoint); | CCoinsMap::iterator it = cacheCoins.find(outpoint); | ||||
if (it != cacheCoins.end() && it->second.flags == 0) { | if (it != cacheCoins.end() && it->second.flags == 0) { | ||||
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); | cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); | ||||
cacheCoins.erase(it); | cacheCoins.erase(it); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 74 Lines • Show Last 20 Lines |