Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1001BOOST_CHECK(!all_caches[1]->HaveCoin(outp));1003flush_all(/*erase=*/ true); // Erase all cache content.1005// --- Bonus check 2: ensure that a FRESH, spent coin is deleted by Sync()1006//1007txid = Txid::FromUint256(m_rng.rand256());1008outp = COutPoint(txid, 0);1009coin = MakeCoin();1010CAmount coin_val = coin.out.nValue;1011BOOST_CHECK(!base.HaveCoin(outp));1012BOOST_CHECK(!all_caches[0]->HaveCoin(outp));1013BOOST_CHECK(!all_caches[1]->HaveCoin(outp));1015// Add and spend from same cache without flushing.1016all_caches[0]->AddCoin(outp, std::move(coin), false);1018// Coin should be FRESH in the cache.1019BOOST_CHECK_EQUAL(GetCoinsMapEntry(all_caches[0]->map(), outp), CoinEntry(coin_val, CoinEntry::State::DIRTY_FRESH));1020// Base shouldn't have seen coin.1021BOOST_CHECK(!base.HaveCoin(outp));1023BOOST_CHECK(all_caches[0]->SpendCoin(outp));1024all_caches[0]->Sync();1026// Ensure there is no sign of the coin after spend/flush.1027BOOST_CHECK(!GetCoinsMapEntry(all_caches[0]->map(), outp));1028BOOST_CHECK(!all_caches[0]->HaveCoinInCache(outp));1029BOOST_CHECK(!base.HaveCoin(outp));1030}1031}; // struct FlushTest1033BOOST_FIXTURE_TEST_CASE(ccoins_flush_behavior, FlushTest)1034{1035// Create two in-memory caches atop a leveldb view.1036CCoinsViewDB base{{.path = "test", .cache_bytes = 8_MiB, .memory_only = true}, {}};1037std::vector<std::unique_ptr<CCoinsViewCacheTest>> caches;1038caches.push_back(std::make_unique<CCoinsViewCacheTest>(&base));1039caches.push_back(std::make_unique<CCoinsViewCacheTest>(caches.back().get()));1041for (const auto& view : caches) {1042TestFlushBehavior(view.get(), base, caches, /*do_erasing_flush=*/false);1043TestFlushBehavior(view.get(), base, caches, /*do_erasing_flush=*/true);1044}1045}1047BOOST_FIXTURE_TEST_CASE(coins_db_leveldb_layout, FlushTest)1048{1049auto level2_files{[](CCoinsViewDB& base) {1050return *Assert(ToIntegral<int>(*Assert(base.GetDBProperty("leveldb.num-files-at-level2"))));1051}};1052const COutPoint outpoint{Txid::FromUint256(m_rng.rand256()), 0};1053const Coin coin{MakeCoin()};1054const uint256 block_hash{m_rng.rand256()};1056CCoinsViewDB base{{.path = m_args.GetDataDirBase() / "coins_db_leveldb_layout", .cache_bytes = 1_MiB, .wipe_data = true}, {}};1057CCoinsViewCache cache{&base};1059cache.EmplaceCoinInternalDANGER(COutPoint{outpoint}, Coin{coin});1060cache.SetBestBlock(block_hash);1061cache.Sync();1063BOOST_CHECK_EQUAL(level2_files(base), 0);1064WITH_LOCK(::cs_main, return base.CompactFullAsync()).wait();1065BOOST_CHECK_EQUAL(level2_files(base), 1);1067BOOST_CHECK_EQUAL(*Assert(base.GetCoin(outpoint)), coin);1068BOOST_CHECK_EQUAL(base.GetBestBlock(), block_hash);1069}1071BOOST_AUTO_TEST_CASE(coins_resource_is_used)1072{1073CCoinsMapMemoryResource resource;1074PoolResourceTester::CheckAllDataAccountedFor(resource);1076{1077CCoinsMap map{0, CCoinsMap::hasher{}, CCoinsMap::key_equal{}, &resource};1078BOOST_TEST(memusage::DynamicUsage(map) >= resource.ChunkSizeBytes());1080map.reserve(1000);1082// The resource has preallocated a chunk, so we should have space for at several nodes without the need to allocate anything else.1083const auto usage_before = memusage::DynamicUsage(map);1085COutPoint out_point{};1086for (size_t i = 0; i < 1000; ++i) {1087out_point.n = i;1088map[out_point];1089}1090BOOST_TEST(usage_before == memusage::DynamicUsage(map));1091}1093PoolResourceTester::CheckAllDataAccountedFor(resource);1094}1096BOOST_AUTO_TEST_CASE(ccoins_addcoin_exception_keeps_usage_balanced)1097{1098CCoinsViewCacheTest cache{&CoinsViewEmpty::Get()};1100const COutPoint outpoint{Txid::FromUint256(m_rng.rand256()), m_rng.rand32()};1102const Coin coin1{CTxOut{m_rng.randrange(10), CScript{} << m_rng.randbytes(CScriptBase::STATIC_SIZE + 1)}, 1, false};1103cache.AddCoin(outpoint, Coin{coin1}, /*possible_overwrite=*/false);1104cache.SelfTest();1106const Coin coin2{CTxOut{m_rng.randrange(20), CScript{} << m_rng.randbytes(CScriptBase::STATIC_SIZE + 2)}, 2, false};1107BOOST_CHECK_THROW(cache.AddCoin(outpoint, Coin{coin2}, /*possible_overwrite=*/false), std::logic_error);1108cache.SelfTest();1110BOOST_CHECK_EQUAL(cache.AccessCoin(outpoint), coin1);1111}1113BOOST_AUTO_TEST_CASE(ccoins_emplace_duplicate_keeps_usage_balanced)1114{1115CCoinsViewCacheTest cache{&CoinsViewEmpty::Get()};1117const COutPoint outpoint{Txid::FromUint256(m_rng.rand256()), m_rng.rand32()};1119const Coin coin1{CTxOut{m_rng.randrange(10), CScript{} << m_rng.randbytes(CScriptBase::STATIC_SIZE + 1)}, 1, false};1120cache.EmplaceCoinInternalDANGER(outpoint, Coin{coin1});1121cache.SelfTest();1123const Coin coin2{CTxOut{m_rng.randrange(20), CScript{} << m_rng.randbytes(CScriptBase::STATIC_SIZE + 2)}, 2, false};1124cache.EmplaceCoinInternalDANGER(outpoint, Coin{coin2});1125cache.SelfTest();1127BOOST_CHECK_EQUAL(cache.AccessCoin(outpoint), coin1);1128}1130BOOST_AUTO_TEST_CASE(ccoins_reset_guard)1131{1132CCoinsViewTest root{m_rng};1133CCoinsViewCache root_cache{&root};1134uint256 base_best_block{m_rng.rand256()};1135root_cache.SetBestBlock(base_best_block);1136root_cache.Flush();1138CCoinsViewCache cache{&root};1140const COutPoint outpoint{Txid::FromUint256(m_rng.rand256()), m_rng.rand32()};1142const Coin coin{CTxOut{m_rng.randrange(10), CScript{} << m_rng.randbytes(CScriptBase::STATIC_SIZE + 1)}, 1, false};1143cache.EmplaceCoinInternalDANGER(outpoint, Coin{coin});1144BOOST_CHECK_EQUAL(cache.GetDirtyCount(), 1U);1146uint256 cache_best_block{m_rng.rand256()};1147cache.SetBestBlock(cache_best_block);1149{1150const auto reset_guard{cache.CreateResetGuard()};1151BOOST_CHECK_EQUAL(cache.AccessCoin(outpoint), coin);1152BOOST_CHECK(!cache.AccessCoin(outpoint).IsSpent());1153BOOST_CHECK_EQUAL(cache.GetCacheSize(), 1);1154BOOST_CHECK_EQUAL(cache.GetDirtyCount(), 1);1155BOOST_CHECK_EQUAL(cache.GetBestBlock(), cache_best_block);1156BOOST_CHECK(!root_cache.HaveCoinInCache(outpoint));1157}1159BOOST_CHECK(cache.AccessCoin(outpoint).IsSpent());1160BOOST_CHECK_EQUAL(cache.GetCacheSize(), 0);1161BOOST_CHECK_EQUAL(cache.GetDirtyCount(), 0);1162BOOST_CHECK_EQUAL(cache.GetBestBlock(), base_best_block);1163BOOST_CHECK(!root_cache.HaveCoinInCache(outpoint));1165// Using a reset guard again is idempotent1166{1167const auto reset_guard{cache.CreateResetGuard()};1168}1170BOOST_CHECK(cache.AccessCoin(outpoint).IsSpent());1171BOOST_CHECK_EQUAL(cache.GetCacheSize(), 0);1172BOOST_CHECK_EQUAL(cache.GetDirtyCount(), 0U);1173BOOST_CHECK_EQUAL(cache.GetBestBlock(), base_best_block);1174BOOST_CHECK(!root_cache.HaveCoinInCache(outpoint));1176// Flush should be a no-op after reset.1177cache.Flush();1178BOOST_CHECK_EQUAL(cache.GetDirtyCount(), 0U);1179}1181BOOST_AUTO_TEST_CASE(ccoins_peekcoin)1182{1183CCoinsViewTest base{m_rng};1185// Populate the base view with a coin.1186const COutPoint outpoint{Txid::FromUint256(m_rng.rand256()), m_rng.rand32()};1187const Coin coin{CTxOut{m_rng.randrange(10), CScript{}}, 1, false};1188{1189CCoinsViewCache cache{&base};1190cache.AddCoin(outpoint, Coin{coin}, /*possible_overwrite=*/false);1191cache.Flush();1192}1194// Verify PeekCoin can read through the cache stack without mutating the intermediate cache.1195CCoinsViewCacheTest main_cache{&base};1196const auto fetched{main_cache.PeekCoin(outpoint)};1197BOOST_CHECK(fetched.has_value());1198BOOST_CHECK_EQUAL(*fetched, coin);1199BOOST_CHECK(!main_cache.HaveCoinInCache(outpoint));1200}1202BOOST_AUTO_TEST_SUITE_END()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.