optimization: cache PresaltedSipHasher in CBlockHeaderAndShortTxIDs

Replaces separate `shorttxidk0`/`shorttxidk1` members with a cached `PresaltedSipHasher`, so `GetShortID()` reuses the precomputed `SipHash` state instead of rebuilding it on every call.

`CBlockHeaderAndShortTxIDs` was never intended to be used before `FillShortTxIDSelector()` runs; doing so already relied on indeterminate salt values.
The new `Assert(m_hasher)` just makes this invariant explicit and fails fast if the object is used in an uninitialized state.
This commit is contained in:
Lőrinc committed 2025-12-09 17:16:17 +01:00
1 parent 9ca52a4cbe
commit 118d22ddb4
2 files changed
+16 -13

No files matched your search

+13 -10
View File
@@ -17,11 +17,14 @@
#include <unordered_map> #include <unordered_map>
CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, const uint64_t nonce) : CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, uint64_t nonce)
nonce(nonce), : nonce(nonce),
shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) { shorttxids(block.vtx.size() - 1),
prefilledtxn(1),
header(block)
{
FillShortTxIDSelector(); FillShortTxIDSelector();
//TODO: Use our mempool prior to block acceptance to predictively fill more than just the coinbase // TODO: Use our mempool prior to block acceptance to predictively fill more than just the coinbase
prefilledtxn[0] = {0, block.vtx[0]}; prefilledtxn[0] = {0, block.vtx[0]};
for (size_t i = 1; i < block.vtx.size(); i++) { for (size_t i = 1; i < block.vtx.size(); i++) {
const CTransaction& tx = *block.vtx[i]; const CTransaction& tx = *block.vtx[i];
@@ -29,21 +32,21 @@ CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, const
} }
} }
void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const { void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const
{
DataStream stream{}; DataStream stream{};
stream << header << nonce; stream << header << nonce;
CSHA256 hasher; CSHA256 hasher;
hasher.Write((unsigned char*)&(*stream.begin()), stream.end() - stream.begin()); hasher.Write((unsigned char*)&(*stream.begin()), stream.end() - stream.begin());
uint256 shorttxidhash; uint256 shorttxidhash;
hasher.Finalize(shorttxidhash.begin()); hasher.Finalize(shorttxidhash.begin());
shorttxidk0 = shorttxidhash.GetUint64(0); m_hasher.emplace(shorttxidhash.GetUint64(0), shorttxidhash.GetUint64(1));
shorttxidk1 = shorttxidhash.GetUint64(1);
} }
uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const Wtxid& wtxid) const { uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const Wtxid& wtxid) const
{
static_assert(SHORTTXIDS_LENGTH == 6, "shorttxids calculation assumes 6-byte shorttxids"); static_assert(SHORTTXIDS_LENGTH == 6, "shorttxids calculation assumes 6-byte shorttxids");
PresaltedSipHasher hasher(shorttxidk0, shorttxidk1); // TODO extract return (*Assert(m_hasher))(wtxid.ToUint256()) & 0xffffffffffffL;
return hasher(wtxid.ToUint256()) & 0xffffffffffffL;
} }
/* Reconstructing a compact block is in the hot-path for block relay, /* Reconstructing a compact block is in the hot-path for block relay,
+3 -3
View File
@@ -5,6 +5,7 @@
#ifndef BITCOIN_BLOCKENCODINGS_H #ifndef BITCOIN_BLOCKENCODINGS_H
#define BITCOIN_BLOCKENCODINGS_H #define BITCOIN_BLOCKENCODINGS_H
#include <crypto/siphash.h>
#include <primitives/block.h> #include <primitives/block.h>
#include <functional> #include <functional>
@@ -87,8 +88,7 @@ typedef enum ReadStatus_t
} ReadStatus; } ReadStatus;
class CBlockHeaderAndShortTxIDs { class CBlockHeaderAndShortTxIDs {
private: mutable std::optional<PresaltedSipHasher> m_hasher;
mutable uint64_t shorttxidk0, shorttxidk1;
uint64_t nonce; uint64_t nonce;
void FillShortTxIDSelector() const; void FillShortTxIDSelector() const;
@@ -112,7 +112,7 @@ public:
/** /**
* @param[in] nonce This should be randomly generated, and is used for the siphash secret key * @param[in] nonce This should be randomly generated, and is used for the siphash secret key
*/ */
CBlockHeaderAndShortTxIDs(const CBlock& block, const uint64_t nonce); CBlockHeaderAndShortTxIDs(const CBlock& block, uint64_t nonce);
uint64_t GetShortID(const Wtxid& wtxid) const; uint64_t GetShortID(const Wtxid& wtxid) const;