Skip to content

Commit 8ffaf5c

Browse files
committed
Merge #19935: Move SaltedHashers to separate file and add some new ones
281fd1a Replace KeyIDHasher with SaltedSipHasher (Andrew Chow) 210b693 Add generic SaltedSipHasher (Andrew Chow) 95e61c1 Move Hashers to util/hasher.{cpp/h} (Andrew Chow) Pull request description: There are existing `SaltedOutPointHasher` and `SaltedTxidHasher` classes used for `std::unordered_map` and `std::unordered_set` that could be useful in other places in the codebase. So we these to their own `saltedhash.{cpp/h}` file. An existing `KeyIDHasher` is moved there too. Additionally, `ScriptIDHasher`, `SaltedPubkeyHasher`, and `SaltedScriptHasher` are added so that they can be used in future work. `KeyIDHasher` and `ScriptIDHasher` are not salted so that equality comparisons of maps and sets keyed by `CKeyID` and `CScriptID` will actually work. Split from #19602 (and a few other PRs/branches I have). ACKs for top commit: laanwj: Code review ACK 281fd1a jonatack: ACK 281fd1a, code review, debug build and ran bitcoind after rebasing to master @ dff0f6f fjahr: utACK 281fd1a Tree-SHA512: bb03b231ccf3c9ecefc997b8da9c3770af4819f9be5b0a72997a103864e84046a2ac39b8eadf0dc9247bdccd53f86f433642e3a098882e6748341a9e7736271b
2 parents 7b97563 + 281fd1a commit 8ffaf5c

File tree

11 files changed

+126
-82
lines changed

11 files changed

+126
-82
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ BITCOIN_CORE_H = \
230230
util/error.h \
231231
util/fees.h \
232232
util/golombrice.h \
233+
util/hasher.h \
233234
util/macros.h \
234235
util/memory.h \
235236
util/message.h \
@@ -550,6 +551,7 @@ libbitcoin_util_a_SOURCES = \
550551
util/bytevectorhash.cpp \
551552
util/error.cpp \
552553
util/fees.cpp \
554+
util/hasher.cpp \
553555
util/system.cpp \
554556
util/message.cpp \
555557
util/moneystr.cpp \

src/coins.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock)
3131
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
3232
size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
3333

34-
SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
35-
3634
CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}
3735

3836
size_t CCoinsViewCache::DynamicMemoryUsage() const {

src/coins.h

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88

99
#include <compressor.h>
1010
#include <core_memusage.h>
11-
#include <crypto/siphash.h>
1211
#include <memusage.h>
1312
#include <primitives/transaction.h>
1413
#include <serialize.h>
1514
#include <uint256.h>
15+
#include <util/hasher.h>
1616

1717
#include <assert.h>
1818
#include <stdint.h>
@@ -82,33 +82,6 @@ class Coin
8282
}
8383
};
8484

85-
class SaltedOutpointHasher
86-
{
87-
private:
88-
/** Salt */
89-
const uint64_t k0, k1;
90-
91-
public:
92-
SaltedOutpointHasher();
93-
94-
/**
95-
* This *must* return size_t. With Boost 1.46 on 32-bit systems the
96-
* unordered_map will behave unpredictably if the custom hasher returns a
97-
* uint64_t, resulting in failures when syncing the chain (#4634).
98-
*
99-
* Having the hash noexcept allows libstdc++'s unordered_map to recalculate
100-
* the hash during rehash, so it does not have to cache the value. This
101-
* reduces node's memory by sizeof(size_t). The required recalculation has
102-
* a slight performance penalty (around 1.6%), but this is compensated by
103-
* memory savings of about 9% which allow for a larger dbcache setting.
104-
*
105-
* @see https://gcc.gnu.org/onlinedocs/gcc-9.2.0/libstdc++/manual/manual/unordered_associative.html
106-
*/
107-
size_t operator()(const COutPoint& id) const noexcept {
108-
return SipHashUint256Extra(k0, k1, id.hash, id.n);
109-
}
110-
};
111-
11285
/**
11386
* A Coin in one level of the coins database caching hierarchy.
11487
*

src/index/blockfilterindex.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,11 @@
99
#include <chain.h>
1010
#include <flatfile.h>
1111
#include <index/base.h>
12+
#include <util/hasher.h>
1213

1314
/** Interval between compact filter checkpoints. See BIP 157. */
1415
static constexpr int CFCHECKPT_INTERVAL = 1000;
1516

16-
struct FilterHeaderHasher
17-
{
18-
size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
19-
};
20-
2117
/**
2218
* BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of
2319
* blocks by height. An index is constructed for each supported filter type with its own database

src/script/sigcache.h

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <script/interpreter.h>
1010
#include <span.h>
11+
#include <util/hasher.h>
1112

1213
#include <vector>
1314

@@ -20,27 +21,6 @@ static const int64_t MAX_MAX_SIG_CACHE_SIZE = 16384;
2021

2122
class CPubKey;
2223

23-
/**
24-
* We're hashing a nonce into the entries themselves, so we don't need extra
25-
* blinding in the set hash computation.
26-
*
27-
* This may exhibit platform endian dependent behavior but because these are
28-
* nonced hashes (random) and this state is only ever used locally it is safe.
29-
* All that matters is local consistency.
30-
*/
31-
class SignatureCacheHasher
32-
{
33-
public:
34-
template <uint8_t hash_select>
35-
uint32_t operator()(const uint256& key) const
36-
{
37-
static_assert(hash_select <8, "SignatureCacheHasher only has 8 hashes available.");
38-
uint32_t u;
39-
std::memcpy(&u, key.begin()+4*hash_select, 4);
40-
return u;
41-
}
42-
};
43-
4424
class CachingTransactionSignatureChecker : public TransactionSignatureChecker
4525
{
4626
private:

src/txmempool.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,5 +1127,3 @@ CTxMemPool::EpochGuard::~EpochGuard()
11271127
++pool.m_epoch;
11281128
pool.m_has_epoch_guard = false;
11291129
}
1130-
1131-
SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}

src/txmempool.h

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515

1616
#include <amount.h>
1717
#include <coins.h>
18-
#include <crypto/siphash.h>
1918
#include <indirectmap.h>
2019
#include <optional.h>
2120
#include <policy/feerate.h>
2221
#include <primitives/transaction.h>
2322
#include <sync.h>
2423
#include <random.h>
24+
#include <util/hasher.h>
2525

2626
#include <boost/multi_index_container.hpp>
2727
#include <boost/multi_index/hashed_index.hpp>
@@ -398,20 +398,6 @@ enum class MemPoolRemovalReason {
398398
REPLACED, //!< Removed for replacement
399399
};
400400

401-
class SaltedTxidHasher
402-
{
403-
private:
404-
/** Salt */
405-
const uint64_t k0, k1;
406-
407-
public:
408-
SaltedTxidHasher();
409-
410-
size_t operator()(const uint256& txid) const {
411-
return SipHashUint256(k0, k1, txid);
412-
}
413-
};
414-
415401
/**
416402
* CTxMemPool stores valid-according-to-the-current-best-chain transactions
417403
* that may be included in the next block.

src/util/hasher.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) 2019 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <random.h>
6+
#include <util/hasher.h>
7+
8+
#include <limits>
9+
10+
SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
11+
12+
SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
13+
14+
SaltedSipHasher::SaltedSipHasher() : m_k0(GetRand(std::numeric_limits<uint64_t>::max())), m_k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
15+
16+
size_t SaltedSipHasher::operator()(const Span<const unsigned char>& script) const
17+
{
18+
return CSipHasher(m_k0, m_k1).Write(script.data(), script.size()).Finalize();
19+
}

src/util/hasher.h

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright (c) 2019 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_UTIL_HASHER_H
6+
#define BITCOIN_UTIL_HASHER_H
7+
8+
#include <crypto/siphash.h>
9+
#include <primitives/transaction.h>
10+
#include <uint256.h>
11+
12+
class SaltedTxidHasher
13+
{
14+
private:
15+
/** Salt */
16+
const uint64_t k0, k1;
17+
18+
public:
19+
SaltedTxidHasher();
20+
21+
size_t operator()(const uint256& txid) const {
22+
return SipHashUint256(k0, k1, txid);
23+
}
24+
};
25+
26+
class SaltedOutpointHasher
27+
{
28+
private:
29+
/** Salt */
30+
const uint64_t k0, k1;
31+
32+
public:
33+
SaltedOutpointHasher();
34+
35+
/**
36+
* This *must* return size_t. With Boost 1.46 on 32-bit systems the
37+
* unordered_map will behave unpredictably if the custom hasher returns a
38+
* uint64_t, resulting in failures when syncing the chain (#4634).
39+
*
40+
* Having the hash noexcept allows libstdc++'s unordered_map to recalculate
41+
* the hash during rehash, so it does not have to cache the value. This
42+
* reduces node's memory by sizeof(size_t). The required recalculation has
43+
* a slight performance penalty (around 1.6%), but this is compensated by
44+
* memory savings of about 9% which allow for a larger dbcache setting.
45+
*
46+
* @see https://gcc.gnu.org/onlinedocs/gcc-9.2.0/libstdc++/manual/manual/unordered_associative.html
47+
*/
48+
size_t operator()(const COutPoint& id) const noexcept {
49+
return SipHashUint256Extra(k0, k1, id.hash, id.n);
50+
}
51+
};
52+
53+
struct FilterHeaderHasher
54+
{
55+
size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
56+
};
57+
58+
/**
59+
* We're hashing a nonce into the entries themselves, so we don't need extra
60+
* blinding in the set hash computation.
61+
*
62+
* This may exhibit platform endian dependent behavior but because these are
63+
* nonced hashes (random) and this state is only ever used locally it is safe.
64+
* All that matters is local consistency.
65+
*/
66+
class SignatureCacheHasher
67+
{
68+
public:
69+
template <uint8_t hash_select>
70+
uint32_t operator()(const uint256& key) const
71+
{
72+
static_assert(hash_select <8, "SignatureCacheHasher only has 8 hashes available.");
73+
uint32_t u;
74+
std::memcpy(&u, key.begin()+4*hash_select, 4);
75+
return u;
76+
}
77+
};
78+
79+
struct BlockHasher
80+
{
81+
// this used to call `GetCheapHash()` in uint256, which was later moved; the
82+
// cheap hash function simply calls ReadLE64() however, so the end result is
83+
// identical
84+
size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
85+
};
86+
87+
class SaltedSipHasher
88+
{
89+
private:
90+
/** Salt */
91+
const uint64_t m_k0, m_k1;
92+
93+
public:
94+
SaltedSipHasher();
95+
96+
size_t operator()(const Span<const unsigned char>& script) const;
97+
};
98+
99+
#endif // BITCOIN_UTIL_HASHER_H

src/validation.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <txdb.h>
2424
#include <versionbits.h>
2525
#include <serialize.h>
26+
#include <util/hasher.h>
2627

2728
#include <atomic>
2829
#include <map>
@@ -93,14 +94,6 @@ static const unsigned int DEFAULT_CHECKLEVEL = 3;
9394
// Setting the target to >= 550 MiB will make it likely we can respect the target.
9495
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
9596

96-
struct BlockHasher
97-
{
98-
// this used to call `GetCheapHash()` in uint256, which was later moved; the
99-
// cheap hash function simply calls ReadLE64() however, so the end result is
100-
// identical
101-
size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
102-
};
103-
10497
/** Current sync state passed to tip changed callbacks. */
10598
enum class SynchronizationState {
10699
INIT_REINDEX,

0 commit comments

Comments
 (0)