mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-12 05:32:22 +02:00
coins: use SipHash-1-3-UJ for CCoinsMap
Use the fixed-width `SipHasher13UJ::Hash` path for `CCoinsMap`, while keeping other `SaltedOutpointHasher` users on SipHash-2-4. The salted outputs are process-local and must not be persisted, serialized, or compared across processes. Retained cache entries identify real transaction outputs and therefore contain computed txids. Missing-input validation may probe arbitrary claimed prevouts, but `FetchCoin()` erases each temporary entry immediately when the backend lookup fails, so non-hash keys cannot accumulate. The assumeutxo loader assumes snapshot txids are valid while loading and verifies the complete snapshot content hash before activation. Co-authored-by: Pieter Wuille <pieter@wuille.net>
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#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>
|
||||
@@ -19,6 +20,13 @@ TRACEPOINT_SEMAPHORE(utxocache, add);
|
||||
TRACEPOINT_SEMAPHORE(utxocache, spent);
|
||||
TRACEPOINT_SEMAPHORE(utxocache, uncache);
|
||||
|
||||
SaltedCoinsCacheHasher::SaltedCoinsCacheHasher(bool deterministic)
|
||||
: m_hasher{
|
||||
deterministic ? 0x8e819f2607a18de6 : FastRandomContext().rand64(),
|
||||
deterministic ? 0xf4020d2e3983b0eb : FastRandomContext().rand64()}
|
||||
{
|
||||
}
|
||||
|
||||
CoinsViewEmpty& CoinsViewEmpty::Get()
|
||||
{
|
||||
static CoinsViewEmpty instance;
|
||||
@@ -35,7 +43,7 @@ std::optional<Coin> CCoinsViewCache::PeekCoin(const COutPoint& outpoint) const
|
||||
|
||||
CCoinsViewCache::CCoinsViewCache(CCoinsView* in_base, bool deterministic) :
|
||||
CCoinsViewBacked(in_base), m_deterministic(deterministic),
|
||||
cacheCoins(0, SaltedOutpointHasher(/*deterministic=*/deterministic), CCoinsMap::key_equal{}, &m_cache_coins_memory_resource)
|
||||
cacheCoins(0, SaltedCoinsCacheHasher{/*deterministic=*/deterministic}, CCoinsMap::key_equal{}, &m_cache_coins_memory_resource)
|
||||
{
|
||||
m_sentinel.second.SelfRef(m_sentinel);
|
||||
}
|
||||
@@ -331,7 +339,7 @@ void CCoinsViewCache::ReallocateCache()
|
||||
cacheCoins.~CCoinsMap();
|
||||
m_cache_coins_memory_resource.~CCoinsMapMemoryResource();
|
||||
::new (&m_cache_coins_memory_resource) CCoinsMapMemoryResource{};
|
||||
::new (&cacheCoins) CCoinsMap{0, SaltedOutpointHasher{/*deterministic=*/m_deterministic}, CCoinsMap::key_equal{}, &m_cache_coins_memory_resource};
|
||||
::new (&cacheCoins) CCoinsMap{0, SaltedCoinsCacheHasher{/*deterministic=*/m_deterministic}, CCoinsMap::key_equal{}, &m_cache_coins_memory_resource};
|
||||
}
|
||||
|
||||
void CCoinsViewCache::SanityCheck() const
|
||||
|
||||
35
src/coins.h
35
src/coins.h
@@ -9,6 +9,7 @@
|
||||
#include <attributes.h>
|
||||
#include <compressor.h>
|
||||
#include <core_memusage.h>
|
||||
#include <crypto/siphash.h>
|
||||
#include <memusage.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <primitives/transaction_identifier.h>
|
||||
@@ -18,7 +19,6 @@
|
||||
#include <util/check.h>
|
||||
#include <util/log.h>
|
||||
#include <util/overflow.h>
|
||||
#include <util/hasher.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
@@ -219,6 +219,37 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* SipHash-1-3-UJ based hasher for the coins cache and related coins containers.
|
||||
*
|
||||
* Retained entries identify real transaction outputs, so their keys contain computed txids.
|
||||
* Missing-input lookups may contain arbitrary claimed prevouts, but FetchCoin() immediately
|
||||
* erases their temporary entries when the backend lookup fails, so non-hash keys cannot
|
||||
* accumulate.
|
||||
*
|
||||
* The assumeutxo loader assumes snapshot txids are valid while loading and verifies the
|
||||
* complete snapshot's content hash before activation.
|
||||
*
|
||||
* Hash values are process-local and must not be persisted, serialized, or compared across
|
||||
* processes.
|
||||
*
|
||||
* Having the hash noexcept lets libstdc++ recalculate it during rehash instead of storing it in
|
||||
* each node.
|
||||
*/
|
||||
class SaltedCoinsCacheHasher
|
||||
{
|
||||
const SipHasher13UJ m_hasher;
|
||||
|
||||
public:
|
||||
SaltedCoinsCacheHasher(bool deterministic = false);
|
||||
|
||||
/** 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
|
||||
{
|
||||
return m_hasher.Hash(id.hash.ToUint256(), uint64_t{id.n});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* PoolAllocator's MAX_BLOCK_SIZE_BYTES parameter here uses sizeof the data, and adds the size
|
||||
* of 4 pointers. We do not know the exact node size used in the std::unordered_node implementation
|
||||
@@ -229,7 +260,7 @@ public:
|
||||
*/
|
||||
using CCoinsMap = std::unordered_map<COutPoint,
|
||||
CCoinsCacheEntry,
|
||||
SaltedOutpointHasher,
|
||||
SaltedCoinsCacheHasher,
|
||||
std::equal_to<COutPoint>,
|
||||
PoolAllocator<CoinsCachePair,
|
||||
sizeof(CoinsCachePair) + sizeof(void*) * 4>>;
|
||||
|
||||
@@ -245,7 +245,7 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsViewCache& co
|
||||
sentinel.second.SelfRef(sentinel);
|
||||
size_t dirty_count{0};
|
||||
CCoinsMapMemoryResource resource;
|
||||
CCoinsMap coins_map{0, SaltedOutpointHasher{/*deterministic=*/true}, CCoinsMap::key_equal{}, &resource};
|
||||
CCoinsMap coins_map{0, SaltedCoinsCacheHasher{/*deterministic=*/true}, CCoinsMap::key_equal{}, &resource};
|
||||
LIMITED_WHILE (good_data && fuzzed_data_provider.ConsumeBool(), 10'000) {
|
||||
CCoinsCacheEntry coins_cache_entry;
|
||||
if (fuzzed_data_provider.ConsumeBool()) {
|
||||
|
||||
@@ -22,9 +22,9 @@ SaltedWtxidHasher::SaltedWtxidHasher() : m_hasher{
|
||||
FastRandomContext().rand64()}
|
||||
{}
|
||||
|
||||
SaltedOutpointHasher::SaltedOutpointHasher(bool deterministic) : m_hasher{
|
||||
deterministic ? 0x8e819f2607a18de6 : FastRandomContext().rand64(),
|
||||
deterministic ? 0xf4020d2e3983b0eb : FastRandomContext().rand64()}
|
||||
SaltedOutpointHasher::SaltedOutpointHasher() : m_hasher{
|
||||
FastRandomContext().rand64(),
|
||||
FastRandomContext().rand64()}
|
||||
{}
|
||||
|
||||
SaltedSipHasher::SaltedSipHasher() :
|
||||
|
||||
@@ -58,7 +58,7 @@ class SaltedOutpointHasher
|
||||
const PresaltedSipHasher m_hasher;
|
||||
|
||||
public:
|
||||
SaltedOutpointHasher(bool deterministic = false);
|
||||
SaltedOutpointHasher();
|
||||
|
||||
/**
|
||||
* Having the hash noexcept allows libstdc++'s unordered_map to recalculate
|
||||
|
||||
Reference in New Issue
Block a user