coins: reuse cache hasher for txid set

Use `SaltedCoinsCacheHasher` for the temporary set of earlier txids in `CoinsViewOverlay`, and in existing overlay tests to exercise the new `Txid` overload.
Every entry is a computed transaction hash, and the set is limited to a few thousand elements per block, satisfying the SipHash-1-3-UJ jumbo-input requirements.

Co-authored-by: Andrew Toth <andrewstoth@gmail.com>
This commit is contained in:
Lőrinc
2026-07-16 16:39:05 -07:00
parent 2beab94896
commit 3bfdcbd7ee
4 changed files with 12 additions and 8 deletions

View File

@@ -8,7 +8,6 @@
#include <primitives/block.h>
#include <random.h>
#include <uint256.h>
#include <util/hasher.h>
#include <util/log.h>
#include <util/threadpool.h>
#include <util/trace.h>
@@ -384,7 +383,7 @@ CCoinsViewCache::ResetGuard CoinsViewOverlay::StartFetching(const CBlock& block
// Loop through the block inputs and set their prevouts in the queue.
// Filter inputs that spend outputs created earlier in the same block. These outputs will be created
// directly in the cache from the tx that creates them, so they will not be requested from a base view.
std::unordered_set<Txid, SaltedTxidHasher> earlier_txids;
std::unordered_set<Txid, SaltedCoinsCacheHasher> earlier_txids;
earlier_txids.reserve(block.vtx.size());
for (const auto& tx : block.vtx | std::views::drop(1)) {
for (const auto& input : tx->vin) {

View File

@@ -243,6 +243,12 @@ class SaltedCoinsCacheHasher
public:
SaltedCoinsCacheHasher(bool deterministic = false);
/** Hash a transaction ID, itself a cryptographic hash, as one jumbo block. */
size_t operator()(const Txid& id) const noexcept
{
return m_hasher.Hash(id.ToUint256());
}
/** Hash an outpoint as its txid jumbo block followed by the zero-extended index as one normal block. */
size_t operator()(const COutPoint& id) const noexcept
{

View File

@@ -10,7 +10,6 @@
#include <txdb.h>
#include <uint256.h>
#include <util/byte_units.h>
#include <util/hasher.h>
#include <util/threadpool.h>
#include <boost/test/unit_test.hpp>
@@ -57,7 +56,7 @@ void PopulateView(const CBlock& block, CCoinsView& view, bool spent = false)
CCoinsViewCache cache{&view};
cache.SetBestBlock(uint256::ONE);
std::unordered_set<Txid, SaltedTxidHasher> txids{};
std::unordered_set<Txid, SaltedCoinsCacheHasher> txids{};
txids.reserve(block.vtx.size() - 1);
for (const auto& tx : block.vtx | std::views::drop(1)) {
for (const auto& in : tx->vin) {
@@ -75,7 +74,7 @@ void PopulateView(const CBlock& block, CCoinsView& view, bool spent = false)
void CheckCache(const CBlock& block, const CCoinsViewCache& cache)
{
uint32_t counter{0};
std::unordered_set<Txid, SaltedTxidHasher> txids{};
std::unordered_set<Txid, SaltedCoinsCacheHasher> txids{};
txids.reserve(block.vtx.size() - 1);
for (const auto& tx : block.vtx) {
@@ -225,7 +224,7 @@ BOOST_AUTO_TEST_CASE(fetch_out_of_order_input_uses_normal_lookup)
PopulateView(block, main_cache);
std::vector<COutPoint> fetched_inputs;
std::unordered_set<Txid, SaltedTxidHasher> txids;
std::unordered_set<Txid, SaltedCoinsCacheHasher> txids;
txids.reserve(block.vtx.size() - 1);
for (const auto& tx : block.vtx | std::views::drop(1)) {
for (const auto& input : tx->vin) {

View File

@@ -429,7 +429,7 @@ FUZZ_TARGET(coins_view_db, .init = initialize_coins_view)
// called.
FUZZ_TARGET(coins_view_overlay, .init = initialize_coins_view)
{
SeedRandomStateForTest(SeedRand::ZEROS); // for SaltedTxidHasher
SeedRandomStateForTest(SeedRand::ZEROS); // for SaltedCoinsCacheHasher
StartPoolIfNeeded();
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
MutationGuardCoinsViewCache backend_cache{&CoinsViewEmpty::Get(), /*deterministic=*/true};
@@ -441,7 +441,7 @@ FUZZ_TARGET(coins_view_overlay, .init = initialize_coins_view)
FUZZ_TARGET(coins_view_stacked, .init = initialize_coins_view)
{
SeedRandomStateForTest(SeedRand::ZEROS); // for SaltedTxidHasher
SeedRandomStateForTest(SeedRand::ZEROS); // for SaltedCoinsCacheHasher
StartPoolIfNeeded();
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
auto db_params = DBParams{