Changeset View
Changeset View
Standalone View
Standalone View
src/test/coins_tests.cpp
Show All 26 Lines | bool operator==(const Coin &a, const Coin &b) { | ||||
} | } | ||||
return a.IsCoinBase() == b.IsCoinBase() && a.GetHeight() == b.GetHeight() && | return a.IsCoinBase() == b.IsCoinBase() && a.GetHeight() == b.GetHeight() && | ||||
a.GetTxOut() == b.GetTxOut(); | a.GetTxOut() == b.GetTxOut(); | ||||
} | } | ||||
class CCoinsViewTest : public CCoinsView { | class CCoinsViewTest : public CCoinsView { | ||||
uint256 hashBestBlock_; | uint256 hashBestBlock_; | ||||
std::map<uint256, CCoins> map_; | std::map<COutPoint, Coin> map_; | ||||
public: | public: | ||||
bool GetCoins(const uint256 &txid, CCoins &coins) const { | bool GetCoin(const COutPoint &outpoint, Coin &coin) const { | ||||
std::map<uint256, CCoins>::const_iterator it = map_.find(txid); | std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint); | ||||
if (it == map_.end()) { | if (it == map_.end()) { | ||||
return false; | return false; | ||||
} | } | ||||
coins = it->second; | coin = it->second; | ||||
if (coins.IsPruned() && insecure_rand() % 2 == 0) { | if (coin.IsSpent() && insecure_rand() % 2 == 0) { | ||||
// Randomly return false in case of an empty entry. | // Randomly return false in case of an empty entry. | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool HaveCoins(const uint256 &txid) const { | bool HaveCoin(const COutPoint outpoint) const { | ||||
CCoins coins; | Coin coin; | ||||
return GetCoins(txid, coins); | return GetCoin(outpoint, coin); | ||||
} | } | ||||
uint256 GetBestBlock() const { return hashBestBlock_; } | uint256 GetBestBlock() const { return hashBestBlock_; } | ||||
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { | bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { | ||||
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { | for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { | ||||
if (it->second.flags & CCoinsCacheEntry::DIRTY) { | if (it->second.flags & CCoinsCacheEntry::DIRTY) { | ||||
// Same optimization used in CCoinsViewDB is to only write dirty | // Same optimization used in CCoinsViewDB is to only write dirty | ||||
// entries. | // entries. | ||||
map_[it->first] = it->second.coins; | map_[it->first] = it->second.coin; | ||||
if (it->second.coins.IsPruned() && insecure_rand() % 3 == 0) { | if (it->second.coin.IsSpent() && insecure_rand() % 3 == 0) { | ||||
// Randomly delete empty entries on write. | // Randomly delete empty entries on write. | ||||
map_.erase(it->first); | map_.erase(it->first); | ||||
} | } | ||||
} | } | ||||
mapCoins.erase(it++); | mapCoins.erase(it++); | ||||
} | } | ||||
if (!hashBlock.IsNull()) hashBestBlock_ = hashBlock; | if (!hashBlock.IsNull()) { | ||||
hashBestBlock_ = hashBlock; | |||||
} | |||||
return true; | return true; | ||||
} | } | ||||
}; | }; | ||||
class CCoinsViewCacheTest : public CCoinsViewCache { | class CCoinsViewCacheTest : public CCoinsViewCache { | ||||
public: | public: | ||||
CCoinsViewCacheTest(CCoinsView *base) : CCoinsViewCache(base) {} | CCoinsViewCacheTest(CCoinsView *base) : CCoinsViewCache(base) {} | ||||
void SelfTest() const { | void SelfTest() const { | ||||
// Manually recompute the dynamic usage of the whole data, and compare | // Manually recompute the dynamic usage of the whole data, and compare | ||||
// it. | // it. | ||||
size_t ret = memusage::DynamicUsage(cacheCoins); | size_t ret = memusage::DynamicUsage(cacheCoins); | ||||
for (CCoinsMap::iterator it = cacheCoins.begin(); | for (CCoinsMap::iterator it = cacheCoins.begin(); | ||||
it != cacheCoins.end(); it++) { | it != cacheCoins.end(); it++) { | ||||
ret += it->second.coins.DynamicMemoryUsage(); | ret += it->second.coin.DynamicMemoryUsage(); | ||||
} | } | ||||
BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret); | BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret); | ||||
} | } | ||||
CCoinsMap &map() { return cacheCoins; } | CCoinsMap &map() { return cacheCoins; } | ||||
size_t &usage() { return cachedCoinsUsage; } | size_t &usage() { return cachedCoinsUsage; } | ||||
}; | }; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 522 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(ccoins_serialization) { | ||||
try { | try { | ||||
CCoins cc5; | CCoins cc5; | ||||
ss5 >> cc5; | ss5 >> cc5; | ||||
BOOST_CHECK_MESSAGE(false, "We should have thrown"); | BOOST_CHECK_MESSAGE(false, "We should have thrown"); | ||||
} catch (const std::ios_base::failure &e) { | } catch (const std::ios_base::failure &e) { | ||||
} | } | ||||
} | } | ||||
// TODO: Remove TXID once the migration is over. | static const COutPoint OUTPOINT; | ||||
static const uint256 TXID; | |||||
static const COutPoint OUTPOINT = {uint256(), 0}; | |||||
static const CAmount PRUNED = -1; | static const CAmount PRUNED = -1; | ||||
static const CAmount ABSENT = -2; | static const CAmount ABSENT = -2; | ||||
static const CAmount FAIL = -3; | static const CAmount FAIL = -3; | ||||
static const CAmount VALUE1 = 100; | static const CAmount VALUE1 = 100; | ||||
static const CAmount VALUE2 = 200; | static const CAmount VALUE2 = 200; | ||||
static const CAmount VALUE3 = 300; | static const CAmount VALUE3 = 300; | ||||
static const char DIRTY = CCoinsCacheEntry::DIRTY; | static const char DIRTY = CCoinsCacheEntry::DIRTY; | ||||
static const char FRESH = CCoinsCacheEntry::FRESH; | static const char FRESH = CCoinsCacheEntry::FRESH; | ||||
static const char NO_ENTRY = -1; | static const char NO_ENTRY = -1; | ||||
static const auto FLAGS = {char(0), FRESH, DIRTY, char(DIRTY | FRESH)}; | static const auto FLAGS = {char(0), FRESH, DIRTY, char(DIRTY | FRESH)}; | ||||
static const auto CLEAN_FLAGS = {char(0), FRESH}; | static const auto CLEAN_FLAGS = {char(0), FRESH}; | ||||
static const auto ABSENT_FLAGS = {NO_ENTRY}; | static const auto ABSENT_FLAGS = {NO_ENTRY}; | ||||
void SetCoinsValue(CAmount value, CCoins &coins) { | void SetCoinsValue(CAmount value, Coin &coin) { | ||||
assert(value != ABSENT); | assert(value != ABSENT); | ||||
coins.Clear(); | coin.Clear(); | ||||
assert(coins.IsPruned()); | assert(coin.IsSpent()); | ||||
if (value != PRUNED) { | if (value != PRUNED) { | ||||
coins.vout.emplace_back(); | CTxOut out; | ||||
coins.vout.back().nValue = value; | out.nValue = value; | ||||
assert(!coins.IsPruned()); | coin = Coin(std::move(out), 1, false); | ||||
assert(!coin.IsSpent()); | |||||
} | } | ||||
} | } | ||||
size_t InsertCoinsMapEntry(CCoinsMap &map, CAmount value, char flags) { | size_t InsertCoinsMapEntry(CCoinsMap &map, CAmount value, char flags) { | ||||
if (value == ABSENT) { | if (value == ABSENT) { | ||||
assert(flags == NO_ENTRY); | assert(flags == NO_ENTRY); | ||||
return 0; | return 0; | ||||
} | } | ||||
assert(flags != NO_ENTRY); | assert(flags != NO_ENTRY); | ||||
CCoinsCacheEntry entry; | CCoinsCacheEntry entry; | ||||
entry.flags = flags; | entry.flags = flags; | ||||
SetCoinsValue(value, entry.coins); | SetCoinsValue(value, entry.coin); | ||||
auto inserted = map.emplace(TXID, std::move(entry)); | auto inserted = map.emplace(OUTPOINT, std::move(entry)); | ||||
assert(inserted.second); | assert(inserted.second); | ||||
return inserted.first->second.coins.DynamicMemoryUsage(); | return inserted.first->second.coin.DynamicMemoryUsage(); | ||||
} | } | ||||
void GetCoinsMapEntry(const CCoinsMap &map, CAmount &value, char &flags) { | void GetCoinsMapEntry(const CCoinsMap &map, CAmount &value, char &flags) { | ||||
auto it = map.find(TXID); | auto it = map.find(OUTPOINT); | ||||
if (it == map.end()) { | if (it == map.end()) { | ||||
value = ABSENT; | value = ABSENT; | ||||
flags = NO_ENTRY; | flags = NO_ENTRY; | ||||
} else { | } else { | ||||
if (it->second.coins.IsPruned()) { | if (it->second.coin.IsSpent()) { | ||||
assert(it->second.coins.vout.size() == 0); | |||||
value = PRUNED; | value = PRUNED; | ||||
} else { | } else { | ||||
assert(it->second.coins.vout.size() == 1); | value = it->second.coin.GetTxOut().nValue; | ||||
value = it->second.coins.vout[0].nValue; | |||||
} | } | ||||
flags = it->second.flags; | flags = it->second.flags; | ||||
assert(flags != NO_ENTRY); | assert(flags != NO_ENTRY); | ||||
} | } | ||||
} | } | ||||
void WriteCoinsViewEntry(CCoinsView &view, CAmount value, char flags) { | void WriteCoinsViewEntry(CCoinsView &view, CAmount value, char flags) { | ||||
CCoinsMap map; | CCoinsMap map; | ||||
▲ Show 20 Lines • Show All 285 Lines • Show Last 20 Lines |