Changeset View
Changeset View
Standalone View
Standalone View
src/coins.cpp
Show All 16 Lines | 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, | ||||
CUtxoCommit *commitDelta) { | |||||
return false; | return false; | ||||
} | } | ||||
CCoinsViewCursor *CCoinsView::Cursor() const { | CCoinsViewCursor *CCoinsView::Cursor() const { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
CUtxoCommit *CCoinsView::GetCommitment() const { | |||||
return nullptr; | |||||
} | |||||
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 { | ||||
return base->GetBestBlock(); | return base->GetBestBlock(); | ||||
} | } | ||||
std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { | std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { | ||||
return base->GetHeadBlocks(); | return base->GetHeadBlocks(); | ||||
} | } | ||||
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { | void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { | ||||
base = &viewIn; | base = &viewIn; | ||||
} | } | ||||
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, | bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, | ||||
const uint256 &hashBlock) { | CUtxoCommit *commitDelta) { | ||||
return base->BatchWrite(mapCoins, hashBlock); | return base->BatchWrite(mapCoins, hashBlock, commitDelta); | ||||
} | } | ||||
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() const { | |||||
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), | ||||
cacheUtxoCommitDelta(nullptr) {} | |||||
CCoinsViewCache::~CCoinsViewCache() { | |||||
if (cacheUtxoCommitDelta != nullptr) { | |||||
delete cacheUtxoCommitDelta; | |||||
} | |||||
} | |||||
void CCoinsViewCache::CalculateCommitment() { | |||||
// Currently this is called *before* the cache is filled, | |||||
// and the commitment is maintained on AddCoin/SpentCoin | |||||
// It is probably faster to do it *after* the cache is filled, | |||||
// as this can be parellelized; this does require us to change the | |||||
// in-memory representation if Coin to include the scriptpubkeys for spent | |||||
// outputs | |||||
// we can't start maintaing the commitment in the middle of | |||||
// a cache batch | |||||
assert(cacheCoins.empty()); | |||||
assert(cacheUtxoCommitDelta == nullptr); | |||||
cacheUtxoCommitDelta = new CUtxoCommit(); | |||||
} | |||||
size_t CCoinsViewCache::DynamicMemoryUsage() const { | size_t CCoinsViewCache::DynamicMemoryUsage() const { | ||||
return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage; | return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage; | ||||
} | } | ||||
CCoinsMap::iterator | CCoinsMap::iterator | ||||
CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const { | CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const { | ||||
CCoinsMap::iterator it = cacheCoins.find(outpoint); | CCoinsMap::iterator it = cacheCoins.find(outpoint); | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | if (!possible_overwrite) { | ||||
"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::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0); | CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0); | ||||
cachedCoinsUsage += it->second.coin.DynamicMemoryUsage(); | cachedCoinsUsage += it->second.coin.DynamicMemoryUsage(); | ||||
if (cacheUtxoCommitDelta != nullptr) { | |||||
cacheUtxoCommitDelta->Add(outpoint, it->second.coin); | |||||
} | |||||
} | } | ||||
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) { | ||||
bool overwrite = check ? cache.HaveCoin(COutPoint(txid, i)) : fCoinbase; | bool overwrite = check ? cache.HaveCoin(COutPoint(txid, i)) : fCoinbase; | ||||
// Always set the possible_overwrite flag to AddCoin for coinbase txn, | // Always set the possible_overwrite flag to AddCoin for coinbase txn, | ||||
// in order to correctly deal with the pre-BIP30 occurrences of | // in order to correctly deal with the pre-BIP30 occurrences of | ||||
// duplicate coinbase transactions. | // duplicate coinbase transactions. | ||||
cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), | cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), | ||||
overwrite); | overwrite); | ||||
} | } | ||||
} | } | ||||
bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin *moveout) { | bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin *moveout) { | ||||
CCoinsMap::iterator it = FetchCoin(outpoint); | CCoinsMap::iterator it = FetchCoin(outpoint); | ||||
if (it == cacheCoins.end()) { | if (it == cacheCoins.end()) { | ||||
return false; | return false; | ||||
} | } | ||||
if (cacheUtxoCommitDelta != nullptr) { | |||||
cacheUtxoCommitDelta->Remove(outpoint, it->second.coin); | |||||
} | |||||
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; | ||||
Show All 29 Lines | uint256 CCoinsViewCache::GetBestBlock() const { | ||||
return hashBlock; | return hashBlock; | ||||
} | } | ||||
void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { | void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { | ||||
hashBlock = hashBlockIn; | hashBlock = hashBlockIn; | ||||
} | } | ||||
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, | bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, | ||||
const uint256 &hashBlockIn) { | const uint256 &hashBlockIn, | ||||
CUtxoCommit *commitDelta) { | |||||
// Merge commitment | |||||
if (commitDelta != nullptr) { | |||||
if (cacheUtxoCommitDelta == nullptr) { | |||||
cacheUtxoCommitDelta = new CUtxoCommit(); | |||||
} | |||||
cacheUtxoCommitDelta->Add(*commitDelta); | |||||
} else { | |||||
// Stop maintaining commitment | |||||
if (cacheUtxoCommitDelta != nullptr) { | |||||
delete cacheUtxoCommitDelta; | |||||
cacheUtxoCommitDelta = nullptr; | |||||
} | |||||
} | |||||
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { | for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { | ||||
// Ignore non-dirty entries (optimization). | // Ignore non-dirty entries (optimization). | ||||
if (it->second.flags & CCoinsCacheEntry::DIRTY) { | if (it->second.flags & CCoinsCacheEntry::DIRTY) { | ||||
CCoinsMap::iterator itUs = cacheCoins.find(it->first); | CCoinsMap::iterator itUs = cacheCoins.find(it->first); | ||||
if (itUs == cacheCoins.end()) { | if (itUs == cacheCoins.end()) { | ||||
// The parent cache does not have an entry, while the child does | // The parent cache does not have an entry, while the child does | ||||
// We can ignore it if it's both FRESH and pruned in the child | // We can ignore it if it's both FRESH and pruned in the child | ||||
if (!(it->second.flags & CCoinsCacheEntry::FRESH && | if (!(it->second.flags & CCoinsCacheEntry::FRESH && | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { | ||||
CCoinsMap::iterator itOld = it++; | CCoinsMap::iterator itOld = it++; | ||||
mapCoins.erase(itOld); | mapCoins.erase(itOld); | ||||
} | } | ||||
hashBlock = hashBlockIn; | hashBlock = hashBlockIn; | ||||
return true; | return true; | ||||
} | } | ||||
bool CCoinsViewCache::Flush() { | bool CCoinsViewCache::Flush() { | ||||
bool fOk = base->BatchWrite(cacheCoins, hashBlock); | bool fOk = base->BatchWrite(cacheCoins, hashBlock, cacheUtxoCommitDelta); | ||||
cacheCoins.clear(); | cacheCoins.clear(); | ||||
cachedCoinsUsage = 0; | cachedCoinsUsage = 0; | ||||
return fOk; | return fOk; | ||||
} | } | ||||
CUtxoCommit *CCoinsViewCache::GetCommitment() const { | |||||
CUtxoCommit *parent = base->GetCommitment(); | |||||
if (parent == nullptr || cacheUtxoCommitDelta == nullptr) { | |||||
return nullptr; | |||||
} else { | |||||
// merge this commitment delta with parent commitment | |||||
CUtxoCommit *result = new CUtxoCommit(); | |||||
result->Add(*parent); | |||||
result->Add(*this->cacheUtxoCommitDelta); | |||||
return result; | |||||
} | |||||
} | |||||
bool CCoinsViewCache::HasCommitmentDelta() const { | |||||
return cacheUtxoCommitDelta != nullptr; | |||||
} | |||||
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 |