refactor: Convert remaining instances from uint256 to Txid
What changed, and why it matters
This is a code cleanup change that replaces generic 256-bit hash values with more specific transaction ID types (Txid and Wtxid) across many files. It does not change what the program computes or how it protects data; it only makes the type names more precise so developers can catch category mistakes at compile time. There is no indication this fixes a security bug.
No security action required. Treat as normal refactoring; review only for accidental functional changes at the .ToUint256() boundaries if desired.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit completes a type-safety refactor: it removes remaining uses of uint256 where the value semantically represents a transaction identifier, substituting Txid or Wtxid, and adds SaltedUint256Hasher/SaltedWtxidHasher helpers. The underlying hashes, serialization, database keys, bloom filters, and network behavior remain identical because conversions such as .ToUint256() are inserted at the boundaries. No consensus, cryptography, or resource-handling logic is altered.
Changed components
src/blockencodings.cppsrc/consensus/merkle.cppsrc/headerssync.cpp/hsrc/index/txindex.cpp/hsrc/kernel/coinstats.cppsrc/kernel/disconnected_transactions.hsrc/net_processing.cppsrc/node/txdownloadman_impl.cppsrc/signet.cppsrc/txmempool.hsrc/util/hasher.cpp/hsrc/validation.cppsrc/wallet/spend.cppsrc/wallet/wallet.cppsrc/zmq/zmqpublishnotifier.cpptest filesInspect captured patch +117 / −69
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index 947f605d..3f61a122 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -42,7 +42,7 @@ void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const {
uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const Wtxid& wtxid) const {
static_assert(SHORTTXIDS_LENGTH == 6, "shorttxids calculation assumes 6-byte shorttxids");
- return SipHashUint256(shorttxidk0, shorttxidk1, wtxid) & 0xffffffffffffL;
+ return SipHashUint256(shorttxidk0, shorttxidk1, wtxid.ToUint256()) & 0xffffffffffffL;
}
ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<CTransactionRef>& extra_txn) {
diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp
index 7dd24e18..e274ed82 100644
--- a/src/consensus/merkle.cpp
+++ b/src/consensus/merkle.cpp
@@ -68,7 +68,7 @@ uint256 BlockMerkleRoot(const CBlock& block, bool* mutated)
std::vector<uint256> leaves;
leaves.resize(block.vtx.size());
for (size_t s = 0; s < block.vtx.size(); s++) {
- leaves[s] = block.vtx[s]->GetHash();
+ leaves[s] = block.vtx[s]->GetHash().ToUint256();
}
return ComputeMerkleRoot(std::move(leaves), mutated);
}
@@ -79,7 +79,7 @@ uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated)
leaves.resize(block.vtx.size());
leaves[0].SetNull(); // The witness hash of the coinbase is 0.
for (size_t s = 1; s < block.vtx.size(); s++) {
- leaves[s] = block.vtx[s]->GetWitnessHash();
+ leaves[s] = block.vtx[s]->GetWitnessHash().ToUint256();
}
return ComputeMerkleRoot(std::move(leaves), mutated);
}
@@ -185,7 +185,7 @@ std::vector<uint256> TransactionMerklePath(const CBlock& block, uint32_t positio
std::vector<uint256> leaves;
leaves.resize(block.vtx.size());
for (size_t s = 0; s < block.vtx.size(); s++) {
- leaves[s] = block.vtx[s]->GetHash();
+ leaves[s] = block.vtx[s]->GetHash().ToUint256();
}
return ComputeMerklePath(leaves, position);
}
diff --git a/src/headerssync.cpp b/src/headerssync.cpp
index 9e8b1905..fbe2026e 100644
--- a/src/headerssync.cpp
+++ b/src/headerssync.cpp
@@ -48,7 +48,7 @@ HeadersSyncState::HeadersSyncState(NodeId id, const Consensus::Params& consensus
/** Free any memory in use, and mark this object as no longer usable. This is
* required to guarantee that we won't reuse this object with the same
- * SaltedTxidHasher for another sync. */
+ * SaltedUint256Hasher for another sync. */
void HeadersSyncState::Finalize()
{
Assume(m_download_state != State::FINAL);
diff --git a/src/headerssync.h b/src/headerssync.h
index 2e7017f1..56380c66 100644
--- a/src/headerssync.h
+++ b/src/headerssync.h
@@ -224,7 +224,7 @@ private:
arith_uint256 m_current_chain_work;
/** m_hasher is a salted hasher for making our 1-bit commitments to headers we've seen. */
- const SaltedTxidHasher m_hasher;
+ const SaltedUint256Hasher m_hasher;
/** A queue of commitment bits, created during the 1st phase, and verified during the 2nd. */
bitdeque<> m_header_commitments;
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index 4bb6dc74..2a7c0066 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -9,6 +9,7 @@
#include <index/disktxpos.h>
#include <logging.h>
#include <node/blockstorage.h>
+#include <util/transaction_identifier.h>
#include <validation.h>
constexpr uint8_t DB_TXINDEX{'t'};
@@ -24,26 +25,26 @@ public:
/// Read the disk location of the transaction data with the given hash. Returns false if the
/// transaction hash is not indexed.
- bool ReadTxPos(const uint256& txid, CDiskTxPos& pos) const;
+ bool ReadTxPos(const Txid& txid, CDiskTxPos& pos) const;
/// Write a batch of transaction positions to the DB.
- [[nodiscard]] bool WriteTxs(const std::vector<std::pair<uint256, CDiskTxPos>>& v_pos);
+ [[nodiscard]] bool WriteTxs(const std::vector<std::pair<Txid, CDiskTxPos>>& v_pos);
};
TxIndex::DB::DB(size_t n_cache_size, bool f_memory, bool f_wipe) :
BaseIndex::DB(gArgs.GetDataDirNet() / "indexes" / "txindex", n_cache_size, f_memory, f_wipe)
{}
-bool TxIndex::DB::ReadTxPos(const uint256 &txid, CDiskTxPos& pos) const
+bool TxIndex::DB::ReadTxPos(const Txid& txid, CDiskTxPos& pos) const
{
- return Read(std::make_pair(DB_TXINDEX, txid), pos);
+ return Read(std::make_pair(DB_TXINDEX, txid.ToUint256()), pos);
}
-bool TxIndex::DB::WriteTxs(const std::vector<std::pair<uint256, CDiskTxPos>>& v_pos)
+bool TxIndex::DB::WriteTxs(const std::vector<std::pair<Txid, CDiskTxPos>>& v_pos)
{
CDBBatch batch(*this);
- for (const auto& tuple : v_pos) {
- batch.Write(std::make_pair(DB_TXINDEX, tuple.first), tuple.second);
+ for (const auto& [txid, pos] : v_pos) {
+ batch.Write(std::make_pair(DB_TXINDEX, txid.ToUint256()), pos);
}
return WriteBatch(batch);
}
@@ -61,7 +62,7 @@ bool TxIndex::CustomAppend(const interfaces::BlockInfo& block)
assert(block.data);
CDiskTxPos pos({block.file_number, block.data_pos}, GetSizeOfCompactSize(block.data->vtx.size()));
- std::vector<std::pair<uint256, CDiskTxPos>> vPos;
+ std::vector<std::pair<Txid, CDiskTxPos>> vPos;
vPos.reserve(block.data->vtx.size());
for (const auto& tx : block.data->vtx) {
vPos.emplace_back(tx->GetHash(), pos);
@@ -72,7 +73,7 @@ bool TxIndex::CustomAppend(const interfaces::BlockInfo& block)
BaseIndex::DB& TxIndex::GetDB() const { return *m_db; }
-bool TxIndex::FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRef& tx) const
+bool TxIndex::FindTx(const Txid& tx_hash, uint256& block_hash, CTransactionRef& tx) const
{
CDiskTxPos postx;
if (!m_db->ReadTxPos(tx_hash, postx)) {
diff --git a/src/index/txindex.h b/src/index/txindex.h
index ef835fe5..f8236c92 100644
--- a/src/index/txindex.h
+++ b/src/index/txindex.h
@@ -42,7 +42,7 @@ public:
/// @param[out] block_hash The hash of the block the transaction is found in.
/// @param[out] tx The transaction itself.
/// @return true if transaction is found, false otherwise
- bool FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRef& tx) const;
+ bool FindTx(const Txid& tx_hash, uint256& block_hash, CTransactionRef& tx) const;
};
/// The global transaction index, used in GetTransaction. May be null.
diff --git a/src/kernel/coinstats.cpp b/src/kernel/coinstats.cpp
index 81c496ab..6270f365 100644
--- a/src/kernel/coinstats.cpp
+++ b/src/kernel/coinstats.cpp
@@ -98,7 +98,7 @@ static void ApplyHash(T& hash_obj, const Txid& hash, const std::map<uint32_t, Co
}
}
-static void ApplyStats(CCoinsStats& stats, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
+static void ApplyStats(CCoinsStats& stats, const std::map<uint32_t, Coin>& outputs)
{
assert(!outputs.empty());
stats.nTransactions++;
@@ -126,7 +126,7 @@ static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, c
Coin coin;
if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
if (!outputs.empty() && key.hash != prevkey) {
- ApplyStats(stats, prevkey, outputs);
+ ApplyStats(stats, outputs);
ApplyHash(hash_obj, prevkey, outputs);
outputs.clear();
}
@@ -140,7 +140,7 @@ static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, c
pcursor->Next();
}
if (!outputs.empty()) {
- ApplyStats(stats, prevkey, outputs);
+ ApplyStats(stats, outputs);
ApplyHash(hash_obj, prevkey, outputs);
}
diff --git a/src/kernel/disconnected_transactions.h b/src/kernel/disconnected_transactions.h
index 401ec435..bc098f71 100644
--- a/src/kernel/disconnected_transactions.h
+++ b/src/kernel/disconnected_transactions.h
@@ -41,7 +41,7 @@ private:
const size_t m_max_mem_usage;
std::list<CTransactionRef> queuedTx;
using TxList = decltype(queuedTx);
- std::unordered_map<uint256, TxList::iterator, SaltedTxidHasher> iters_by_txid;
+ std::unordered_map<Txid, TxList::iterator, SaltedTxidHasher> iters_by_txid;
/** Trim the earliest-added entries until we are within memory bounds. */
std::vector<CTransactionRef> LimitMemoryUsage();
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 546e14b8..810627a1 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -3030,7 +3030,7 @@ std::optional<node::PackageToValidate> PeerManagerImpl::ProcessInvalidTx(NodeId
AddToCompactExtraTransactions(ptx);
}
for (const Txid& parent_txid : unique_parents) {
- if (peer) AddKnownTx(*peer, parent_txid);
+ if (peer) AddKnownTx(*peer, parent_txid.ToUint256());
}
MaybePunishNodeForTx(nodeid, state);
@@ -4280,12 +4280,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
CTransactionRef ptx;
vRecv >> TX_WITH_WITNESS(ptx);
- const CTransaction& tx = *ptx;
- const uint256& txid = ptx->GetHash();
- const uint256& wtxid = ptx->GetWitnessHash();
+ const Txid& txid = ptx->GetHash();
+ const Wtxid& wtxid = ptx->GetWitnessHash();
- const uint256& hash = peer->m_wtxid_relay ? wtxid : txid;
+ const uint256& hash = peer->m_wtxid_relay ? wtxid.ToUint256() : txid.ToUint256();
AddKnownTx(*peer, hash);
LOCK2(cs_main, m_tx_download_mutex);
@@ -4296,13 +4295,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Always relay transactions received from peers with forcerelay
// permission, even if they were already in the mempool, allowing
// the node to function as a gateway for nodes hidden behind it.
- if (!m_mempool.exists(tx.GetHash())) {
+ if (!m_mempool.exists(txid)) {
LogPrintf("Not relaying non-mempool transaction %s (wtxid=%s) from forcerelay peer=%d\n",
- tx.GetHash().ToString(), tx.GetWitnessHash().ToString(), pfrom.GetId());
+ txid.ToString(), wtxid.ToString(), pfrom.GetId());
} else {
LogPrintf("Force relaying tx %s (wtxid=%s) from peer=%d\n",
- tx.GetHash().ToString(), tx.GetWitnessHash().ToString(), pfrom.GetId());
- RelayTransaction(tx.GetHash(), tx.GetWitnessHash());
+ txid.ToString(), wtxid.ToString(), pfrom.GetId());
+ RelayTransaction(txid, wtxid);
}
}
diff --git a/src/node/txdownloadman_impl.cpp b/src/node/txdownloadman_impl.cpp
index 0105fe3d..91bc7f3b 100644
--- a/src/node/txdownloadman_impl.cpp
+++ b/src/node/txdownloadman_impl.cpp
@@ -104,8 +104,8 @@ void TxDownloadManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>&
if (ptx->HasWitness()) {
RecentConfirmedTransactionsFilter().insert(ptx->GetWitnessHash().ToUint256());
}
- m_txrequest.ForgetTxHash(ptx->GetHash());
- m_txrequest.ForgetTxHash(ptx->GetWitnessHash());
+ m_txrequest.ForgetTxHash(ptx->GetHash().ToUint256());
+ m_txrequest.ForgetTxHash(ptx->GetWitnessHash().ToUint256());
}
}
@@ -324,8 +324,8 @@ void TxDownloadManagerImpl::MempoolAcceptedTx(const CTransactionRef& tx)
{
// As this version of the transaction was acceptable, we can forget about any requests for it.
// No-op if the tx is not in txrequest.
- m_txrequest.ForgetTxHash(tx->GetHash());
- m_txrequest.ForgetTxHash(tx->GetWitnessHash());
+ m_txrequest.ForgetTxHash(tx->GetHash().ToUint256());
+ m_txrequest.ForgetTxHash(tx->GetWitnessHash().ToUint256());
m_orphanage->AddChildrenToWorkSet(*tx, m_opts.m_rng);
// If it came from the orphanage, remove it. No-op if the tx is not in txorphanage.
@@ -406,8 +406,8 @@ node::RejectedTxTodo TxDownloadManagerImpl::MempoolRejectedTx(const CTransaction
//
// Search by txid and, if the tx has a witness, wtxid
std::vector<NodeId> orphan_resolution_candidates{nodeid};
- m_txrequest.GetCandidatePeers(ptx->GetHash(), orphan_resolution_candidates);
- if (ptx->HasWitness()) m_txrequest.GetCandidatePeers(ptx->GetWitnessHash(), orphan_resolution_candidates);
+ m_txrequest.GetCandidatePeers(ptx->GetHash().ToUint256(), orphan_resolution_candidates);
+ if (ptx->HasWitness()) m_txrequest.GetCandidatePeers(ptx->GetWitnessHash().ToUint256(), orphan_resolution_candidates);
for (const auto& nodeid : orphan_resolution_candidates) {
if (MaybeAddOrphanResolutionCandidate(unique_parents, ptx->GetWitnessHash(), nodeid, now)) {
@@ -416,8 +416,8 @@ node::RejectedTxTodo TxDownloadManagerImpl::MempoolRejectedTx(const CTransaction
}
// Once added to the orphan pool, a tx is considered AlreadyHave, and we shouldn't request it anymore.
- m_txrequest.ForgetTxHash(tx.GetHash());
- m_txrequest.ForgetTxHash(tx.GetWitnessHash());
+ m_txrequest.ForgetTxHash(tx.GetHash().ToUint256());
+ m_txrequest.ForgetTxHash(tx.GetWitnessHash().ToUint256());
} else {
unique_parents.clear();
LogDebug(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n",
@@ -431,8 +431,8 @@ node::RejectedTxTodo TxDownloadManagerImpl::MempoolRejectedTx(const CTransaction
// from any of our non-wtxidrelay peers.
RecentRejectsFilter().insert(tx.GetHash().ToUint256());
RecentRejectsFilter().insert(tx.GetWitnessHash().ToUint256());
- m_txrequest.ForgetTxHash(tx.GetHash());
- m_txrequest.ForgetTxHash(tx.GetWitnessHash());
+ m_txrequest.ForgetTxHash(tx.GetHash().ToUint256());
+ m_txrequest.ForgetTxHash(tx.GetWitnessHash().ToUint256());
}
}
} else if (state.GetResult() == TxValidationResult::TX_WITNESS_STRIPPED) {
@@ -467,7 +467,7 @@ node::RejectedTxTodo TxDownloadManagerImpl::MempoolRejectedTx(const CTransaction
} else {
RecentRejectsFilter().insert(ptx->GetWitnessHash().ToUint256());
}
- m_txrequest.ForgetTxHash(ptx->GetWitnessHash());
+ m_txrequest.ForgetTxHash(ptx->GetWitnessHash().ToUint256());
// If the transaction failed for TX_INPUTS_NOT_STANDARD,
// then we know that the witness was irrelevant to the policy
// failure, since this check depends only on the txid
@@ -480,7 +480,7 @@ node::RejectedTxTodo TxDownloadManagerImpl::MempoolRejectedTx(const CTransaction
// rolling bloom filter.
if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && ptx->HasWitness()) {
RecentRejectsFilter().insert(ptx->GetHash().ToUint256());
- m_txrequest.ForgetTxHash(ptx->GetHash());
+ m_txrequest.ForgetTxHash(ptx->GetHash().ToUint256());
}
}
@@ -508,8 +508,8 @@ std::pair<bool, std::optional<PackageToValidate>> TxDownloadManagerImpl::Receive
const Wtxid& wtxid = ptx->GetWitnessHash();
// Mark that we have received a response
- m_txrequest.ReceivedResponse(nodeid, txid);
- if (ptx->HasWitness()) m_txrequest.ReceivedResponse(nodeid, wtxid);
+ m_txrequest.ReceivedResponse(nodeid, txid.ToUint256());
+ if (ptx->HasWitness()) m_txrequest.ReceivedResponse(nodeid, wtxid.ToUint256());
// First check if we should drop this tx.
// We do the AlreadyHaveTx() check using wtxid, rather than txid - in the
diff --git a/src/signet.cpp b/src/signet.cpp
index 45d279d2..742d03d9 100644
--- a/src/signet.cpp
+++ b/src/signet.cpp
@@ -59,9 +59,9 @@ static uint256 ComputeModifiedMerkleRoot(const CMutableTransaction& cb, const CB
{
std::vector<uint256> leaves;
leaves.resize(block.vtx.size());
- leaves[0] = cb.GetHash();
+ leaves[0] = cb.GetHash().ToUint256();
for (size_t s = 1; s < block.vtx.size(); ++s) {
- leaves[s] = block.vtx[s]->GetHash();
+ leaves[s] = block.vtx[s]->GetHash().ToUint256();
}
return ComputeMerkleRoot(std::move(leaves));
}
diff --git a/src/test/disconnected_transactions.cpp b/src/test/disconnected_transactions.cpp
index d4dc124b..7897e5f1 100644
--- a/src/test/disconnected_transactions.cpp
+++ b/src/test/disconnected_transactions.cpp
@@ -22,7 +22,7 @@ BOOST_AUTO_TEST_CASE(disconnectpool_memory_limits)
// is within an expected range.
// Overhead for the hashmap depends on number of buckets
- std::unordered_map<uint256, CTransaction*, SaltedTxidHasher> temp_map;
+ std::unordered_map<Txid, CTransaction*, SaltedTxidHasher> temp_map;
temp_map.reserve(1);
const size_t MAP_1{memusage::DynamicUsage(temp_map)};
temp_map.reserve(100);
diff --git a/src/test/fuzz/merkle.cpp b/src/test/fuzz/merkle.cpp
index 84055ac8..4bb91faf 100644
--- a/src/test/fuzz/merkle.cpp
+++ b/src/test/fuzz/merkle.cpp
@@ -19,7 +19,7 @@ uint256 ComputeMerkleRootFromPath(const CBlock& block, uint32_t position, const
throw std::out_of_range("Position out of range");
}
- uint256 current_hash = block.vtx[position]->GetHash();
+ uint256 current_hash = block.vtx[position]->GetHash().ToUint256();
for (const uint256& sibling : merkle_path) {
if (position % 2 == 0) {
@@ -47,7 +47,7 @@ FUZZ_TARGET(merkle)
tx_hashes.reserve(num_txs);
for (size_t i = 0; i < num_txs; ++i) {
- tx_hashes.push_back(block->vtx[i]->GetHash());
+ tx_hashes.push_back(block->vtx[i]->GetHash().ToUint256());
}
// Test ComputeMerkleRoot
diff --git a/src/test/fuzz/p2p_headers_presync.cpp b/src/test/fuzz/p2p_headers_presync.cpp
index a2c3a0f3..9aebac30 100644
--- a/src/test/fuzz/p2p_headers_presync.cpp
+++ b/src/test/fuzz/p2p_headers_presync.cpp
@@ -139,7 +139,7 @@ CBlock ConsumeBlock(FuzzedDataProvider& fuzzed_data_provider, const uint256& pre
tx.vout[0].nValue = 0;
tx.vin[0].scriptSig.resize(2);
block.vtx.push_back(MakeTransactionRef(tx));
- block.hashMerkleRoot = block.vtx[0]->GetHash();
+ block.hashMerkleRoot = block.vtx[0]->GetHash().ToUint256();
return block;
}
diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp
index f8cb0094..cad23321 100644
--- a/src/test/merkle_tests.cpp
+++ b/src/test/merkle_tests.cpp
@@ -29,7 +29,7 @@ static uint256 BlockBuildMerkleTree(const CBlock& block, bool* fMutated, std::ve
vMerkleTree.clear();
vMerkleTree.reserve(block.vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes.
for (std::vector<CTransactionRef>::const_iterator it(block.vtx.begin()); it != block.vtx.end(); ++it)
- vMerkleTree.push_back((*it)->GetHash());
+ vMerkleTree.push_back((*it)->GetHash().ToUint256());
int j = 0;
bool mutated = false;
for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
@@ -138,7 +138,7 @@ BOOST_AUTO_TEST_CASE(merkle_test)
std::vector<uint256> newBranch = TransactionMerklePath(block, mtx);
std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx);
BOOST_CHECK(oldBranch == newBranch);
- BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx]->GetHash(), newBranch, mtx) == oldRoot);
+ BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx]->GetHash().ToUint256(), newBranch, mtx) == oldRoot);
}
}
}
@@ -166,7 +166,7 @@ BOOST_AUTO_TEST_CASE(merkle_test_oneTx_block)
mtx.nLockTime = 0;
block.vtx[0] = MakeTransactionRef(std::move(mtx));
uint256 root = BlockMerkleRoot(block, &mutated);
- BOOST_CHECK_EQUAL(root, block.vtx[0]->GetHash());
+ BOOST_CHECK_EQUAL(root, block.vtx[0]->GetHash().ToUint256());
BOOST_CHECK_EQUAL(mutated, false);
}
@@ -239,7 +239,7 @@ BOOST_AUTO_TEST_CASE(merkle_test_BlockWitness)
std::vector<uint256> hashes;
hashes.resize(block.vtx.size());
hashes[0].SetNull();
- hashes[1] = block.vtx[1]->GetHash();
+ hashes[1] = block.vtx[1]->GetHash().ToUint256();
uint256 merkleRootofHashes = ComputeMerkleRoot(hashes);
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 76a42d19..0fc7991e 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -629,3 +629,11 @@ std::ostream& operator<<(std::ostream& os, const uint256& num)
{
return os << num.ToString();
}
+
+std::ostream& operator<<(std::ostream& os, const Txid& txid) {
+ return os << txid.ToString();
+}
+
+std::ostream& operator<<(std::ostream& os, const Wtxid& wtxid) {
+ return os << wtxid.ToString();
+}
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index 57bea908..150f5065 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -291,6 +291,8 @@ inline std::ostream& operator<<(std::ostream& os, const std::optional<T>& v)
std::ostream& operator<<(std::ostream& os, const arith_uint256& num);
std::ostream& operator<<(std::ostream& os, const uint160& num);
std::ostream& operator<<(std::ostream& os, const uint256& num);
+std::ostream& operator<<(std::ostream& os, const Txid& txid);
+std::ostream& operator<<(std::ostream& os, const Wtxid& wtxid);
// @}
/**
diff --git a/src/test/validation_tests.cpp b/src/test/validation_tests.cpp
index 7e86b3a3..5d4c3ee1 100644
--- a/src/test/validation_tests.cpp
+++ b/src/test/validation_tests.cpp
@@ -214,9 +214,9 @@ BOOST_AUTO_TEST_CASE(block_malleation)
// Block with a single coinbase tx is mutated if the merkle root is not
// equal to the coinbase tx's hash.
block.vtx.push_back(create_coinbase_tx());
- BOOST_CHECK(block.vtx[0]->GetHash() != block.hashMerkleRoot);
+ BOOST_CHECK(block.vtx[0]->GetHash().ToUint256() != block.hashMerkleRoot);
BOOST_CHECK(is_mutated(block, /*check_witness_root=*/false));
- block.hashMerkleRoot = block.vtx[0]->GetHash();
+ block.hashMerkleRoot = block.vtx[0]->GetHash().ToUint256();
BOOST_CHECK(is_not_mutated(block, /*check_witness_root=*/false));
// Block with two transactions is mutated if the merkle root does not
@@ -248,7 +248,7 @@ BOOST_AUTO_TEST_CASE(block_malleation)
mtx.vout.resize(1);
mtx.vout[0].scriptPubKey.resize(4);
block.vtx.push_back(MakeTransactionRef(mtx));
- block.hashMerkleRoot = block.vtx.back()->GetHash();
+ block.hashMerkleRoot = block.vtx.back()->GetHash().ToUint256();
assert(block.vtx.back()->IsCoinBase());
assert(GetSerializeSize(TX_NO_WITNESS(block.vtx.back())) == 64);
}
@@ -285,7 +285,7 @@ BOOST_AUTO_TEST_CASE(block_malleation)
HashWriter hasher;
hasher.write(tx1.GetHash());
hasher.write(tx2.GetHash());
- assert(hasher.GetHash() == tx3.GetHash());
+ assert(hasher.GetHash() == tx3.GetHash().ToUint256());
// Verify that tx3 is 64 bytes in size (without witness).
assert(GetSerializeSize(TX_NO_WITNESS(tx3)) == 64);
}
diff --git a/src/txmempool.h b/src/txmempool.h
index 8b55d9cd..5c81876a 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -313,7 +313,7 @@ public:
boost::multi_index::hashed_unique<
boost::multi_index::tag<index_by_wtxid>,
mempoolentry_wtxid,
- SaltedTxidHasher
+ SaltedWtxidHasher
>,
// sorted by fee rate
boost::multi_index::ordered_non_unique<
diff --git a/src/util/hasher.cpp b/src/util/hasher.cpp
index 117cfe8d..c4051ae0 100644
--- a/src/util/hasher.cpp
+++ b/src/util/hasher.cpp
@@ -7,10 +7,18 @@
#include <span.h>
#include <util/hasher.h>
+SaltedUint256Hasher::SaltedUint256Hasher() :
+ k0{FastRandomContext().rand64()},
+ k1{FastRandomContext().rand64()} {}
+
SaltedTxidHasher::SaltedTxidHasher() :
k0{FastRandomContext().rand64()},
k1{FastRandomContext().rand64()} {}
+SaltedWtxidHasher::SaltedWtxidHasher() :
+ k0{FastRandomContext().rand64()},
+ k1{FastRandomContext().rand64()} {}
+
SaltedOutpointHasher::SaltedOutpointHasher(bool deterministic) :
k0{deterministic ? 0x8e819f2607a18de6 : FastRandomContext().rand64()},
k1{deterministic ? 0xf4020d2e3983b0eb : FastRandomContext().rand64()}
diff --git a/src/util/hasher.h b/src/util/hasher.h
index 3a75c91a..be5d9eb1 100644
--- a/src/util/hasher.h
+++ b/src/util/hasher.h
@@ -11,9 +11,24 @@
#include <span.h>
#include <uint256.h>
+#include <concepts>
#include <cstdint>
#include <cstring>
+class SaltedUint256Hasher
+{
+private:
+ /** Salt */
+ const uint64_t k0, k1;
+
+public:
+ SaltedUint256Hasher();
+
+ size_t operator()(const uint256& hash) const {
+ return SipHashUint256(k0, k1, hash);
+ }
+};
+
class SaltedTxidHasher
{
private:
@@ -23,11 +38,26 @@ private:
public:
SaltedTxidHasher();
- size_t operator()(const uint256& txid) const {
- return SipHashUint256(k0, k1, txid);
+ size_t operator()(const Txid& txid) const {
+ return SipHashUint256(k0, k1, txid.ToUint256());
}
};
+class SaltedWtxidHasher
+{
+private:
+ /** Salt */
+ const uint64_t k0, k1;
+
+public:
+ SaltedWtxidHasher();
+
+ size_t operator()(const Wtxid& wtxid) const {
+ return SipHashUint256(k0, k1, wtxid.ToUint256());
+ }
+};
+
+
class SaltedOutpointHasher
{
private:
@@ -47,7 +77,7 @@ public:
* @see https://gcc.gnu.org/onlinedocs/gcc-13.2.0/libstdc++/manual/manual/unordered_associative.html
*/
size_t operator()(const COutPoint& id) const noexcept {
- return SipHashUint256Extra(k0, k1, id.hash, id.n);
+ return SipHashUint256Extra(k0, k1, id.hash.ToUint256(), id.n);
}
};
diff --git a/src/validation.cpp b/src/validation.cpp
index 0d68475a..91adbdff 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1275,7 +1275,7 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws)
AssertLockHeld(cs_main);
AssertLockHeld(m_pool.cs);
const CTransaction& tx = *ws.m_ptx;
- const uint256& hash = ws.m_hash;
+ const Txid& hash = ws.m_hash;
TxValidationState& state = ws.m_state;
// Check again against the current block tip's script verification
@@ -1322,7 +1322,7 @@ void MemPoolAccept::FinalizeSubpackage(const ATMPArgs& args)
const bool replaced_with_tx{m_subpackage.m_changeset->GetTxCount() == 1};
if (replaced_with_tx) {
const CTransaction& tx = m_subpackage.m_changeset->GetAddedTxn(0);
- tx_or_package_hash = tx.GetHash();
+ tx_or_package_hash = tx.GetHash().ToUint256();
log_string += strprintf("New tx %s (wtxid=%s, fees=%s, vsize=%s)",
tx.GetHash().ToString(),
tx.GetWitnessHash().ToString(),
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 250377af..4ae34d0b 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -327,7 +327,7 @@ CoinsResult AvailableCoins(const CWallet& wallet,
std::set<Txid> trusted_parents;
// Cache for whether each tx passes the tx level checks (first bool), and whether the transaction is "safe" (second bool)
- std::unordered_map<uint256, std::pair<bool, bool>, SaltedTxidHasher> tx_safe_cache;
+ std::unordered_map<Txid, std::pair<bool, bool>, SaltedTxidHasher> tx_safe_cache;
for (const auto& [outpoint, txo] : wallet.GetTXOs()) {
const CWalletTx& wtx = txo.GetWalletTx();
const CTxOut& output = txo.GetTxOut();
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 91a494c3..5e7bec48 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2319,7 +2319,7 @@ util::Result<void> CWallet::RemoveTxs(WalletBatch& batch, std::vector<Txid>& txs
for (const auto& txin : it->second.tx->vin)
mapTxSpends.erase(txin.prevout);
for (unsigned int i = 0; i < it->second.tx->vout.size(); ++i) {
- m_txos.erase(COutPoint(Txid::FromUint256(hash), i));
+ m_txos.erase(COutPoint(hash, i));
}
mapWallet.erase(it);
NotifyTransactionChanged(hash, CT_DELETED);
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index 1e7aa11c..693d70c8 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -230,7 +230,7 @@ bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
{
- uint256 hash = transaction.GetHash();
+ uint256 hash = transaction.GetHash().ToUint256();
LogDebug(BCLog::ZMQ, "Publish hashtx %s to %s\n", hash.GetHex(), this->address);
uint8_t data[32];
for (unsigned int i = 0; i < 32; i++) {
@@ -254,7 +254,7 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
{
- uint256 hash = transaction.GetHash();
+ uint256 hash = transaction.GetHash().ToUint256();
LogDebug(BCLog::ZMQ, "Publish rawtx %s to %s\n", hash.GetHex(), this->address);
DataStream ss;
ss << TX_WITH_WITNESS(transaction);
@@ -290,14 +290,14 @@ bool CZMQPublishSequenceNotifier::NotifyBlockDisconnect(const CBlockIndex *pinde
bool CZMQPublishSequenceNotifier::NotifyTransactionAcceptance(const CTransaction &transaction, uint64_t mempool_sequence)
{
- uint256 hash = transaction.GetHash();
+ uint256 hash = transaction.GetHash().ToUint256();
LogDebug(BCLog::ZMQ, "Publish hashtx mempool acceptance %s to %s\n", hash.GetHex(), this->address);
return SendSequenceMsg(*this, hash, /* Mempool (A)cceptance */ 'A', mempool_sequence);
}
bool CZMQPublishSequenceNotifier::NotifyTransactionRemoval(const CTransaction &transaction, uint64_t mempool_sequence)
{
- uint256 hash = transaction.GetHash();
+ uint256 hash = transaction.GetHash().ToUint256();
LogDebug(BCLog::ZMQ, "Publish hashtx mempool removal %s to %s\n", hash.GetHex(), this->address);
return SendSequenceMsg(*this, hash, /* Mempool (R)emoval */ 'R', mempool_sequence);
}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.