diff --git a/src/coins.cpp b/src/coins.cpp index 5da63c5202..1d26495788 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -37,14 +37,22 @@ size_t CCoinsViewCache::DynamicMemoryUsage() const { return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage; } +// ELEMENTS: +// Create a CCoinsMapKey for non-PEGIN utxo. +static inline CCoinsMapKey native_key(const COutPoint& outpoint) { + return std::make_pair(uint256(), outpoint); +} + CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const { - CCoinsMap::iterator it = cacheCoins.find(outpoint); + CCoinsMap::iterator it = cacheCoins.find(native_key(outpoint)); if (it != cacheCoins.end()) return it; Coin tmp; if (!base->GetCoin(outpoint, tmp)) return cacheCoins.end(); - CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first; + CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, + std::forward_as_tuple(native_key(outpoint)), + std::forward_as_tuple(std::move(tmp))).first; if (ret->second.coin.IsSpent()) { // The parent only has an empty entry for this outpoint; we can consider our // version as fresh. @@ -68,7 +76,8 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi if (coin.out.scriptPubKey.IsUnspendable()) return; CCoinsMap::iterator it; bool inserted; - std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>()); + std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, + std::forward_as_tuple(native_key(outpoint)), std::tuple<>()); bool fresh = false; if (!inserted) { cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); @@ -128,7 +137,7 @@ bool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const { } bool CCoinsViewCache::HaveCoinInCache(const COutPoint &outpoint) const { - CCoinsMap::const_iterator it = cacheCoins.find(outpoint); + CCoinsMap::const_iterator it = cacheCoins.find(native_key(outpoint)); return (it != cacheCoins.end() && !it->second.coin.IsSpent()); } @@ -207,9 +216,9 @@ bool CCoinsViewCache::Flush() { return fOk; } -void CCoinsViewCache::Uncache(const COutPoint& hash) +void CCoinsViewCache::Uncache(const COutPoint& point) { - CCoinsMap::iterator it = cacheCoins.find(hash); + CCoinsMap::iterator it = cacheCoins.find(native_key(point)); if (it != cacheCoins.end() && it->second.flags == 0) { cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage(); cacheCoins.erase(it); diff --git a/src/coins.h b/src/coins.h index 41a422f485..be44a6fad2 100644 --- a/src/coins.h +++ b/src/coins.h @@ -81,25 +81,6 @@ public: } }; -class SaltedOutpointHasher -{ -private: - /** Salt */ - const uint64_t k0, k1; - -public: - SaltedOutpointHasher(); - - /** - * This *must* return size_t. With Boost 1.46 on 32-bit systems the - * unordered_map will behave unpredictably if the custom hasher returns a - * uint64_t, resulting in failures when syncing the chain (#4634). - */ - size_t operator()(const COutPoint& id) const { - return SipHashUint256Extra(k0, k1, id.hash, id.n); - } -}; - struct CCoinsCacheEntry { Coin coin; // The actual cached data. @@ -119,7 +100,31 @@ struct CCoinsCacheEntry explicit CCoinsCacheEntry(Coin&& coin_) : coin(std::move(coin_)), flags(0) {} }; -typedef std::unordered_map CCoinsMap; +// For PEGIN entries, the first is the genesis hash, the second is the outpoint. +// For ~PEGIN entries, the first is zero, the second is the outpoint. +typedef std::pair CCoinsMapKey; +class SaltedOutpointHasher +{ +private: + /** Salt */ + const uint64_t k0, k1; + +public: + SaltedOutpointHasher(); + + /** + * This *must* return size_t. With Boost 1.46 on 32-bit systems the + * unordered_map will behave unpredictably if the custom hasher returns a + * uint64_t, resulting in failures when syncing the chain (#4634). + */ + size_t operator()(const CCoinsMapKey& key) const { + return SipHashUint256(k0, k1, key.first) ^ SipHashUint256Extra(k0, k1, key.second.hash, key.second.n); + } + size_t operator()(const COutPoint& id) const { + return SipHashUint256Extra(k0, k1, id.hash, id.n); + } +}; +typedef std::unordered_map CCoinsMap; /** Cursor for iterating over CoinsView state */ class CCoinsViewCursor