This commit is contained in:
marcofleon 2025-04-29 11:53:03 +02:00 committed by GitHub
commit f568a92a03
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
95 changed files with 630 additions and 579 deletions

View file

@ -42,7 +42,7 @@ void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const {
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");
return SipHashUint256(shorttxidk0, shorttxidk1, wtxid) & 0xffffffffffffL; return SipHashUint256(shorttxidk0, shorttxidk1, wtxid.ToUint256()) & 0xffffffffffffL;
} }

View file

@ -68,7 +68,7 @@ uint256 BlockMerkleRoot(const CBlock& block, bool* mutated)
std::vector<uint256> leaves; std::vector<uint256> leaves;
leaves.resize(block.vtx.size()); leaves.resize(block.vtx.size());
for (size_t s = 0; s < block.vtx.size(); s++) { 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); return ComputeMerkleRoot(std::move(leaves), mutated);
} }
@ -79,7 +79,7 @@ uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated)
leaves.resize(block.vtx.size()); leaves.resize(block.vtx.size());
leaves[0].SetNull(); // The witness hash of the coinbase is 0. leaves[0].SetNull(); // The witness hash of the coinbase is 0.
for (size_t s = 1; s < block.vtx.size(); s++) { 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); return ComputeMerkleRoot(std::move(leaves), mutated);
} }
@ -185,7 +185,7 @@ std::vector<uint256> TransactionMerklePath(const CBlock& block, uint32_t positio
std::vector<uint256> leaves; std::vector<uint256> leaves;
leaves.resize(block.vtx.size()); leaves.resize(block.vtx.size());
for (size_t s = 0; s < block.vtx.size(); s++) { 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); return ComputeMerklePath(leaves, position);
} }

View file

@ -224,7 +224,7 @@ private:
arith_uint256 m_current_chain_work; arith_uint256 m_current_chain_work;
/** m_hasher is a salted hasher for making our 1-bit commitments to headers we've seen. */ /** 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. */ /** A queue of commitment bits, created during the 1st phase, and verified during the 2nd. */
bitdeque<> m_header_commitments; bitdeque<> m_header_commitments;

View file

@ -9,6 +9,7 @@
#include <index/disktxpos.h> #include <index/disktxpos.h>
#include <logging.h> #include <logging.h>
#include <node/blockstorage.h> #include <node/blockstorage.h>
#include <util/transaction_identifier.h>
#include <validation.h> #include <validation.h>
constexpr uint8_t DB_TXINDEX{'t'}; 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 /// Read the disk location of the transaction data with the given hash. Returns false if the
/// transaction hash is not indexed. /// 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. /// 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) : 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) 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); CDBBatch batch(*this);
for (const auto& tuple : v_pos) { for (const auto& tuple : v_pos) {
batch.Write(std::make_pair(DB_TXINDEX, tuple.first), tuple.second); batch.Write(std::make_pair(DB_TXINDEX, tuple.first.ToUint256()), tuple.second);
} }
return WriteBatch(batch); return WriteBatch(batch);
} }
@ -61,7 +62,7 @@ bool TxIndex::CustomAppend(const interfaces::BlockInfo& block)
assert(block.data); assert(block.data);
CDiskTxPos pos({block.file_number, block.data_pos}, GetSizeOfCompactSize(block.data->vtx.size())); 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()); vPos.reserve(block.data->vtx.size());
for (const auto& tx : block.data->vtx) { for (const auto& tx : block.data->vtx) {
vPos.emplace_back(tx->GetHash(), pos); 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; } 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; CDiskTxPos postx;
if (!m_db->ReadTxPos(tx_hash, postx)) { if (!m_db->ReadTxPos(tx_hash, postx)) {

View file

@ -42,7 +42,7 @@ public:
/// @param[out] block_hash The hash of the block the transaction is found in. /// @param[out] block_hash The hash of the block the transaction is found in.
/// @param[out] tx The transaction itself. /// @param[out] tx The transaction itself.
/// @return true if transaction is found, false otherwise /// @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. /// The global transaction index, used in GetTransaction. May be null.

View file

@ -207,10 +207,10 @@ public:
virtual RBFTransactionState isRBFOptIn(const CTransaction& tx) = 0; virtual RBFTransactionState isRBFOptIn(const CTransaction& tx) = 0;
//! Check if transaction is in mempool. //! Check if transaction is in mempool.
virtual bool isInMempool(const uint256& txid) = 0; virtual bool isInMempool(const Txid& txid) = 0;
//! Check if transaction has descendants in mempool. //! Check if transaction has descendants in mempool.
virtual bool hasDescendantsInMempool(const uint256& txid) = 0; virtual bool hasDescendantsInMempool(const Txid& txid) = 0;
//! Transaction is added to memory pool, if the transaction fee is below the //! Transaction is added to memory pool, if the transaction fee is below the
//! amount specified by max_tx_fee, and broadcast to all peers if relay is set to true. //! amount specified by max_tx_fee, and broadcast to all peers if relay is set to true.
@ -221,7 +221,7 @@ public:
std::string& err_string) = 0; std::string& err_string) = 0;
//! Calculate mempool ancestor and descendant counts for the given transaction. //! Calculate mempool ancestor and descendant counts for the given transaction.
virtual void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize = nullptr, CAmount* ancestorfees = nullptr) = 0; virtual void getTransactionAncestry(const Txid& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize = nullptr, CAmount* ancestorfees = nullptr) = 0;
//! For each outpoint, calculate the fee-bumping cost to spend this outpoint at the specified //! For each outpoint, calculate the fee-bumping cost to spend this outpoint at the specified
// feerate, including bumping its ancestors. For example, if the target feerate is 10sat/vbyte // feerate, including bumping its ancestors. For example, if the target feerate is 10sat/vbyte

View file

@ -159,16 +159,16 @@ public:
WalletOrderForm order_form) = 0; WalletOrderForm order_form) = 0;
//! Return whether transaction can be abandoned. //! Return whether transaction can be abandoned.
virtual bool transactionCanBeAbandoned(const uint256& txid) = 0; virtual bool transactionCanBeAbandoned(const Txid& txid) = 0;
//! Abandon transaction. //! Abandon transaction.
virtual bool abandonTransaction(const uint256& txid) = 0; virtual bool abandonTransaction(const Txid& txid) = 0;
//! Return whether transaction can be bumped. //! Return whether transaction can be bumped.
virtual bool transactionCanBeBumped(const uint256& txid) = 0; virtual bool transactionCanBeBumped(const Txid& txid) = 0;
//! Create bump transaction. //! Create bump transaction.
virtual bool createBumpTransaction(const uint256& txid, virtual bool createBumpTransaction(const Txid& txid,
const wallet::CCoinControl& coin_control, const wallet::CCoinControl& coin_control,
std::vector<bilingual_str>& errors, std::vector<bilingual_str>& errors,
CAmount& old_fee, CAmount& old_fee,
@ -179,28 +179,28 @@ public:
virtual bool signBumpTransaction(CMutableTransaction& mtx) = 0; virtual bool signBumpTransaction(CMutableTransaction& mtx) = 0;
//! Commit bump transaction. //! Commit bump transaction.
virtual bool commitBumpTransaction(const uint256& txid, virtual bool commitBumpTransaction(const Txid& txid,
CMutableTransaction&& mtx, CMutableTransaction&& mtx,
std::vector<bilingual_str>& errors, std::vector<bilingual_str>& errors,
uint256& bumped_txid) = 0; Txid& bumped_txid) = 0;
//! Get a transaction. //! Get a transaction.
virtual CTransactionRef getTx(const uint256& txid) = 0; virtual CTransactionRef getTx(const Txid& txid) = 0;
//! Get transaction information. //! Get transaction information.
virtual WalletTx getWalletTx(const uint256& txid) = 0; virtual WalletTx getWalletTx(const Txid& txid) = 0;
//! Get list of all wallet transactions. //! Get list of all wallet transactions.
virtual std::set<WalletTx> getWalletTxs() = 0; virtual std::set<WalletTx> getWalletTxs() = 0;
//! Try to get updated status for a particular transaction, if possible without blocking. //! Try to get updated status for a particular transaction, if possible without blocking.
virtual bool tryGetTxStatus(const uint256& txid, virtual bool tryGetTxStatus(const Txid& txid,
WalletTxStatus& tx_status, WalletTxStatus& tx_status,
int& num_blocks, int& num_blocks,
int64_t& block_time) = 0; int64_t& block_time) = 0;
//! Get transaction details. //! Get transaction details.
virtual WalletTx getWalletTxDetails(const uint256& txid, virtual WalletTx getWalletTxDetails(const Txid& txid,
WalletTxStatus& tx_status, WalletTxStatus& tx_status,
WalletOrderForm& order_form, WalletOrderForm& order_form,
bool& in_mempool, bool& in_mempool,
@ -306,7 +306,7 @@ public:
virtual std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) = 0; virtual std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) = 0;
//! Register handler for transaction changed messages. //! Register handler for transaction changed messages.
using TransactionChangedFn = std::function<void(const uint256& txid, ChangeType status)>; using TransactionChangedFn = std::function<void(const Txid& txid, ChangeType status)>;
virtual std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) = 0; virtual std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) = 0;
//! Register handler for watchonly changed messages. //! Register handler for watchonly changed messages.

View file

@ -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()); assert(!outputs.empty());
stats.nTransactions++; stats.nTransactions++;
@ -126,7 +126,7 @@ static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, c
Coin coin; Coin coin;
if (pcursor->GetKey(key) && pcursor->GetValue(coin)) { if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
if (!outputs.empty() && key.hash != prevkey) { if (!outputs.empty() && key.hash != prevkey) {
ApplyStats(stats, prevkey, outputs); ApplyStats(stats, outputs);
ApplyHash(hash_obj, prevkey, outputs); ApplyHash(hash_obj, prevkey, outputs);
outputs.clear(); outputs.clear();
} }
@ -140,7 +140,7 @@ static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, c
pcursor->Next(); pcursor->Next();
} }
if (!outputs.empty()) { if (!outputs.empty()) {
ApplyStats(stats, prevkey, outputs); ApplyStats(stats, outputs);
ApplyHash(hash_obj, prevkey, outputs); ApplyHash(hash_obj, prevkey, outputs);
} }

View file

@ -41,7 +41,7 @@ private:
const size_t m_max_mem_usage; const size_t m_max_mem_usage;
std::list<CTransactionRef> queuedTx; std::list<CTransactionRef> queuedTx;
using TxList = decltype(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. */ /** Trim the earliest-added entries until we are within memory bounds. */
std::vector<CTransactionRef> LimitMemoryUsage(); std::vector<CTransactionRef> LimitMemoryUsage();

View file

@ -44,11 +44,11 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std:
vMatch.push_back(true); vMatch.push_back(true);
} else if (filter && filter->IsRelevantAndUpdate(*block.vtx[i])) { } else if (filter && filter->IsRelevantAndUpdate(*block.vtx[i])) {
vMatch.push_back(true); vMatch.push_back(true);
vMatchedTxn.emplace_back(i, hash); vMatchedTxn.emplace_back(i, hash.ToUint256());
} else { } else {
vMatch.push_back(false); vMatch.push_back(false);
} }
vHashes.push_back(hash); vHashes.push_back(hash.ToUint256());
} }
txn = CPartialMerkleTree(vHashes, vMatch); txn = CPartialMerkleTree(vHashes, vMatch);

View file

@ -302,7 +302,7 @@ struct Peer {
* non-wtxid-relay peers, wtxid for wtxid-relay peers). We use the * non-wtxid-relay peers, wtxid for wtxid-relay peers). We use the
* mempool to sort transactions in dependency order before relay, so * mempool to sort transactions in dependency order before relay, so
* this does not have to be sorted. */ * this does not have to be sorted. */
std::set<uint256> m_tx_inventory_to_send GUARDED_BY(m_tx_inventory_mutex); std::set<GenTxid> m_tx_inventory_to_send GUARDED_BY(m_tx_inventory_mutex);
/** Whether the peer has requested us to send our complete mempool. Only /** Whether the peer has requested us to send our complete mempool. Only
* permitted if the peer has NetPermissionFlags::Mempool or we advertise * permitted if the peer has NetPermissionFlags::Mempool or we advertise
* NODE_BLOOM. See BIP35. */ * NODE_BLOOM. See BIP35. */
@ -536,7 +536,7 @@ public:
std::vector<TxOrphanage::OrphanTxBase> GetOrphanTransactions() override EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex); std::vector<TxOrphanage::OrphanTxBase> GetOrphanTransactions() override EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex);
PeerManagerInfo GetInfo() const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); PeerManagerInfo GetInfo() const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void SendPings() override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void SendPings() override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void RelayTransaction(const uint256& txid, const uint256& wtxid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void RelayTransaction(const Txid& txid, const Wtxid& wtxid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void SetBestBlock(int height, std::chrono::seconds time) override void SetBestBlock(int height, std::chrono::seconds time) override
{ {
m_best_height = height; m_best_height = height;
@ -856,7 +856,7 @@ private:
std::shared_ptr<const CBlock> m_most_recent_block GUARDED_BY(m_most_recent_block_mutex); std::shared_ptr<const CBlock> m_most_recent_block GUARDED_BY(m_most_recent_block_mutex);
std::shared_ptr<const CBlockHeaderAndShortTxIDs> m_most_recent_compact_block GUARDED_BY(m_most_recent_block_mutex); std::shared_ptr<const CBlockHeaderAndShortTxIDs> m_most_recent_compact_block GUARDED_BY(m_most_recent_block_mutex);
uint256 m_most_recent_block_hash GUARDED_BY(m_most_recent_block_mutex); uint256 m_most_recent_block_hash GUARDED_BY(m_most_recent_block_mutex);
std::unique_ptr<const std::map<uint256, CTransactionRef>> m_most_recent_block_txs GUARDED_BY(m_most_recent_block_mutex); std::unique_ptr<const std::map<GenTxid, CTransactionRef>> m_most_recent_block_txs GUARDED_BY(m_most_recent_block_mutex);
// Data about the low-work headers synchronization, aggregated from all peers' HeadersSyncStates. // Data about the low-work headers synchronization, aggregated from all peers' HeadersSyncStates.
/** Mutex guarding the other m_headers_presync_* variables. */ /** Mutex guarding the other m_headers_presync_* variables. */
@ -1575,7 +1575,7 @@ void PeerManagerImpl::InitializeNode(const CNode& node, ServiceFlags our_service
void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler) void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler)
{ {
std::set<uint256> unbroadcast_txids = m_mempool.GetUnbroadcastTxs(); std::set<Txid> unbroadcast_txids = m_mempool.GetUnbroadcastTxs();
for (const auto& txid : unbroadcast_txids) { for (const auto& txid : unbroadcast_txids) {
CTransactionRef tx = m_mempool.get(txid); CTransactionRef tx = m_mempool.get(txid);
@ -2025,7 +2025,7 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha
std::async(std::launch::deferred, [&] { return NetMsg::Make(NetMsgType::CMPCTBLOCK, *pcmpctblock); })}; std::async(std::launch::deferred, [&] { return NetMsg::Make(NetMsgType::CMPCTBLOCK, *pcmpctblock); })};
{ {
auto most_recent_block_txs = std::make_unique<std::map<uint256, CTransactionRef>>(); auto most_recent_block_txs = std::make_unique<std::map<GenTxid, CTransactionRef>>();
for (const auto& tx : pblock->vtx) { for (const auto& tx : pblock->vtx) {
most_recent_block_txs->emplace(tx->GetHash(), tx); most_recent_block_txs->emplace(tx->GetHash(), tx);
most_recent_block_txs->emplace(tx->GetWitnessHash(), tx); most_recent_block_txs->emplace(tx->GetWitnessHash(), tx);
@ -2148,7 +2148,7 @@ void PeerManagerImpl::SendPings()
for(auto& it : m_peer_map) it.second->m_ping_queued = true; for(auto& it : m_peer_map) it.second->m_ping_queued = true;
} }
void PeerManagerImpl::RelayTransaction(const uint256& txid, const uint256& wtxid) void PeerManagerImpl::RelayTransaction(const Txid& txid, const Wtxid& wtxid)
{ {
LOCK(m_peer_mutex); LOCK(m_peer_mutex);
for(auto& it : m_peer_map) { for(auto& it : m_peer_map) {
@ -2164,11 +2164,17 @@ void PeerManagerImpl::RelayTransaction(const uint256& txid, const uint256& wtxid
// in the announcement. // in the announcement.
if (tx_relay->m_next_inv_send_time == 0s) continue; if (tx_relay->m_next_inv_send_time == 0s) continue;
const uint256& hash{peer.m_wtxid_relay ? wtxid : txid}; GenTxid gtxid;
if (!tx_relay->m_tx_inventory_known_filter.contains(hash)) { if (peer.m_wtxid_relay) {
tx_relay->m_tx_inventory_to_send.insert(hash); gtxid = wtxid;
} else {
gtxid = txid;
} }
};
if (!tx_relay->m_tx_inventory_known_filter.contains(gtxid.ToUint256())) {
tx_relay->m_tx_inventory_to_send.insert(gtxid);
}
}
} }
void PeerManagerImpl::RelayAddress(NodeId originator, void PeerManagerImpl::RelayAddress(NodeId originator,
@ -2401,7 +2407,7 @@ CTransactionRef PeerManagerImpl::FindTxForGetData(const Peer::TxRelay& tx_relay,
{ {
LOCK(m_most_recent_block_mutex); LOCK(m_most_recent_block_mutex);
if (m_most_recent_block_txs != nullptr) { if (m_most_recent_block_txs != nullptr) {
auto it = m_most_recent_block_txs->find(gtxid.GetHash()); auto it = m_most_recent_block_txs->find(gtxid);
if (it != m_most_recent_block_txs->end()) return it->second; if (it != m_most_recent_block_txs->end()) return it->second;
} }
} }
@ -3016,7 +3022,7 @@ std::optional<node::PackageToValidate> PeerManagerImpl::ProcessInvalidTx(NodeId
AddToCompactExtraTransactions(ptx); AddToCompactExtraTransactions(ptx);
} }
for (const Txid& parent_txid : unique_parents) { for (const Txid& parent_txid : unique_parents) {
if (peer) AddKnownTx(*peer, parent_txid); if (peer) AddKnownTx(*peer, parent_txid.ToUint256());
} }
MaybePunishNodeForTx(nodeid, state); MaybePunishNodeForTx(nodeid, state);
@ -4252,12 +4258,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
CTransactionRef ptx; CTransactionRef ptx;
vRecv >> TX_WITH_WITNESS(ptx); vRecv >> TX_WITH_WITNESS(ptx);
const CTransaction& tx = *ptx;
const uint256& txid = ptx->GetHash(); const Txid& txid = ptx->GetHash();
const uint256& wtxid = ptx->GetWitnessHash(); 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); AddKnownTx(*peer, hash);
LOCK2(cs_main, m_tx_download_mutex); LOCK2(cs_main, m_tx_download_mutex);
@ -4268,13 +4273,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Always relay transactions received from peers with forcerelay // Always relay transactions received from peers with forcerelay
// permission, even if they were already in the mempool, allowing // permission, even if they were already in the mempool, allowing
// the node to function as a gateway for nodes hidden behind it. // the node to function as a gateway for nodes hidden behind it.
if (!m_mempool.exists(GenTxid::Txid(tx.GetHash()))) { if (!m_mempool.exists(txid)) {
LogPrintf("Not relaying non-mempool transaction %s (wtxid=%s) from forcerelay peer=%d\n", 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 { } else {
LogPrintf("Force relaying tx %s (wtxid=%s) from peer=%d\n", LogPrintf("Force relaying tx %s (wtxid=%s) from peer=%d\n",
tx.GetHash().ToString(), tx.GetWitnessHash().ToString(), pfrom.GetId()); txid.ToString(), wtxid.ToString(), pfrom.GetId());
RelayTransaction(tx.GetHash(), tx.GetWitnessHash()); RelayTransaction(txid, wtxid);
} }
} }
@ -4901,11 +4906,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (msg_type == NetMsgType::NOTFOUND) { if (msg_type == NetMsgType::NOTFOUND) {
std::vector<CInv> vInv; std::vector<CInv> vInv;
vRecv >> vInv; vRecv >> vInv;
std::vector<uint256> tx_invs; std::vector<GenTxid> tx_invs;
if (vInv.size() <= node::MAX_PEER_TX_ANNOUNCEMENTS + MAX_BLOCKS_IN_TRANSIT_PER_PEER) { if (vInv.size() <= node::MAX_PEER_TX_ANNOUNCEMENTS + MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
for (CInv &inv : vInv) { for (CInv &inv : vInv) {
if (inv.IsGenTxMsg()) { if (inv.IsGenTxMsg()) {
tx_invs.emplace_back(inv.hash); tx_invs.emplace_back(ToGenTxid(inv));
} }
} }
} }
@ -5406,19 +5411,17 @@ namespace {
class CompareInvMempoolOrder class CompareInvMempoolOrder
{ {
CTxMemPool* mp; CTxMemPool* mp;
bool m_wtxid_relay;
public: public:
explicit CompareInvMempoolOrder(CTxMemPool *_mempool, bool use_wtxid) explicit CompareInvMempoolOrder(CTxMemPool *_mempool)
{ {
mp = _mempool; mp = _mempool;
m_wtxid_relay = use_wtxid;
} }
bool operator()(std::set<uint256>::iterator a, std::set<uint256>::iterator b) bool operator()(std::set<GenTxid>::iterator a, std::set<GenTxid>::iterator b)
{ {
/* As std::make_heap produces a max-heap, we want the entries with the /* As std::make_heap produces a max-heap, we want the entries with the
* fewest ancestors/highest fee to sort later. */ * fewest ancestors/highest fee to sort later. */
return mp->CompareDepthAndScore(*b, *a, m_wtxid_relay); return mp->CompareDepthAndScore(*b, *a);
} }
}; };
} // namespace } // namespace
@ -5736,7 +5739,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
txinfo.tx->GetWitnessHash().ToUint256() : txinfo.tx->GetWitnessHash().ToUint256() :
txinfo.tx->GetHash().ToUint256(), txinfo.tx->GetHash().ToUint256(),
}; };
tx_relay->m_tx_inventory_to_send.erase(inv.hash); tx_relay->m_tx_inventory_to_send.erase(ToGenTxid(inv));
// Don't send transactions that peers will not put into their mempool // Don't send transactions that peers will not put into their mempool
if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) { if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
@ -5757,15 +5760,15 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Determine transactions to relay // Determine transactions to relay
if (fSendTrickle) { if (fSendTrickle) {
// Produce a vector with all candidates for sending // Produce a vector with all candidates for sending
std::vector<std::set<uint256>::iterator> vInvTx; std::vector<std::set<GenTxid>::iterator> vInvTx;
vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size()); vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size());
for (std::set<uint256>::iterator it = tx_relay->m_tx_inventory_to_send.begin(); it != tx_relay->m_tx_inventory_to_send.end(); it++) { for (std::set<GenTxid>::iterator it = tx_relay->m_tx_inventory_to_send.begin(); it != tx_relay->m_tx_inventory_to_send.end(); it++) {
vInvTx.push_back(it); vInvTx.push_back(it);
} }
const CFeeRate filterrate{tx_relay->m_fee_filter_received.load()}; const CFeeRate filterrate{tx_relay->m_fee_filter_received.load()};
// Topologically and fee-rate sort the inventory we send for privacy and priority reasons. // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
// A heap is used so that not all items need sorting if only a few are being sent. // A heap is used so that not all items need sorting if only a few are being sent.
CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool, peer->m_wtxid_relay); CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool);
std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder); std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
// No reason to drain out at many times the network's capacity, // No reason to drain out at many times the network's capacity,
// especially since we have many peers and some will draw much shorter delays. // especially since we have many peers and some will draw much shorter delays.
@ -5776,14 +5779,14 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
while (!vInvTx.empty() && nRelayedTransactions < broadcast_max) { while (!vInvTx.empty() && nRelayedTransactions < broadcast_max) {
// Fetch the top element from the heap // Fetch the top element from the heap
std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder); std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
std::set<uint256>::iterator it = vInvTx.back(); std::set<GenTxid>::iterator it = vInvTx.back();
vInvTx.pop_back(); vInvTx.pop_back();
uint256 hash = *it; GenTxid hash = *it;
CInv inv(peer->m_wtxid_relay ? MSG_WTX : MSG_TX, hash); CInv inv(peer->m_wtxid_relay ? MSG_WTX : MSG_TX, hash.ToUint256());
// Remove it from the to-be-sent set // Remove it from the to-be-sent set
tx_relay->m_tx_inventory_to_send.erase(it); tx_relay->m_tx_inventory_to_send.erase(it);
// Check if not in the filter already // Check if not in the filter already
if (tx_relay->m_tx_inventory_known_filter.contains(hash)) { if (tx_relay->m_tx_inventory_known_filter.contains(hash.ToUint256())) {
continue; continue;
} }
// Not in the mempool anymore? don't bother sending it. // Not in the mempool anymore? don't bother sending it.
@ -5803,7 +5806,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
MakeAndPushMessage(*pto, NetMsgType::INV, vInv); MakeAndPushMessage(*pto, NetMsgType::INV, vInv);
vInv.clear(); vInv.clear();
} }
tx_relay->m_tx_inventory_known_filter.insert(hash); tx_relay->m_tx_inventory_known_filter.insert(hash.ToUint256());
} }
// Ensure we'll respond to GETDATA requests for anything we've just announced // Ensure we'll respond to GETDATA requests for anything we've just announced
@ -5926,7 +5929,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
{ {
LOCK(m_tx_download_mutex); LOCK(m_tx_download_mutex);
for (const GenTxid& gtxid : m_txdownloadman.GetRequestsToSend(pto->GetId(), current_time)) { for (const GenTxid& gtxid : m_txdownloadman.GetRequestsToSend(pto->GetId(), current_time)) {
vGetData.emplace_back(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*peer)), gtxid.GetHash()); vGetData.emplace_back(std::holds_alternative<Wtxid>(gtxid) ? MSG_WTX : (MSG_TX | GetFetchFlags(*peer)), gtxid.ToUint256());
if (vGetData.size() >= MAX_GETDATA_SZ) { if (vGetData.size() >= MAX_GETDATA_SZ) {
MakeAndPushMessage(*pto, NetMsgType::GETDATA, vGetData); MakeAndPushMessage(*pto, NetMsgType::GETDATA, vGetData);
vGetData.clear(); vGetData.clear();

View file

@ -119,7 +119,7 @@ public:
virtual PeerManagerInfo GetInfo() const = 0; virtual PeerManagerInfo GetInfo() const = 0;
/** Relay transaction to all peers. */ /** Relay transaction to all peers. */
virtual void RelayTransaction(const uint256& txid, const uint256& wtxid) = 0; virtual void RelayTransaction(const Txid& txid, const Wtxid& wtxid) = 0;
/** Send ping message to all peers */ /** Send ping message to all peers */
virtual void SendPings() = 0; virtual void SendPings() = 0;

View file

@ -669,17 +669,17 @@ public:
LOCK(m_node.mempool->cs); LOCK(m_node.mempool->cs);
return IsRBFOptIn(tx, *m_node.mempool); return IsRBFOptIn(tx, *m_node.mempool);
} }
bool isInMempool(const uint256& txid) override bool isInMempool(const Txid& txid) override
{ {
if (!m_node.mempool) return false; if (!m_node.mempool) return false;
LOCK(m_node.mempool->cs); LOCK(m_node.mempool->cs);
return m_node.mempool->exists(GenTxid::Txid(txid)); return m_node.mempool->exists(txid);
} }
bool hasDescendantsInMempool(const uint256& txid) override bool hasDescendantsInMempool(const Txid& txid) override
{ {
if (!m_node.mempool) return false; if (!m_node.mempool) return false;
LOCK(m_node.mempool->cs); LOCK(m_node.mempool->cs);
const auto entry{m_node.mempool->GetEntry(Txid::FromUint256(txid))}; const auto entry{m_node.mempool->GetEntry(txid)};
if (entry == nullptr) return false; if (entry == nullptr) return false;
return entry->GetCountWithDescendants() > 1; return entry->GetCountWithDescendants() > 1;
} }
@ -694,7 +694,7 @@ public:
// that Chain clients do not need to know about. // that Chain clients do not need to know about.
return TransactionError::OK == err; return TransactionError::OK == err;
} }
void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize, CAmount* ancestorfees) override void getTransactionAncestry(const Txid& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize, CAmount* ancestorfees) override
{ {
ancestors = descendants = 0; ancestors = descendants = 0;
if (!m_node.mempool) return; if (!m_node.mempool) return;

View file

@ -106,7 +106,7 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active
// wallet(s) having loaded it while we were processing // wallet(s) having loaded it while we were processing
// mempool transactions; consider these as valid, instead of // mempool transactions; consider these as valid, instead of
// failed, but mark them as 'already there' // failed, but mark them as 'already there'
if (pool.exists(GenTxid::Txid(tx->GetHash()))) { if (pool.exists(tx->GetHash())) {
++already_there; ++already_there;
} else { } else {
++failed; ++failed;
@ -118,7 +118,7 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active
if (active_chainstate.m_chainman.m_interrupt) if (active_chainstate.m_chainman.m_interrupt)
return false; return false;
} }
std::map<uint256, CAmount> mapDeltas; std::map<Txid, CAmount> mapDeltas;
file >> mapDeltas; file >> mapDeltas;
if (opts.apply_fee_delta_priority) { if (opts.apply_fee_delta_priority) {
@ -127,7 +127,7 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active
} }
} }
std::set<uint256> unbroadcast_txids; std::set<Txid> unbroadcast_txids;
file >> unbroadcast_txids; file >> unbroadcast_txids;
if (opts.apply_unbroadcast_set) { if (opts.apply_unbroadcast_set) {
unbroadcast = unbroadcast_txids.size(); unbroadcast = unbroadcast_txids.size();
@ -150,9 +150,9 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mock
{ {
auto start = SteadyClock::now(); auto start = SteadyClock::now();
std::map<uint256, CAmount> mapDeltas; std::map<Txid, CAmount> mapDeltas;
std::vector<TxMempoolInfo> vinfo; std::vector<TxMempoolInfo> vinfo;
std::set<uint256> unbroadcast_txids; std::set<Txid> unbroadcast_txids;
static Mutex dump_mutex; static Mutex dump_mutex;
LOCK(dump_mutex); LOCK(dump_mutex);

View file

@ -27,7 +27,7 @@ MiniMiner::MiniMiner(const CTxMemPool& mempool, const std::vector<COutPoint>& ou
// Anything that's spent by the mempool is to-be-replaced // Anything that's spent by the mempool is to-be-replaced
// Anything otherwise unavailable just has a bump fee of 0 // Anything otherwise unavailable just has a bump fee of 0
for (const auto& outpoint : outpoints) { for (const auto& outpoint : outpoints) {
if (!mempool.exists(GenTxid::Txid(outpoint.hash))) { if (!mempool.exists(outpoint.hash)) {
// This UTXO is either confirmed or not yet submitted to mempool. // This UTXO is either confirmed or not yet submitted to mempool.
// If it's confirmed, no bump fee is required. // If it's confirmed, no bump fee is required.
// If it's not yet submitted, we have no information, so return 0. // If it's not yet submitted, we have no information, so return 0.
@ -61,7 +61,7 @@ MiniMiner::MiniMiner(const CTxMemPool& mempool, const std::vector<COutPoint>& ou
if (m_requested_outpoints_by_txid.empty()) return; if (m_requested_outpoints_by_txid.empty()) return;
// Calculate the cluster and construct the entry map. // Calculate the cluster and construct the entry map.
std::vector<uint256> txids_needed; std::vector<Txid> txids_needed;
txids_needed.reserve(m_requested_outpoints_by_txid.size()); txids_needed.reserve(m_requested_outpoints_by_txid.size());
for (const auto& [txid, _]: m_requested_outpoints_by_txid) { for (const auto& [txid, _]: m_requested_outpoints_by_txid) {
txids_needed.push_back(txid); txids_needed.push_back(txid);
@ -286,7 +286,7 @@ void MiniMiner::BuildMockTemplate(std::optional<CFeeRate> target_feerate)
} }
// Track the order in which transactions were selected. // Track the order in which transactions were selected.
for (const auto& ancestor : ancestors) { for (const auto& ancestor : ancestors) {
m_inclusion_order.emplace(Txid::FromUint256(ancestor->first), sequence_num); m_inclusion_order.emplace(ancestor->first, sequence_num);
} }
DeleteAncestorPackage(ancestors); DeleteAncestorPackage(ancestors);
SanityCheck(); SanityCheck();
@ -409,7 +409,7 @@ std::optional<CAmount> MiniMiner::CalculateTotalBumpFees(const CFeeRate& target_
ancestors.insert(iter); ancestors.insert(iter);
} }
std::set<uint256> has_been_processed; std::set<Txid> has_been_processed;
while (!to_process.empty()) { while (!to_process.empty()) {
auto iter = to_process.begin(); auto iter = to_process.begin();
const CTransaction& tx = (*iter)->second.GetTx(); const CTransaction& tx = (*iter)->second.GetTx();

View file

@ -83,12 +83,12 @@ class MiniMiner
// Set once per lifetime, fill in during initialization. // Set once per lifetime, fill in during initialization.
// txids of to-be-replaced transactions // txids of to-be-replaced transactions
std::set<uint256> m_to_be_replaced; std::set<Txid> m_to_be_replaced;
// If multiple argument outpoints correspond to the same transaction, cache them together in // If multiple argument outpoints correspond to the same transaction, cache them together in
// a single entry indexed by txid. Then we can just work with txids since all outpoints from // a single entry indexed by txid. Then we can just work with txids since all outpoints from
// the same tx will have the same bumpfee. Excludes non-mempool transactions. // the same tx will have the same bumpfee. Excludes non-mempool transactions.
std::map<uint256, std::vector<COutPoint>> m_requested_outpoints_by_txid; std::map<Txid, std::vector<COutPoint>> m_requested_outpoints_by_txid;
// Txid to a number representing the order in which this transaction was included (smaller // Txid to a number representing the order in which this transaction was included (smaller
// number = included earlier). Transactions included in an ancestor set together have the same // number = included earlier). Transactions included in an ancestor set together have the same
@ -98,21 +98,21 @@ class MiniMiner
std::map<COutPoint, CAmount> m_bump_fees; std::map<COutPoint, CAmount> m_bump_fees;
// The constructed block template // The constructed block template
std::set<uint256> m_in_block; std::set<Txid> m_in_block;
// Information on the current status of the block // Information on the current status of the block
CAmount m_total_fees{0}; CAmount m_total_fees{0};
int32_t m_total_vsize{0}; int32_t m_total_vsize{0};
/** Main data structure holding the entries, can be indexed by txid */ /** Main data structure holding the entries, can be indexed by txid */
std::map<uint256, MiniMinerMempoolEntry> m_entries_by_txid; std::map<Txid, MiniMinerMempoolEntry> m_entries_by_txid;
using MockEntryMap = decltype(m_entries_by_txid); using MockEntryMap = decltype(m_entries_by_txid);
/** Vector of entries, can be sorted by ancestor feerate. */ /** Vector of entries, can be sorted by ancestor feerate. */
std::vector<MockEntryMap::iterator> m_entries; std::vector<MockEntryMap::iterator> m_entries;
/** Map of txid to its descendants. Should be inclusive. */ /** Map of txid to its descendants. Should be inclusive. */
std::map<uint256, std::vector<MockEntryMap::iterator>> m_descendant_set_by_txid; std::map<Txid, std::vector<MockEntryMap::iterator>> m_descendant_set_by_txid;
/** Consider this ancestor package "mined" so remove all these entries from our data structures. */ /** Consider this ancestor package "mined" so remove all these entries from our data structures. */
void DeleteAncestorPackage(const std::set<MockEntryMap::iterator, IteratorComparator>& ancestors); void DeleteAncestorPackage(const std::set<MockEntryMap::iterator, IteratorComparator>& ancestors);
@ -129,7 +129,7 @@ public:
void BuildMockTemplate(std::optional<CFeeRate> target_feerate); void BuildMockTemplate(std::optional<CFeeRate> target_feerate);
/** Returns set of txids in the block template if one has been constructed. */ /** Returns set of txids in the block template if one has been constructed. */
std::set<uint256> GetMockTemplateTxids() const { return m_in_block; } std::set<Txid> GetMockTemplateTxids() const { return m_in_block; }
/** Constructor that takes a list of outpoints that may or may not belong to transactions in the /** Constructor that takes a list of outpoints that may or may not belong to transactions in the
* mempool. Copies out information about the relevant transactions in the mempool into * mempool. Copies out information about the relevant transactions in the mempool into

View file

@ -42,7 +42,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
std::promise<void> promise; std::promise<void> promise;
Txid txid = tx->GetHash(); Txid txid = tx->GetHash();
uint256 wtxid = tx->GetWitnessHash(); Wtxid wtxid = tx->GetWitnessHash();
bool callback_set = false; bool callback_set = false;
{ {
@ -123,7 +123,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
return TransactionError::OK; return TransactionError::OK;
} }
CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, uint256& hashBlock, const BlockManager& blockman) CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const Txid& hash, uint256& hashBlock, const BlockManager& blockman)
{ {
if (mempool && !block_index) { if (mempool && !block_index) {
CTransactionRef ptx = mempool->get(hash); CTransactionRef ptx = mempool->get(hash);

View file

@ -63,7 +63,7 @@ static const CAmount DEFAULT_MAX_BURN_AMOUNT{0};
* @param[out] hashBlock The block hash, if the tx was found via -txindex or block_index * @param[out] hashBlock The block hash, if the tx was found via -txindex or block_index
* @returns The tx if found, otherwise nullptr * @returns The tx if found, otherwise nullptr
*/ */
CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, uint256& hashBlock, const BlockManager& blockman); CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const Txid& hash, uint256& hashBlock, const BlockManager& blockman);
} // namespace node } // namespace node
#endif // BITCOIN_NODE_TRANSACTION_H #endif // BITCOIN_NODE_TRANSACTION_H

View file

@ -8,6 +8,7 @@
#include <net.h> #include <net.h>
#include <policy/packages.h> #include <policy/packages.h>
#include <txorphanage.h> #include <txorphanage.h>
#include <util/transaction_identifier.h>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
@ -143,7 +144,7 @@ public:
std::vector<GenTxid> GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time); std::vector<GenTxid> GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time);
/** Should be called when a notfound for a tx has been received. */ /** Should be called when a notfound for a tx has been received. */
void ReceivedNotFound(NodeId nodeid, const std::vector<uint256>& txhashes); void ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& txhashes);
/** Respond to successful transaction submission to mempool */ /** Respond to successful transaction submission to mempool */
void MempoolAcceptedTx(const CTransactionRef& tx); void MempoolAcceptedTx(const CTransactionRef& tx);

View file

@ -47,7 +47,7 @@ std::vector<GenTxid> TxDownloadManager::GetRequestsToSend(NodeId nodeid, std::ch
{ {
return m_impl->GetRequestsToSend(nodeid, current_time); return m_impl->GetRequestsToSend(nodeid, current_time);
} }
void TxDownloadManager::ReceivedNotFound(NodeId nodeid, const std::vector<uint256>& txhashes) void TxDownloadManager::ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& txhashes)
{ {
m_impl->ReceivedNotFound(nodeid, txhashes); m_impl->ReceivedNotFound(nodeid, txhashes);
} }
@ -124,12 +124,9 @@ void TxDownloadManagerImpl::BlockDisconnected()
bool TxDownloadManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable) bool TxDownloadManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable)
{ {
const uint256& hash = gtxid.GetHash(); bool in_orphanage = std::visit(util::Overloaded{
if (gtxid.IsWtxid()) {
// Normal query by wtxid. // Normal query by wtxid.
if (m_orphanage.HaveTx(Wtxid::FromUint256(hash))) return true; [this](const Wtxid& wtxid) { return m_orphanage.HaveTx(wtxid); },
} else {
// Never query by txid: it is possible that the transaction in the orphanage has the same // Never query by txid: it is possible that the transaction in the orphanage has the same
// txid but a different witness, which would give us a false positive result. If we decided // txid but a different witness, which would give us a false positive result. If we decided
// not to request the transaction based on this result, an attacker could prevent us from // not to request the transaction based on this result, an attacker could prevent us from
@ -141,8 +138,12 @@ bool TxDownloadManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_rec
// While we won't query by txid, we can try to "guess" what the wtxid is based on the txid. // While we won't query by txid, we can try to "guess" what the wtxid is based on the txid.
// A non-segwit transaction's txid == wtxid. Query this txid "casted" to a wtxid. This will // A non-segwit transaction's txid == wtxid. Query this txid "casted" to a wtxid. This will
// help us find non-segwit transactions, saving bandwidth, and should have no false positives. // help us find non-segwit transactions, saving bandwidth, and should have no false positives.
if (m_orphanage.HaveTx(Wtxid::FromUint256(hash))) return true; [this](const Txid& txid) { return m_orphanage.HaveTx(Wtxid::FromUint256(txid.ToUint256())); }
} }, gtxid);
if (in_orphanage) return true;
const uint256& hash = gtxid.ToUint256();
if (include_reconsiderable && RecentRejectsReconsiderableFilter().contains(hash)) return true; if (include_reconsiderable && RecentRejectsReconsiderableFilter().contains(hash)) return true;
@ -178,12 +179,11 @@ bool TxDownloadManagerImpl::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid,
// - is wtxid matching something in orphanage // - is wtxid matching something in orphanage
// - exists in orphanage // - exists in orphanage
// - peer can be an orphan resolution candidate // - peer can be an orphan resolution candidate
if (gtxid.IsWtxid()) { if (const auto* wtxid = std::get_if<Wtxid>(&gtxid)) {
const auto wtxid{Wtxid::FromUint256(gtxid.GetHash())}; if (auto orphan_tx{m_orphanage.GetTx(*wtxid)}) {
if (auto orphan_tx{m_orphanage.GetTx(wtxid)}) {
auto unique_parents{GetUniqueParents(*orphan_tx)}; auto unique_parents{GetUniqueParents(*orphan_tx)};
std::erase_if(unique_parents, [&](const auto& txid){ std::erase_if(unique_parents, [&](const auto& txid){
return AlreadyHaveTx(GenTxid::Txid(txid), /*include_reconsiderable=*/false); return AlreadyHaveTx(txid, /*include_reconsiderable=*/false);
}); });
// The missing parents may have all been rejected or accepted since the orphan was added to the orphanage. // The missing parents may have all been rejected or accepted since the orphan was added to the orphanage.
@ -192,7 +192,7 @@ bool TxDownloadManagerImpl::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid,
return true; return true;
} }
if (MaybeAddOrphanResolutionCandidate(unique_parents, wtxid, peer, now)) { if (MaybeAddOrphanResolutionCandidate(unique_parents, *wtxid, peer, now)) {
m_orphanage.AddAnnouncer(orphan_tx->GetWitnessHash(), peer); m_orphanage.AddAnnouncer(orphan_tx->GetWitnessHash(), peer);
} }
@ -220,7 +220,7 @@ bool TxDownloadManagerImpl::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid,
// MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't have NetPermissionFlags::Relay). // MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't have NetPermissionFlags::Relay).
auto delay{0us}; auto delay{0us};
if (!info.m_preferred) delay += NONPREF_PEER_TX_DELAY; if (!info.m_preferred) delay += NONPREF_PEER_TX_DELAY;
if (!gtxid.IsWtxid() && m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY; if (!std::holds_alternative<Wtxid>(gtxid) && m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY;
const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(peer) >= MAX_PEER_TX_REQUEST_IN_FLIGHT; const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(peer) >= MAX_PEER_TX_REQUEST_IN_FLIGHT;
if (overloaded) delay += OVERLOADED_PEER_TX_DELAY; if (overloaded) delay += OVERLOADED_PEER_TX_DELAY;
@ -261,7 +261,7 @@ bool TxDownloadManagerImpl::MaybeAddOrphanResolutionCandidate(const std::vector<
// Treat finding orphan resolution candidate as equivalent to the peer announcing all missing parents. // Treat finding orphan resolution candidate as equivalent to the peer announcing all missing parents.
// In the future, orphan resolution may include more explicit steps // In the future, orphan resolution may include more explicit steps
for (const auto& parent_txid : unique_parents) { for (const auto& parent_txid : unique_parents) {
m_txrequest.ReceivedInv(nodeid, GenTxid::Txid(parent_txid), info.m_preferred, now + delay); m_txrequest.ReceivedInv(nodeid, parent_txid, info.m_preferred, now + delay);
} }
LogDebug(BCLog::TXPACKAGES, "added peer=%d as a candidate for resolving orphan %s\n", nodeid, wtxid.ToString()); LogDebug(BCLog::TXPACKAGES, "added peer=%d as a candidate for resolving orphan %s\n", nodeid, wtxid.ToString());
return true; return true;
@ -273,25 +273,25 @@ std::vector<GenTxid> TxDownloadManagerImpl::GetRequestsToSend(NodeId nodeid, std
std::vector<std::pair<NodeId, GenTxid>> expired; std::vector<std::pair<NodeId, GenTxid>> expired;
auto requestable = m_txrequest.GetRequestable(nodeid, current_time, &expired); auto requestable = m_txrequest.GetRequestable(nodeid, current_time, &expired);
for (const auto& entry : expired) { for (const auto& entry : expired) {
LogDebug(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", entry.second.IsWtxid() ? "wtx" : "tx", LogDebug(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", std::holds_alternative<Wtxid>(entry.second) ? "wtx" : "tx",
entry.second.GetHash().ToString(), entry.first); entry.second.ToUint256().ToString(), entry.first);
} }
for (const GenTxid& gtxid : requestable) { for (const GenTxid& gtxid : requestable) {
if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) { if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) {
LogDebug(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx", LogDebug(BCLog::NET, "Requesting %s %s peer=%d\n", std::holds_alternative<Wtxid>(gtxid) ? "wtx" : "tx",
gtxid.GetHash().ToString(), nodeid); gtxid.ToUint256().ToString(), nodeid);
requests.emplace_back(gtxid); requests.emplace_back(gtxid);
m_txrequest.RequestedTx(nodeid, gtxid.GetHash(), current_time + GETDATA_TX_INTERVAL); m_txrequest.RequestedTx(nodeid, gtxid, current_time + GETDATA_TX_INTERVAL);
} else { } else {
// We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as // We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as
// this should already be called whenever a transaction becomes AlreadyHaveTx(). // this should already be called whenever a transaction becomes AlreadyHaveTx().
m_txrequest.ForgetTxHash(gtxid.GetHash()); m_txrequest.ForgetTxHash(gtxid);
} }
} }
return requests; return requests;
} }
void TxDownloadManagerImpl::ReceivedNotFound(NodeId nodeid, const std::vector<uint256>& txhashes) void TxDownloadManagerImpl::ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& txhashes)
{ {
for (const auto& txhash : txhashes) { for (const auto& txhash : txhashes) {
// If we receive a NOTFOUND message for a tx we requested, mark the announcement for it as // If we receive a NOTFOUND message for a tx we requested, mark the announcement for it as
@ -378,19 +378,19 @@ node::RejectedTxTodo TxDownloadManagerImpl::MempoolRejectedTx(const CTransaction
// We can tolerate having up to 1 parent in m_lazy_recent_rejects_reconsiderable since we // We can tolerate having up to 1 parent in m_lazy_recent_rejects_reconsiderable since we
// submit 1p1c packages. However, fail immediately if any are in m_lazy_recent_rejects. // submit 1p1c packages. However, fail immediately if any are in m_lazy_recent_rejects.
std::optional<uint256> rejected_parent_reconsiderable; std::optional<uint256> rejected_parent_reconsiderable;
for (const uint256& parent_txid : unique_parents) { for (const Txid& parent_txid : unique_parents) {
if (RecentRejectsFilter().contains(parent_txid)) { if (RecentRejectsFilter().contains(parent_txid.ToUint256())) {
fRejectedParents = true; fRejectedParents = true;
break; break;
} else if (RecentRejectsReconsiderableFilter().contains(parent_txid) && } else if (RecentRejectsReconsiderableFilter().contains(parent_txid.ToUint256()) &&
!m_opts.m_mempool.exists(GenTxid::Txid(parent_txid))) { !m_opts.m_mempool.exists(parent_txid)) {
// More than 1 parent in m_lazy_recent_rejects_reconsiderable: 1p1c will not be // More than 1 parent in m_lazy_recent_rejects_reconsiderable: 1p1c will not be
// sufficient to accept this package, so just give up here. // sufficient to accept this package, so just give up here.
if (rejected_parent_reconsiderable.has_value()) { if (rejected_parent_reconsiderable.has_value()) {
fRejectedParents = true; fRejectedParents = true;
break; break;
} }
rejected_parent_reconsiderable = parent_txid; rejected_parent_reconsiderable = parent_txid.ToUint256();
} }
} }
if (!fRejectedParents) { if (!fRejectedParents) {
@ -398,7 +398,7 @@ node::RejectedTxTodo TxDownloadManagerImpl::MempoolRejectedTx(const CTransaction
// Exclude m_lazy_recent_rejects_reconsiderable: the missing parent may have been // Exclude m_lazy_recent_rejects_reconsiderable: the missing parent may have been
// previously rejected for being too low feerate. This orphan might CPFP it. // previously rejected for being too low feerate. This orphan might CPFP it.
std::erase_if(unique_parents, [&](const auto& txid){ std::erase_if(unique_parents, [&](const auto& txid){
return AlreadyHaveTx(GenTxid::Txid(txid), /*include_reconsiderable=*/false); return AlreadyHaveTx(txid, /*include_reconsiderable=*/false);
}); });
const auto now{GetTime<std::chrono::microseconds>()}; const auto now{GetTime<std::chrono::microseconds>()};
const auto& wtxid = ptx->GetWitnessHash(); const auto& wtxid = ptx->GetWitnessHash();
@ -412,8 +412,8 @@ node::RejectedTxTodo TxDownloadManagerImpl::MempoolRejectedTx(const CTransaction
// //
// Search by txid and, if the tx has a witness, wtxid // Search by txid and, if the tx has a witness, wtxid
std::vector<NodeId> orphan_resolution_candidates{nodeid}; std::vector<NodeId> orphan_resolution_candidates{nodeid};
m_txrequest.GetCandidatePeers(ptx->GetHash().ToUint256(), orphan_resolution_candidates); m_txrequest.GetCandidatePeers(ptx->GetHash(), orphan_resolution_candidates);
if (ptx->HasWitness()) m_txrequest.GetCandidatePeers(ptx->GetWitnessHash().ToUint256(), orphan_resolution_candidates); if (ptx->HasWitness()) m_txrequest.GetCandidatePeers(ptx->GetWitnessHash(), orphan_resolution_candidates);
for (const auto& nodeid : orphan_resolution_candidates) { for (const auto& nodeid : orphan_resolution_candidates) {
if (MaybeAddOrphanResolutionCandidate(unique_parents, ptx->GetWitnessHash(), nodeid, now)) { if (MaybeAddOrphanResolutionCandidate(unique_parents, ptx->GetWitnessHash(), nodeid, now)) {
@ -515,8 +515,8 @@ void TxDownloadManagerImpl::MempoolRejectedPackage(const Package& package)
std::pair<bool, std::optional<PackageToValidate>> TxDownloadManagerImpl::ReceivedTx(NodeId nodeid, const CTransactionRef& ptx) std::pair<bool, std::optional<PackageToValidate>> TxDownloadManagerImpl::ReceivedTx(NodeId nodeid, const CTransactionRef& ptx)
{ {
const uint256& txid = ptx->GetHash(); const Txid& txid = ptx->GetHash();
const uint256& wtxid = ptx->GetWitnessHash(); const Wtxid& wtxid = ptx->GetWitnessHash();
// Mark that we have received a response // Mark that we have received a response
m_txrequest.ReceivedResponse(nodeid, txid); m_txrequest.ReceivedResponse(nodeid, txid);
@ -535,7 +535,7 @@ std::pair<bool, std::optional<PackageToValidate>> TxDownloadManagerImpl::Receive
// already; and an adversary can already relay us old transactions // already; and an adversary can already relay us old transactions
// (older than our recency filter) if trying to DoS us, without any need // (older than our recency filter) if trying to DoS us, without any need
// for witness malleation. // for witness malleation.
if (AlreadyHaveTx(GenTxid::Wtxid(wtxid), /*include_reconsiderable=*/false)) { if (AlreadyHaveTx(wtxid, /*include_reconsiderable=*/false)) {
// If a tx is detected by m_lazy_recent_rejects it is ignored. Because we haven't // If a tx is detected by m_lazy_recent_rejects it is ignored. Because we haven't
// submitted the tx to our mempool, we won't have computed a DoS // submitted the tx to our mempool, we won't have computed a DoS
// score for it or determined exactly why we consider it invalid. // score for it or determined exactly why we consider it invalid.
@ -552,7 +552,7 @@ std::pair<bool, std::optional<PackageToValidate>> TxDownloadManagerImpl::Receive
// peer simply for relaying a tx that our m_lazy_recent_rejects has caught, // peer simply for relaying a tx that our m_lazy_recent_rejects has caught,
// regardless of false positives. // regardless of false positives.
return {false, std::nullopt}; return {false, std::nullopt};
} else if (RecentRejectsReconsiderableFilter().contains(wtxid)) { } else if (RecentRejectsReconsiderableFilter().contains(wtxid.ToUint256())) {
// When a transaction is already in m_lazy_recent_rejects_reconsiderable, we shouldn't submit // When a transaction is already in m_lazy_recent_rejects_reconsiderable, we shouldn't submit
// it by itself again. However, look for a matching child in the orphanage, as it is // it by itself again. However, look for a matching child in the orphanage, as it is
// possible that they succeed as a package. // possible that they succeed as a package.

View file

@ -169,7 +169,7 @@ public:
std::vector<GenTxid> GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time); std::vector<GenTxid> GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time);
/** Marks a tx as ReceivedResponse in txrequest. */ /** Marks a tx as ReceivedResponse in txrequest. */
void ReceivedNotFound(NodeId nodeid, const std::vector<uint256>& txhashes); void ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& txhashes);
/** Look for a child of this transaction in the orphanage to form a 1-parent-1-child package, /** Look for a child of this transaction in the orphanage to form a 1-parent-1-child package,
* skipping any combinations that have already been tried. Return the resulting package along with * skipping any combinations that have already been tried. Return the resulting package along with

View file

@ -518,16 +518,16 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe
} }
} }
bool CBlockPolicyEstimator::removeTx(uint256 hash) bool CBlockPolicyEstimator::removeTx(Txid hash)
{ {
LOCK(m_cs_fee_estimator); LOCK(m_cs_fee_estimator);
return _removeTx(hash, /*inBlock=*/false); return _removeTx(hash, /*inBlock=*/false);
} }
bool CBlockPolicyEstimator::_removeTx(const uint256& hash, bool inBlock) bool CBlockPolicyEstimator::_removeTx(const Txid& hash, bool inBlock)
{ {
AssertLockHeld(m_cs_fee_estimator); AssertLockHeld(m_cs_fee_estimator);
std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash); std::map<Txid, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
if (pos != mapMemPoolTxs.end()) { if (pos != mapMemPoolTxs.end()) {
feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock); feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock); shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);

View file

@ -212,7 +212,7 @@ public:
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator); EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Remove a transaction from the mempool tracking stats for non BLOCK removal reasons*/ /** Remove a transaction from the mempool tracking stats for non BLOCK removal reasons*/
bool removeTx(uint256 hash) bool removeTx(Txid hash)
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator); EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** DEPRECATED. Return a feerate estimate */ /** DEPRECATED. Return a feerate estimate */
@ -287,7 +287,7 @@ private:
}; };
// map of txids to information about that transaction // map of txids to information about that transaction
std::map<uint256, TxStatsInfo> mapMemPoolTxs GUARDED_BY(m_cs_fee_estimator); std::map<Txid, TxStatsInfo> mapMemPoolTxs GUARDED_BY(m_cs_fee_estimator);
/** Classes to track historical data on transaction confirmations */ /** Classes to track historical data on transaction confirmations */
std::unique_ptr<TxConfirmStats> feeStats PT_GUARDED_BY(m_cs_fee_estimator); std::unique_ptr<TxConfirmStats> feeStats PT_GUARDED_BY(m_cs_fee_estimator);
@ -315,7 +315,7 @@ private:
unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator); unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
/** A non-thread-safe helper for the removeTx function */ /** A non-thread-safe helper for the removeTx function */
bool _removeTx(const uint256& hash, bool inBlock) bool _removeTx(const Txid& hash, bool inBlock)
EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator); EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
}; };

View file

@ -16,7 +16,7 @@
/** IsTopoSortedPackage where a set of txids has been pre-populated. The set is assumed to be correct and /** IsTopoSortedPackage where a set of txids has been pre-populated. The set is assumed to be correct and
* is mutated within this function (even if return value is false). */ * is mutated within this function (even if return value is false). */
bool IsTopoSortedPackage(const Package& txns, std::unordered_set<uint256, SaltedTxidHasher>& later_txids) bool IsTopoSortedPackage(const Package& txns, std::unordered_set<Txid, SaltedTxidHasher>& later_txids)
{ {
// Avoid misusing this function: later_txids should contain the txids of txns. // Avoid misusing this function: later_txids should contain the txids of txns.
Assume(txns.size() == later_txids.size()); Assume(txns.size() == later_txids.size());
@ -42,7 +42,7 @@ bool IsTopoSortedPackage(const Package& txns, std::unordered_set<uint256, Salted
bool IsTopoSortedPackage(const Package& txns) bool IsTopoSortedPackage(const Package& txns)
{ {
std::unordered_set<uint256, SaltedTxidHasher> later_txids; std::unordered_set<Txid, SaltedTxidHasher> later_txids;
std::transform(txns.cbegin(), txns.cend(), std::inserter(later_txids, later_txids.end()), std::transform(txns.cbegin(), txns.cend(), std::inserter(later_txids, later_txids.end()),
[](const auto& tx) { return tx->GetHash(); }); [](const auto& tx) { return tx->GetHash(); });
@ -91,7 +91,7 @@ bool IsWellFormedPackage(const Package& txns, PackageValidationState& state, boo
return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-large"); return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-large");
} }
std::unordered_set<uint256, SaltedTxidHasher> later_txids; std::unordered_set<Txid, SaltedTxidHasher> later_txids;
std::transform(txns.cbegin(), txns.cend(), std::inserter(later_txids, later_txids.end()), std::transform(txns.cbegin(), txns.cend(), std::inserter(later_txids, later_txids.end()),
[](const auto& tx) { return tx->GetHash(); }); [](const auto& tx) { return tx->GetHash(); });
@ -123,7 +123,7 @@ bool IsChildWithParents(const Package& package)
// The package is expected to be sorted, so the last transaction is the child. // The package is expected to be sorted, so the last transaction is the child.
const auto& child = package.back(); const auto& child = package.back();
std::unordered_set<uint256, SaltedTxidHasher> input_txids; std::unordered_set<Txid, SaltedTxidHasher> input_txids;
std::transform(child->vin.cbegin(), child->vin.cend(), std::transform(child->vin.cbegin(), child->vin.cend(),
std::inserter(input_txids, input_txids.end()), std::inserter(input_txids, input_txids.end()),
[](const auto& input) { return input.prevout.hash; }); [](const auto& input) { return input.prevout.hash; });
@ -136,7 +136,7 @@ bool IsChildWithParents(const Package& package)
bool IsChildWithParentsTree(const Package& package) bool IsChildWithParentsTree(const Package& package)
{ {
if (!IsChildWithParents(package)) return false; if (!IsChildWithParents(package)) return false;
std::unordered_set<uint256, SaltedTxidHasher> parent_txids; std::unordered_set<Txid, SaltedTxidHasher> parent_txids;
std::transform(package.cbegin(), package.cend() - 1, std::inserter(parent_txids, parent_txids.end()), std::transform(package.cbegin(), package.cend() - 1, std::inserter(parent_txids, parent_txids.end()),
[](const auto& ptx) { return ptx->GetHash(); }); [](const auto& ptx) { return ptx->GetHash(); });
// Each parent must not have an input who is one of the other parents. // Each parent must not have an input who is one of the other parents.

View file

@ -32,7 +32,7 @@ RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
// If this transaction is not in our mempool, then we can't be sure // If this transaction is not in our mempool, then we can't be sure
// we will know about all its inputs. // we will know about all its inputs.
if (!pool.exists(GenTxid::Txid(tx.GetHash()))) { if (!pool.exists(tx.GetHash())) {
return RBFTransactionState::UNKNOWN; return RBFTransactionState::UNKNOWN;
} }
@ -62,7 +62,7 @@ std::optional<std::string> GetEntriesForConflicts(const CTransaction& tx,
CTxMemPool::setEntries& all_conflicts) CTxMemPool::setEntries& all_conflicts)
{ {
AssertLockHeld(pool.cs); AssertLockHeld(pool.cs);
const uint256 txid = tx.GetHash(); const Txid txid = tx.GetHash();
uint64_t nConflictingCount = 0; uint64_t nConflictingCount = 0;
for (const auto& mi : iters_conflicting) { for (const auto& mi : iters_conflicting) {
nConflictingCount += mi->GetCountWithDescendants(); nConflictingCount += mi->GetCountWithDescendants();
@ -89,7 +89,7 @@ std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx,
const CTxMemPool::setEntries& iters_conflicting) const CTxMemPool::setEntries& iters_conflicting)
{ {
AssertLockHeld(pool.cs); AssertLockHeld(pool.cs);
std::set<uint256> parents_of_conflicts; std::set<Txid> parents_of_conflicts;
for (const auto& mi : iters_conflicting) { for (const auto& mi : iters_conflicting) {
for (const CTxIn& txin : mi->GetTx().vin) { for (const CTxIn& txin : mi->GetTx().vin) {
parents_of_conflicts.insert(txin.prevout.hash); parents_of_conflicts.insert(txin.prevout.hash);
@ -107,7 +107,7 @@ std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx,
if (!parents_of_conflicts.count(tx.vin[j].prevout.hash)) { if (!parents_of_conflicts.count(tx.vin[j].prevout.hash)) {
// Rather than check the UTXO set - potentially expensive - it's cheaper to just check // Rather than check the UTXO set - potentially expensive - it's cheaper to just check
// if the new input refers to a tx that's in the mempool. // if the new input refers to a tx that's in the mempool.
if (pool.exists(GenTxid::Txid(tx.vin[j].prevout.hash))) { if (pool.exists(tx.vin[j].prevout.hash)) {
return strprintf("replacement %s adds unconfirmed input, idx %d", return strprintf("replacement %s adds unconfirmed input, idx %d",
tx.GetHash().ToString(), j); tx.GetHash().ToString(), j);
} }
@ -118,7 +118,7 @@ std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx,
std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& ancestors, std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& ancestors,
const std::set<Txid>& direct_conflicts, const std::set<Txid>& direct_conflicts,
const uint256& txid) const Txid& txid)
{ {
for (CTxMemPool::txiter ancestorIt : ancestors) { for (CTxMemPool::txiter ancestorIt : ancestors) {
const Txid& hashAncestor = ancestorIt->GetTx().GetHash(); const Txid& hashAncestor = ancestorIt->GetTx().GetHash();
@ -133,7 +133,7 @@ std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries&
std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& iters_conflicting, std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& iters_conflicting,
CFeeRate replacement_feerate, CFeeRate replacement_feerate,
const uint256& txid) const Txid& txid)
{ {
for (const auto& mi : iters_conflicting) { for (const auto& mi : iters_conflicting) {
// Don't allow the replacement to reduce the feerate of the mempool. // Don't allow the replacement to reduce the feerate of the mempool.
@ -161,7 +161,7 @@ std::optional<std::string> PaysForRBF(CAmount original_fees,
CAmount replacement_fees, CAmount replacement_fees,
size_t replacement_vsize, size_t replacement_vsize,
CFeeRate relay_fee, CFeeRate relay_fee,
const uint256& txid) const Txid& txid)
{ {
// Rule #3: The replacement fees must be greater than or equal to fees of the // Rule #3: The replacement fees must be greater than or equal to fees of the
// transactions it replaces, otherwise the bandwidth used by those conflicting transactions // transactions it replaces, otherwise the bandwidth used by those conflicting transactions

View file

@ -90,7 +90,7 @@ std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx, const CTx
*/ */
std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& ancestors, std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& ancestors,
const std::set<Txid>& direct_conflicts, const std::set<Txid>& direct_conflicts,
const uint256& txid); const Txid& txid);
/** Check that the feerate of the replacement transaction(s) is higher than the feerate of each /** Check that the feerate of the replacement transaction(s) is higher than the feerate of each
* of the transactions in iters_conflicting. * of the transactions in iters_conflicting.
@ -98,7 +98,7 @@ std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries&
* @returns error message if fees insufficient, otherwise std::nullopt. * @returns error message if fees insufficient, otherwise std::nullopt.
*/ */
std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& iters_conflicting, std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& iters_conflicting,
CFeeRate replacement_feerate, const uint256& txid); CFeeRate replacement_feerate, const Txid& txid);
/** The replacement transaction must pay more fees than the original transactions. The additional /** The replacement transaction must pay more fees than the original transactions. The additional
* fees must pay for the replacement's bandwidth at or above the incremental relay feerate. * fees must pay for the replacement's bandwidth at or above the incremental relay feerate.
@ -113,7 +113,7 @@ std::optional<std::string> PaysForRBF(CAmount original_fees,
CAmount replacement_fees, CAmount replacement_fees,
size_t replacement_vsize, size_t replacement_vsize,
CFeeRate relay_fee, CFeeRate relay_fee,
const uint256& txid); const Txid& txid);
/** /**
* The replacement transaction must improve the feerate diagram of the mempool. * The replacement transaction must improve the feerate diagram of the mempool.

View file

@ -423,20 +423,4 @@ struct CMutableTransaction
typedef std::shared_ptr<const CTransaction> CTransactionRef; typedef std::shared_ptr<const CTransaction> CTransactionRef;
template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); } template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }
/** A generic txid reference (txid or wtxid). */
class GenTxid
{
bool m_is_wtxid;
uint256 m_hash;
GenTxid(bool is_wtxid, const uint256& hash) : m_is_wtxid(is_wtxid), m_hash(hash) {}
public:
static GenTxid Txid(const uint256& hash) { return GenTxid{false, hash}; }
static GenTxid Wtxid(const uint256& hash) { return GenTxid{true, hash}; }
bool IsWtxid() const { return m_is_wtxid; }
const uint256& GetHash() const LIFETIMEBOUND { return m_hash; }
friend bool operator==(const GenTxid& a, const GenTxid& b) { return a.m_is_wtxid == b.m_is_wtxid && a.m_hash == b.m_hash; }
friend bool operator<(const GenTxid& a, const GenTxid& b) { return std::tie(a.m_is_wtxid, a.m_hash) < std::tie(b.m_is_wtxid, b.m_hash); }
};
#endif // BITCOIN_PRIMITIVES_TRANSACTION_H #endif // BITCOIN_PRIMITIVES_TRANSACTION_H

View file

@ -121,5 +121,9 @@ std::vector<std::string> serviceFlagsToStr(uint64_t flags)
GenTxid ToGenTxid(const CInv& inv) GenTxid ToGenTxid(const CInv& inv)
{ {
assert(inv.IsGenTxMsg()); assert(inv.IsGenTxMsg());
return inv.IsMsgWtx() ? GenTxid::Wtxid(inv.hash) : GenTxid::Txid(inv.hash); if (inv.IsMsgWtx()) {
return Wtxid::FromUint256(inv.hash);
} else {
return Txid::FromUint256(inv.hash);
}
} }

View file

@ -61,7 +61,7 @@ public Q_SLOTS:
void setBalance(const interfaces::WalletBalances& balances); void setBalance(const interfaces::WalletBalances& balances);
Q_SIGNALS: Q_SIGNALS:
void coinsSent(const uint256& txid); void coinsSent(const Txid& txid);
private: private:
Ui::SendCoinsDialog *ui; Ui::SendCoinsDialog *ui;

View file

@ -75,7 +75,7 @@ void ConfirmSend(QString* text = nullptr, QMessageBox::StandardButton confirm_ty
} }
//! Send coins to address and return txid. //! Send coins to address and return txid.
uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf, Txid SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf,
QMessageBox::StandardButton confirm_type = QMessageBox::Yes) QMessageBox::StandardButton confirm_type = QMessageBox::Yes)
{ {
QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries"); QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
@ -86,8 +86,8 @@ uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDe
->findChild<QFrame*>("frameFeeSelection") ->findChild<QFrame*>("frameFeeSelection")
->findChild<QCheckBox*>("optInRBF") ->findChild<QCheckBox*>("optInRBF")
->setCheckState(rbf ? Qt::Checked : Qt::Unchecked); ->setCheckState(rbf ? Qt::Checked : Qt::Unchecked);
uint256 txid; Txid txid;
boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](const uint256& hash, ChangeType status) { boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](const Txid& hash, ChangeType status) {
if (status == CT_NEW) txid = hash; if (status == CT_NEW) txid = hash;
})); }));
ConfirmSend(/*text=*/nullptr, confirm_type); ConfirmSend(/*text=*/nullptr, confirm_type);
@ -97,7 +97,7 @@ uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDe
} }
//! Find index of txid in transaction list. //! Find index of txid in transaction list.
QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid) QModelIndex FindTx(const QAbstractItemModel& model, const Txid& txid)
{ {
QString hash = QString::fromStdString(txid.ToString()); QString hash = QString::fromStdString(txid.ToString());
int rows = model.rowCount({}); int rows = model.rowCount({});
@ -111,7 +111,7 @@ QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
} }
//! Invoke bumpfee on txid and check results. //! Invoke bumpfee on txid and check results.
void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, std::string expectError, bool cancel) void BumpFee(TransactionView& view, const Txid& txid, bool expectDisabled, std::string expectError, bool cancel)
{ {
QTableView* table = view.findChild<QTableView*>("transactionView"); QTableView* table = view.findChild<QTableView*>("transactionView");
QModelIndex index = FindTx(*table->selectionModel()->model(), txid); QModelIndex index = FindTx(*table->selectionModel()->model(), txid);
@ -285,8 +285,8 @@ void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
// Send two transactions, and verify they are added to transaction list. // Send two transactions, and verify they are added to transaction list.
TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel(); TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
QCOMPARE(transactionTableModel->rowCount({}), 105); QCOMPARE(transactionTableModel->rowCount({}), 105);
uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false); Txid txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false);
uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, /*rbf=*/true); Txid txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, /*rbf=*/true);
// Transaction table model updates on a QueuedConnection, so process events to ensure it's updated. // Transaction table model updates on a QueuedConnection, so process events to ensure it's updated.
qApp->processEvents(); qApp->processEvents();
QCOMPARE(transactionTableModel->rowCount({}), 107); QCOMPARE(transactionTableModel->rowCount({}), 107);

View file

@ -37,7 +37,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface
CAmount nCredit = wtx.credit; CAmount nCredit = wtx.credit;
CAmount nDebit = wtx.debit; CAmount nDebit = wtx.debit;
CAmount nNet = nCredit - nDebit; CAmount nNet = nCredit - nDebit;
uint256 hash = wtx.tx->GetHash(); Txid hash = wtx.tx->GetHash();
std::map<std::string, std::string> mapValue = wtx.value_map; std::map<std::string, std::string> mapValue = wtx.value_map;
bool involvesWatchAddress = false; bool involvesWatchAddress = false;

View file

@ -7,6 +7,7 @@
#include <consensus/amount.h> #include <consensus/amount.h>
#include <uint256.h> #include <uint256.h>
#include <util/transaction_identifier.h>
#include <QList> #include <QList>
#include <QString> #include <QString>
@ -79,13 +80,13 @@ public:
{ {
} }
TransactionRecord(uint256 _hash, qint64 _time): TransactionRecord(Txid _hash, qint64 _time):
hash(_hash), time(_time), type(Other), debit(0), hash(_hash), time(_time), type(Other), debit(0),
credit(0), idx(0) credit(0), idx(0)
{ {
} }
TransactionRecord(uint256 _hash, qint64 _time, TransactionRecord(Txid _hash, qint64 _time,
Type _type, const std::string &_address, Type _type, const std::string &_address,
const CAmount& _debit, const CAmount& _credit): const CAmount& _debit, const CAmount& _credit):
hash(_hash), time(_time), type(_type), address(_address), debit(_debit), credit(_credit), hash(_hash), time(_time), type(_type), address(_address), debit(_debit), credit(_credit),
@ -100,7 +101,7 @@ public:
/** @name Immutable transaction attributes /** @name Immutable transaction attributes
@{*/ @{*/
uint256 hash; Txid hash;
qint64 time; qint64 time;
Type type; Type type;
std::string address; std::string address;

View file

@ -49,11 +49,11 @@ struct TxLessThan
{ {
return a.hash < b.hash; return a.hash < b.hash;
} }
bool operator()(const TransactionRecord &a, const uint256 &b) const bool operator()(const TransactionRecord &a, const Txid &b) const
{ {
return a.hash < b; return a.hash < b;
} }
bool operator()(const uint256 &a, const TransactionRecord &b) const bool operator()(const Txid &a, const TransactionRecord &b) const
{ {
return a < b.hash; return a < b.hash;
} }
@ -64,7 +64,7 @@ struct TransactionNotification
{ {
public: public:
TransactionNotification() = default; TransactionNotification() = default;
TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction): TransactionNotification(Txid _hash, ChangeType _status, bool _showTransaction):
hash(_hash), status(_status), showTransaction(_showTransaction) {} hash(_hash), status(_status), showTransaction(_showTransaction) {}
void invoke(QObject *ttm) void invoke(QObject *ttm)
@ -78,7 +78,7 @@ public:
assert(invoked); assert(invoked);
} }
private: private:
uint256 hash; Txid hash;
ChangeType status; ChangeType status;
bool showTransaction; bool showTransaction;
}; };
@ -103,7 +103,7 @@ public:
bool m_loading = false; bool m_loading = false;
std::vector< TransactionNotification > vQueueNotifications; std::vector< TransactionNotification > vQueueNotifications;
void NotifyTransactionChanged(const uint256 &hash, ChangeType status); void NotifyTransactionChanged(const Txid& hash, ChangeType status);
void DispatchNotifications(); void DispatchNotifications();
/* Query entire wallet anew from core. /* Query entire wallet anew from core.
@ -127,7 +127,7 @@ public:
Call with transaction that was added, removed or changed. Call with transaction that was added, removed or changed.
*/ */
void updateWallet(interfaces::Wallet& wallet, const uint256 &hash, int status, bool showTransaction) void updateWallet(interfaces::Wallet& wallet, const Txid &hash, int status, bool showTransaction)
{ {
qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status); qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
@ -699,7 +699,7 @@ void TransactionTableModel::updateDisplayUnit()
Q_EMIT dataChanged(index(0, Amount), index(priv->size()-1, Amount)); Q_EMIT dataChanged(index(0, Amount), index(priv->size()-1, Amount));
} }
void TransactionTablePriv::NotifyTransactionChanged(const uint256 &hash, ChangeType status) void TransactionTablePriv::NotifyTransactionChanged(const Txid& hash, ChangeType status)
{ {
// Find transaction in wallet // Find transaction in wallet
// Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread) // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread)

View file

@ -193,7 +193,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
// Double-clicking on a transaction on the transaction history page shows details // Double-clicking on a transaction on the transaction history page shows details
connect(this, &TransactionView::doubleClicked, this, &TransactionView::showDetails); connect(this, &TransactionView::doubleClicked, this, &TransactionView::showDetails);
// Highlight transaction after fee bump // Highlight transaction after fee bump
connect(this, &TransactionView::bumpedFee, [this](const uint256& txid) { connect(this, &TransactionView::bumpedFee, [this](const Txid& txid) {
focusTransaction(txid); focusTransaction(txid);
}); });
} }
@ -436,7 +436,7 @@ void TransactionView::bumpFee([[maybe_unused]] bool checked)
Txid hash = Txid::FromHex(hashQStr.toStdString()).value(); Txid hash = Txid::FromHex(hashQStr.toStdString()).value();
// Bump tx fee over the walletModel // Bump tx fee over the walletModel
uint256 newHash; Txid newHash;
if (model->bumpFee(hash, newHash)) { if (model->bumpFee(hash, newHash)) {
// Update the table // Update the table
transactionView->selectionModel()->clearSelection(); transactionView->selectionModel()->clearSelection();
@ -604,7 +604,7 @@ void TransactionView::focusTransaction(const QModelIndex &idx)
transactionView->setFocus(); transactionView->setFocus();
} }
void TransactionView::focusTransaction(const uint256& txid) void TransactionView::focusTransaction(const Txid& txid)
{ {
if (!transactionProxyModel) if (!transactionProxyModel)
return; return;

View file

@ -115,7 +115,7 @@ Q_SIGNALS:
/** Fired when a message should be reported to the user */ /** Fired when a message should be reported to the user */
void message(const QString &title, const QString &message, unsigned int style); void message(const QString &title, const QString &message, unsigned int style);
void bumpedFee(const uint256& txid); void bumpedFee(const Txid& txid);
public Q_SLOTS: public Q_SLOTS:
void chooseDate(int idx); void chooseDate(int idx);
@ -126,7 +126,7 @@ public Q_SLOTS:
void exportClicked(); void exportClicked();
void closeOpenedDialogs(); void closeOpenedDialogs();
void focusTransaction(const QModelIndex&); void focusTransaction(const QModelIndex&);
void focusTransaction(const uint256& txid); void focusTransaction(const Txid& txid);
}; };
#endif // BITCOIN_QT_TRANSACTIONVIEW_H #endif // BITCOIN_QT_TRANSACTIONVIEW_H

View file

@ -388,7 +388,7 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel,
assert(invoked); assert(invoked);
} }
static void NotifyTransactionChanged(WalletModel *walletmodel, const uint256 &hash, ChangeType status) static void NotifyTransactionChanged(WalletModel *walletmodel, const Txid& hash, ChangeType status)
{ {
Q_UNUSED(hash); Q_UNUSED(hash);
Q_UNUSED(status); Q_UNUSED(status);
@ -479,7 +479,7 @@ WalletModel::UnlockContext::~UnlockContext()
} }
} }
bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) bool WalletModel::bumpFee(Txid hash, Txid& new_hash)
{ {
CCoinControl coin_control; CCoinControl coin_control;
coin_control.m_signal_bip125_rbf = true; coin_control.m_signal_bip125_rbf = true;

View file

@ -129,7 +129,7 @@ public:
UnlockContext requestUnlock(); UnlockContext requestUnlock();
bool bumpFee(uint256 hash, uint256& new_hash); bool bumpFee(Txid hash, Txid& new_hash);
void displayAddress(std::string sAddress) const; void displayAddress(std::string sAddress) const;
static bool isWalletEnabled(); static bool isWalletEnabled();

View file

@ -82,7 +82,7 @@ WalletView::WalletView(WalletModel* wallet_model, const PlatformStyle* _platform
connect(sendCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent); connect(sendCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent);
// Highlight transaction after send // Highlight transaction after send
connect(sendCoinsPage, &SendCoinsDialog::coinsSent, transactionView, qOverload<const uint256&>(&TransactionView::focusTransaction)); connect(sendCoinsPage, &SendCoinsDialog::coinsSent, transactionView, qOverload<const Txid&>(&TransactionView::focusTransaction));
// Clicking on "Export" allows to export the transaction list // Clicking on "Export" allows to export the transaction list
connect(exportButton, &QPushButton::clicked, transactionView, &TransactionView::exportClicked); connect(exportButton, &QPushButton::clicked, transactionView, &TransactionView::exportClicked);

View file

@ -709,7 +709,7 @@ static bool rest_tx(const std::any& context, HTTPRequest* req, const std::string
std::string hashStr; std::string hashStr;
const RESTResponseFormat rf = ParseDataFormat(hashStr, strURIPart); const RESTResponseFormat rf = ParseDataFormat(hashStr, strURIPart);
auto hash{uint256::FromHex(hashStr)}; auto hash{Txid::FromHex(hashStr)};
if (!hash) { if (!hash) {
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
} }

View file

@ -309,7 +309,7 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool
std::set<std::string> setDepends; std::set<std::string> setDepends;
for (const CTxIn& txin : tx.vin) for (const CTxIn& txin : tx.vin)
{ {
if (pool.exists(GenTxid::Txid(txin.prevout.hash))) if (pool.exists(txin.prevout.hash))
setDepends.insert(txin.prevout.hash.ToString()); setDepends.insert(txin.prevout.hash.ToString());
} }
@ -457,12 +457,12 @@ static RPCHelpMan getmempoolancestors()
if (!request.params[1].isNull()) if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool(); fVerbose = request.params[1].get_bool();
uint256 hash = ParseHashV(request.params[0], "parameter 1"); Txid hash = Txid::FromUint256(ParseHashV(request.params[0], "parameter 1"));
const CTxMemPool& mempool = EnsureAnyMemPool(request.context); const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
LOCK(mempool.cs); LOCK(mempool.cs);
const auto entry{mempool.GetEntry(Txid::FromUint256(hash))}; const auto entry{mempool.GetEntry(hash)};
if (entry == nullptr) { if (entry == nullptr) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
} }
@ -479,7 +479,7 @@ static RPCHelpMan getmempoolancestors()
UniValue o(UniValue::VOBJ); UniValue o(UniValue::VOBJ);
for (CTxMemPool::txiter ancestorIt : ancestors) { for (CTxMemPool::txiter ancestorIt : ancestors) {
const CTxMemPoolEntry &e = *ancestorIt; const CTxMemPoolEntry &e = *ancestorIt;
const uint256& _hash = e.GetTx().GetHash(); const Txid& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ); UniValue info(UniValue::VOBJ);
entryToJSON(mempool, info, e); entryToJSON(mempool, info, e);
o.pushKV(_hash.ToString(), std::move(info)); o.pushKV(_hash.ToString(), std::move(info));
@ -518,7 +518,7 @@ static RPCHelpMan getmempooldescendants()
if (!request.params[1].isNull()) if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool(); fVerbose = request.params[1].get_bool();
uint256 hash = ParseHashV(request.params[0], "parameter 1"); Txid hash = Txid::FromUint256(ParseHashV(request.params[0], "parameter 1"));
const CTxMemPool& mempool = EnsureAnyMemPool(request.context); const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
LOCK(mempool.cs); LOCK(mempool.cs);
@ -544,7 +544,7 @@ static RPCHelpMan getmempooldescendants()
UniValue o(UniValue::VOBJ); UniValue o(UniValue::VOBJ);
for (CTxMemPool::txiter descendantIt : setDescendants) { for (CTxMemPool::txiter descendantIt : setDescendants) {
const CTxMemPoolEntry &e = *descendantIt; const CTxMemPoolEntry &e = *descendantIt;
const uint256& _hash = e.GetTx().GetHash(); const Txid& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ); UniValue info(UniValue::VOBJ);
entryToJSON(mempool, info, e); entryToJSON(mempool, info, e);
o.pushKV(_hash.ToString(), std::move(info)); o.pushKV(_hash.ToString(), std::move(info));
@ -570,12 +570,12 @@ static RPCHelpMan getmempoolentry()
}, },
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{ {
uint256 hash = ParseHashV(request.params[0], "parameter 1"); Txid hash = Txid::FromUint256(ParseHashV(request.params[0], "parameter 1"));
const CTxMemPool& mempool = EnsureAnyMemPool(request.context); const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
LOCK(mempool.cs); LOCK(mempool.cs);
const auto entry{mempool.GetEntry(Txid::FromUint256(hash))}; const auto entry{mempool.GetEntry(hash)};
if (entry == nullptr) { if (entry == nullptr) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
} }
@ -1030,7 +1030,7 @@ static RPCHelpMan submitpackage()
// Belt-and-suspenders check; everything should be successful here // Belt-and-suspenders check; everything should be successful here
CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size()); CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size());
for (const auto& tx : txns) { for (const auto& tx : txns) {
CHECK_NONFATAL(mempool.exists(GenTxid::Txid(tx->GetHash()))); CHECK_NONFATAL(mempool.exists(tx->GetHash()));
} }
break; break;
} }
@ -1054,7 +1054,7 @@ static RPCHelpMan submitpackage()
size_t num_broadcast{0}; size_t num_broadcast{0};
for (const auto& tx : txns) { for (const auto& tx : txns) {
// We don't want to re-submit the txn for validation in BroadcastTransaction // We don't want to re-submit the txn for validation in BroadcastTransaction
if (!mempool.exists(GenTxid::Txid(tx->GetHash()))) { if (!mempool.exists(tx->GetHash())) {
continue; continue;
} }
@ -1072,7 +1072,7 @@ static RPCHelpMan submitpackage()
UniValue rpc_result{UniValue::VOBJ}; UniValue rpc_result{UniValue::VOBJ};
rpc_result.pushKV("package_msg", package_msg); rpc_result.pushKV("package_msg", package_msg);
UniValue tx_result_map{UniValue::VOBJ}; UniValue tx_result_map{UniValue::VOBJ};
std::set<uint256> replaced_txids; std::set<Txid> replaced_txids;
for (const auto& tx : txns) { for (const auto& tx : txns) {
UniValue result_inner{UniValue::VOBJ}; UniValue result_inner{UniValue::VOBJ};
result_inner.pushKV("txid", tx->GetHash().GetHex()); result_inner.pushKV("txid", tx->GetHash().GetHex());
@ -1116,7 +1116,7 @@ static RPCHelpMan submitpackage()
} }
rpc_result.pushKV("tx-results", std::move(tx_result_map)); rpc_result.pushKV("tx-results", std::move(tx_result_map));
UniValue replaced_list(UniValue::VARR); UniValue replaced_list(UniValue::VARR);
for (const uint256& hash : replaced_txids) replaced_list.push_back(hash.ToString()); for (const Txid& hash : replaced_txids) replaced_list.push_back(hash.ToString());
rpc_result.pushKV("replaced-transactions", std::move(replaced_list)); rpc_result.pushKV("replaced-transactions", std::move(replaced_list));
return rpc_result; return rpc_result;
}, },

View file

@ -352,7 +352,7 @@ static RPCHelpMan generateblock()
const auto& str{raw_txs_or_txids[i].get_str()}; const auto& str{raw_txs_or_txids[i].get_str()};
CMutableTransaction mtx; CMutableTransaction mtx;
if (auto hash{uint256::FromHex(str)}) { if (auto hash{Txid::FromHex(str)}) {
const auto tx{mempool.get(*hash)}; const auto tx{mempool.get(*hash)};
if (!tx) { if (!tx) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Transaction %s not in mempool.", str)); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Transaction %s not in mempool.", str));
@ -516,7 +516,7 @@ static RPCHelpMan prioritisetransaction()
{ {
LOCK(cs_main); LOCK(cs_main);
uint256 hash(ParseHashV(request.params[0], "txid")); Txid hash = Txid::FromUint256((ParseHashV(request.params[0], "txid")));
const auto dummy{self.MaybeArg<double>("dummy")}; const auto dummy{self.MaybeArg<double>("dummy")};
CAmount nAmount = request.params[2].getInt<int64_t>(); CAmount nAmount = request.params[2].getInt<int64_t>();
@ -890,14 +890,14 @@ static RPCHelpMan getblocktemplate()
UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
UniValue transactions(UniValue::VARR); UniValue transactions(UniValue::VARR);
std::map<uint256, int64_t> setTxIndex; std::map<Txid, int64_t> setTxIndex;
std::vector<CAmount> tx_fees{block_template->getTxFees()}; std::vector<CAmount> tx_fees{block_template->getTxFees()};
std::vector<CAmount> tx_sigops{block_template->getTxSigops()}; std::vector<CAmount> tx_sigops{block_template->getTxSigops()};
int i = 0; int i = 0;
for (const auto& it : block.vtx) { for (const auto& it : block.vtx) {
const CTransaction& tx = *it; const CTransaction& tx = *it;
uint256 txHash = tx.GetHash(); Txid txHash = tx.GetHash();
setTxIndex[txHash] = i++; setTxIndex[txHash] = i++;
if (tx.IsCoinBase()) if (tx.IsCoinBase())

View file

@ -319,10 +319,10 @@ static RPCHelpMan getrawtransaction()
const NodeContext& node = EnsureAnyNodeContext(request.context); const NodeContext& node = EnsureAnyNodeContext(request.context);
ChainstateManager& chainman = EnsureChainman(node); ChainstateManager& chainman = EnsureChainman(node);
uint256 hash = ParseHashV(request.params[0], "parameter 1"); Txid hash = Txid::FromUint256(ParseHashV(request.params[0], "parameter 1"));
const CBlockIndex* blockindex = nullptr; const CBlockIndex* blockindex = nullptr;
if (hash == chainman.GetParams().GenesisBlock().hashMerkleRoot) { if (hash.ToUint256() == chainman.GetParams().GenesisBlock().hashMerkleRoot) {
// Special exception for the genesis block coinbase transaction // Special exception for the genesis block coinbase transaction
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved");
} }

View file

@ -59,9 +59,9 @@ static uint256 ComputeModifiedMerkleRoot(const CMutableTransaction& cb, const CB
{ {
std::vector<uint256> leaves; std::vector<uint256> leaves;
leaves.resize(block.vtx.size()); leaves.resize(block.vtx.size());
leaves[0] = cb.GetHash(); leaves[0] = cb.GetHash().ToUint256();
for (size_t s = 1; s < block.vtx.size(); ++s) { 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)); return ComputeMerkleRoot(std::move(leaves));
} }

View file

@ -154,7 +154,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
AddToMempool(pool, entry.FromTx(block.vtx[2])); AddToMempool(pool, entry.FromTx(block.vtx[2]));
BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0); BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
uint256 txhash; Txid txhash;
// Test with pre-forwarding tx 1, but not coinbase // Test with pre-forwarding tx 1, but not coinbase
{ {
@ -225,7 +225,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
AddToMempool(pool, entry.FromTx(block.vtx[1])); AddToMempool(pool, entry.FromTx(block.vtx[1]));
BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()).use_count(), SHARED_TX_OFFSET + 0); BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
uint256 txhash; Txid txhash;
// Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool // Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool
{ {

View file

@ -22,7 +22,7 @@ BOOST_AUTO_TEST_CASE(disconnectpool_memory_limits)
// is within an expected range. // is within an expected range.
// Overhead for the hashmap depends on number of buckets // Overhead for the hashmap depends on number of buckets
std::unordered_map<uint256, CTransaction*, SaltedTxidHasher> temp_map; std::unordered_map<uint256, CTransaction*, SaltedUint256Hasher> temp_map;
temp_map.reserve(1); temp_map.reserve(1);
const size_t MAP_1{memusage::DynamicUsage(temp_map)}; const size_t MAP_1{memusage::DynamicUsage(temp_map)};
temp_map.reserve(100); temp_map.reserve(100);

View file

@ -173,7 +173,7 @@ FUZZ_TARGET(mini_miner_selection, .init = initialize_miner)
if (!pool.GetConflictTx(coin)) outpoints.push_back(coin); if (!pool.GetConflictTx(coin)) outpoints.push_back(coin);
} }
for (const auto& tx : transactions) { for (const auto& tx : transactions) {
assert(pool.exists(GenTxid::Txid(tx->GetHash()))); assert(pool.exists(tx->GetHash()));
for (uint32_t n{0}; n < tx->vout.size(); ++n) { for (uint32_t n{0}; n < tx->vout.size(); ++n) {
COutPoint coin{tx->GetHash(), n}; COutPoint coin{tx->GetHash(), n};
if (!pool.GetConflictTx(coin)) outpoints.push_back(coin); if (!pool.GetConflictTx(coin)) outpoints.push_back(coin);

View file

@ -139,7 +139,7 @@ CBlock ConsumeBlock(FuzzedDataProvider& fuzzed_data_provider, const uint256& pre
tx.vout[0].nValue = 0; tx.vout[0].nValue = 0;
tx.vin[0].scriptSig.resize(2); tx.vin[0].scriptSig.resize(2);
block.vtx.push_back(MakeTransactionRef(tx)); block.vtx.push_back(MakeTransactionRef(tx));
block.hashMerkleRoot = block.vtx[0]->GetHash(); block.hashMerkleRoot = block.vtx[0]->GetHash().ToUint256();
return block; return block;
} }

View file

@ -310,10 +310,10 @@ FUZZ_TARGET(ephemeral_package_eval, .init = initialize_tx_pool)
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN); const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
// We only prioritise out of mempool transactions since PrioritiseTransaction doesn't // We only prioritise out of mempool transactions since PrioritiseTransaction doesn't
// filter for ephemeral dust // filter for ephemeral dust
if (tx_pool.exists(GenTxid::Txid(txid))) { if (tx_pool.exists(txid)) {
const auto tx_info{tx_pool.info(GenTxid::Txid(txid))}; const auto tx_info{tx_pool.info(txid)};
if (GetDust(*tx_info.tx, tx_pool.m_opts.dust_relay_feerate).empty()) { if (GetDust(*tx_info.tx, tx_pool.m_opts.dust_relay_feerate).empty()) {
tx_pool.PrioritiseTransaction(txid.ToUint256(), delta); tx_pool.PrioritiseTransaction(txid, delta);
} }
} }
} }
@ -476,7 +476,7 @@ FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool)
txs.back()->GetHash() : txs.back()->GetHash() :
PickValue(fuzzed_data_provider, mempool_outpoints).hash; PickValue(fuzzed_data_provider, mempool_outpoints).hash;
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN); const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
tx_pool.PrioritiseTransaction(txid.ToUint256(), delta); tx_pool.PrioritiseTransaction(txid, delta);
} }
// Remember all added transactions // Remember all added transactions

View file

@ -79,7 +79,7 @@ FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb)
available.insert(i); available.insert(i);
} }
if (add_to_mempool && !pool.exists(GenTxid::Txid(tx->GetHash()))) { if (add_to_mempool && !pool.exists(tx->GetHash())) {
LOCK2(cs_main, pool.cs); LOCK2(cs_main, pool.cs);
AddToMempool(pool, ConsumeTxMemPoolEntry(fuzzed_data_provider, *tx)); AddToMempool(pool, ConsumeTxMemPoolEntry(fuzzed_data_provider, *tx));
available.insert(i); available.insert(i);

View file

@ -85,7 +85,7 @@ FUZZ_TARGET(policy_estimator, .init = initialize_policy_estimator)
block_policy_estimator.processBlock(txs, current_height); block_policy_estimator.processBlock(txs, current_height);
}, },
[&] { [&] {
(void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider)); (void)block_policy_estimator.removeTx(Txid::FromUint256(ConsumeUInt256(fuzzed_data_provider)));
}, },
[&] { [&] {
block_policy_estimator.FlushUnconfirmed(); block_policy_estimator.FlushUnconfirmed();

View file

@ -160,7 +160,7 @@ FUZZ_TARGET(package_rbf, .init = initialize_package_rbf)
} }
if (fuzzed_data_provider.ConsumeBool()) { if (fuzzed_data_provider.ConsumeBool()) {
pool.PrioritiseTransaction(mempool_txs.back().GetHash().ToUint256(), fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(-100000, 100000)); pool.PrioritiseTransaction(mempool_txs.back().GetHash(), fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(-100000, 100000));
} }
} }

View file

@ -287,7 +287,7 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
tx->GetHash() : tx->GetHash() :
PickValue(fuzzed_data_provider, outpoints_rbf).hash; PickValue(fuzzed_data_provider, outpoints_rbf).hash;
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN); const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
tx_pool.PrioritiseTransaction(txid.ToUint256(), delta); tx_pool.PrioritiseTransaction(txid, delta);
} }
// Remember all removed and added transactions // Remember all removed and added transactions
@ -315,8 +315,8 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
node.validation_signals->SyncWithValidationInterfaceQueue(); node.validation_signals->SyncWithValidationInterfaceQueue();
node.validation_signals->UnregisterSharedValidationInterface(txr); node.validation_signals->UnregisterSharedValidationInterface(txr);
bool txid_in_mempool = tx_pool.exists(GenTxid::Txid(tx->GetHash())); bool txid_in_mempool = tx_pool.exists(tx->GetHash());
bool wtxid_in_mempool = tx_pool.exists(GenTxid::Wtxid(tx->GetWitnessHash())); bool wtxid_in_mempool = tx_pool.exists(tx->GetWitnessHash());
CheckATMPInvariants(res, txid_in_mempool, wtxid_in_mempool); CheckATMPInvariants(res, txid_in_mempool, wtxid_in_mempool);
Assert(accepted != added.empty()); Assert(accepted != added.empty());
@ -408,7 +408,7 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
mut_tx.GetHash() : mut_tx.GetHash() :
PickValue(fuzzed_data_provider, txids); PickValue(fuzzed_data_provider, txids);
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN); const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
tx_pool.PrioritiseTransaction(txid.ToUint256(), delta); tx_pool.PrioritiseTransaction(txid, delta);
} }
const auto tx = MakeTransactionRef(mut_tx); const auto tx = MakeTransactionRef(mut_tx);

View file

@ -227,9 +227,12 @@ FUZZ_TARGET(txdownloadman, .init = initialize)
Assert(first_time_failure || !todo.m_should_add_extra_compact_tx); Assert(first_time_failure || !todo.m_should_add_extra_compact_tx);
}, },
[&] { [&] {
GenTxid gtxid = fuzzed_data_provider.ConsumeBool() ? GenTxid gtxid;
GenTxid::Txid(rand_tx->GetHash()) : if (fuzzed_data_provider.ConsumeBool()) {
GenTxid::Wtxid(rand_tx->GetWitnessHash()); rand_tx->GetHash();
} else {
rand_tx->GetWitnessHash();
}
txdownloadman.AddTxAnnouncement(rand_peer, gtxid, time); txdownloadman.AddTxAnnouncement(rand_peer, gtxid, time);
}, },
[&] { [&] {
@ -373,9 +376,12 @@ FUZZ_TARGET(txdownloadman_impl, .init = initialize)
if (!reject_contains_wtxid) Assert(todo.m_unique_parents.size() <= rand_tx->vin.size()); if (!reject_contains_wtxid) Assert(todo.m_unique_parents.size() <= rand_tx->vin.size());
}, },
[&] { [&] {
GenTxid gtxid = fuzzed_data_provider.ConsumeBool() ? GenTxid gtxid;
GenTxid::Txid(rand_tx->GetHash()) : if (fuzzed_data_provider.ConsumeBool()) {
GenTxid::Wtxid(rand_tx->GetWitnessHash()); rand_tx->GetHash();
} else {
rand_tx->GetWitnessHash();
}
txdownload_impl.AddTxAnnouncement(rand_peer, gtxid, time); txdownload_impl.AddTxAnnouncement(rand_peer, gtxid, time);
}, },
[&] { [&] {
@ -395,7 +401,7 @@ FUZZ_TARGET(txdownloadman_impl, .init = initialize)
// The only combination that doesn't make sense is validate both tx and package. // The only combination that doesn't make sense is validate both tx and package.
Assert(!(should_validate && maybe_package.has_value())); Assert(!(should_validate && maybe_package.has_value()));
if (should_validate) { if (should_validate) {
Assert(!txdownload_impl.AlreadyHaveTx(GenTxid::Wtxid(rand_tx->GetWitnessHash()), /*include_reconsiderable=*/true)); Assert(!txdownload_impl.AlreadyHaveTx(rand_tx->GetWitnessHash(), /*include_reconsiderable=*/true));
} }
if (maybe_package.has_value()) { if (maybe_package.has_value()) {
CheckPackageToValidate(*maybe_package, rand_peer); CheckPackageToValidate(*maybe_package, rand_peer);
@ -424,7 +430,7 @@ FUZZ_TARGET(txdownloadman_impl, .init = initialize)
// However, if there was a non-null tx in the workset, HaveMoreWork should have // However, if there was a non-null tx in the workset, HaveMoreWork should have
// returned true. // returned true.
Assert(expect_work); Assert(expect_work);
Assert(txdownload_impl.AlreadyHaveTx(GenTxid::Wtxid(ptx->GetWitnessHash()), /*include_reconsiderable=*/false)); Assert(txdownload_impl.AlreadyHaveTx(ptx->GetWitnessHash(), /*include_reconsiderable=*/false));
// Presumably we have validated this tx. Use "missing inputs" to keep it in the // Presumably we have validated this tx. Use "missing inputs" to keep it in the
// orphanage longer. Later iterations might call MempoolAcceptedTx or // orphanage longer. Later iterations might call MempoolAcceptedTx or
// MempoolRejectedTx with a different error. // MempoolRejectedTx with a different error.

View file

@ -20,7 +20,7 @@ constexpr int MAX_TXHASHES = 16;
constexpr int MAX_PEERS = 16; constexpr int MAX_PEERS = 16;
//! Randomly generated GenTxids used in this test (length is MAX_TXHASHES). //! Randomly generated GenTxids used in this test (length is MAX_TXHASHES).
uint256 TXHASHES[MAX_TXHASHES]; GenTxid TXHASHES[MAX_TXHASHES];
//! Precomputed random durations (positive and negative, each ~exponentially distributed). //! Precomputed random durations (positive and negative, each ~exponentially distributed).
std::chrono::microseconds DELAYS[256]; std::chrono::microseconds DELAYS[256];
@ -30,7 +30,13 @@ struct Initializer
Initializer() Initializer()
{ {
for (uint8_t txhash = 0; txhash < MAX_TXHASHES; txhash += 1) { for (uint8_t txhash = 0; txhash < MAX_TXHASHES; txhash += 1) {
CSHA256().Write(&txhash, 1).Finalize(TXHASHES[txhash].begin()); uint256 hash;
CSHA256().Write(&txhash, 1).Finalize(hash.begin());
if (txhash % 2 == 0) {
TXHASHES[txhash] = Txid::FromUint256(hash);
} else {
TXHASHES[txhash] = Wtxid::FromUint256(hash);
}
} }
int i = 0; int i = 0;
// DELAYS[N] for N=0..15 is just N microseconds. // DELAYS[N] for N=0..15 is just N microseconds.
@ -94,7 +100,6 @@ class Tester
uint64_t m_sequence; uint64_t m_sequence;
State m_state{State::NOTHING}; State m_state{State::NOTHING};
bool m_preferred; bool m_preferred;
bool m_is_wtxid;
uint64_t m_priority; //!< Precomputed priority. uint64_t m_priority; //!< Precomputed priority.
}; };
@ -186,7 +191,7 @@ public:
m_tracker.ForgetTxHash(TXHASHES[txhash]); m_tracker.ForgetTxHash(TXHASHES[txhash]);
} }
void ReceivedInv(int peer, int txhash, bool is_wtxid, bool preferred, std::chrono::microseconds reqtime) void ReceivedInv(int peer, int txhash, bool preferred, std::chrono::microseconds reqtime)
{ {
// Apply to naive structure: if no announcement for txidnum/peer combination // Apply to naive structure: if no announcement for txidnum/peer combination
// already, create a new CANDIDATE; otherwise do nothing. // already, create a new CANDIDATE; otherwise do nothing.
@ -195,7 +200,6 @@ public:
ann.m_preferred = preferred; ann.m_preferred = preferred;
ann.m_state = State::CANDIDATE; ann.m_state = State::CANDIDATE;
ann.m_time = reqtime; ann.m_time = reqtime;
ann.m_is_wtxid = is_wtxid;
ann.m_sequence = m_current_sequence++; ann.m_sequence = m_current_sequence++;
ann.m_priority = m_tracker.ComputePriority(TXHASHES[txhash], peer, ann.m_preferred); ann.m_priority = m_tracker.ComputePriority(TXHASHES[txhash], peer, ann.m_preferred);
@ -204,7 +208,7 @@ public:
} }
// Call TxRequestTracker's implementation. // Call TxRequestTracker's implementation.
m_tracker.ReceivedInv(peer, is_wtxid ? GenTxid::Wtxid(TXHASHES[txhash]) : GenTxid::Txid(TXHASHES[txhash]), preferred, reqtime); m_tracker.ReceivedInv(peer, TXHASHES[txhash], preferred, reqtime);
} }
void RequestedTx(int peer, int txhash, std::chrono::microseconds exptime) void RequestedTx(int peer, int txhash, std::chrono::microseconds exptime)
@ -252,7 +256,7 @@ public:
for (int peer2 = 0; peer2 < MAX_PEERS; ++peer2) { for (int peer2 = 0; peer2 < MAX_PEERS; ++peer2) {
Announcement& ann2 = m_announcements[txhash][peer2]; Announcement& ann2 = m_announcements[txhash][peer2];
if (ann2.m_state == State::REQUESTED && ann2.m_time <= m_now) { if (ann2.m_state == State::REQUESTED && ann2.m_time <= m_now) {
expected_expired.emplace_back(peer2, ann2.m_is_wtxid ? GenTxid::Wtxid(TXHASHES[txhash]) : GenTxid::Txid(TXHASHES[txhash])); expected_expired.emplace_back(peer2, TXHASHES[txhash]);
ann2.m_state = State::COMPLETED; ann2.m_state = State::COMPLETED;
break; break;
} }
@ -262,7 +266,7 @@ public:
// CANDIDATEs for which this announcement has the highest priority get returned. // CANDIDATEs for which this announcement has the highest priority get returned.
const Announcement& ann = m_announcements[txhash][peer]; const Announcement& ann = m_announcements[txhash][peer];
if (ann.m_state == State::CANDIDATE && GetSelected(txhash) == peer) { if (ann.m_state == State::CANDIDATE && GetSelected(txhash) == peer) {
result.emplace_back(ann.m_sequence, txhash, ann.m_is_wtxid); result.emplace_back(ann.m_sequence, txhash, std::holds_alternative<Wtxid>(TXHASHES[txhash]));
} }
} }
// Sort the results by sequence number. // Sort the results by sequence number.
@ -278,8 +282,8 @@ public:
m_tracker.PostGetRequestableSanityCheck(m_now); m_tracker.PostGetRequestableSanityCheck(m_now);
assert(result.size() == actual.size()); assert(result.size() == actual.size());
for (size_t pos = 0; pos < actual.size(); ++pos) { for (size_t pos = 0; pos < actual.size(); ++pos) {
assert(TXHASHES[std::get<1>(result[pos])] == actual[pos].GetHash()); assert(TXHASHES[std::get<1>(result[pos])] == actual[pos]);
assert(std::get<2>(result[pos]) == actual[pos].IsWtxid()); assert(std::get<2>(result[pos]) == std::holds_alternative<Wtxid>(actual[pos]));
} }
} }
@ -357,16 +361,14 @@ FUZZ_TARGET(txrequest)
case 6: // Same, but non-preferred. case 6: // Same, but non-preferred.
peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS; peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS;
txidnum = it == buffer.end() ? 0 : *(it++); txidnum = it == buffer.end() ? 0 : *(it++);
tester.ReceivedInv(peer, txidnum % MAX_TXHASHES, (txidnum / MAX_TXHASHES) & 1, cmd & 1, tester.ReceivedInv(peer, txidnum % MAX_TXHASHES, cmd & 1, std::chrono::microseconds::min());
std::chrono::microseconds::min());
break; break;
case 7: // Received delayed preferred inv case 7: // Received delayed preferred inv
case 8: // Same, but non-preferred. case 8: // Same, but non-preferred.
peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS; peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS;
txidnum = it == buffer.end() ? 0 : *(it++); txidnum = it == buffer.end() ? 0 : *(it++);
delaynum = it == buffer.end() ? 0 : *(it++); delaynum = it == buffer.end() ? 0 : *(it++);
tester.ReceivedInv(peer, txidnum % MAX_TXHASHES, (txidnum / MAX_TXHASHES) & 1, cmd & 1, tester.ReceivedInv(peer, txidnum % MAX_TXHASHES, cmd & 1, tester.Now() + DELAYS[delaynum]);
tester.Now() + DELAYS[delaynum]);
break; break;
case 9: // Requested tx from peer case 9: // Requested tx from peer
peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS; peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS;

View file

@ -454,12 +454,12 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
AddToMempool(pool, entry.Fee(5000LL).FromTx(tx2)); AddToMempool(pool, entry.Fee(5000LL).FromTx(tx2));
pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing
BOOST_CHECK(pool.exists(GenTxid::Txid(tx1.GetHash()))); BOOST_CHECK(pool.exists(tx1.GetHash()));
BOOST_CHECK(pool.exists(GenTxid::Txid(tx2.GetHash()))); BOOST_CHECK(pool.exists(tx2.GetHash()));
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction
BOOST_CHECK(pool.exists(GenTxid::Txid(tx1.GetHash()))); BOOST_CHECK(pool.exists(tx1.GetHash()));
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx2.GetHash()))); BOOST_CHECK(!pool.exists(tx2.GetHash()));
AddToMempool(pool, entry.FromTx(tx2)); AddToMempool(pool, entry.FromTx(tx2));
CMutableTransaction tx3 = CMutableTransaction(); CMutableTransaction tx3 = CMutableTransaction();
@ -472,14 +472,14 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
AddToMempool(pool, entry.Fee(20000LL).FromTx(tx3)); AddToMempool(pool, entry.Fee(20000LL).FromTx(tx3));
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP) pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx1.GetHash()))); BOOST_CHECK(!pool.exists(tx1.GetHash()));
BOOST_CHECK(pool.exists(GenTxid::Txid(tx2.GetHash()))); BOOST_CHECK(pool.exists(tx2.GetHash()));
BOOST_CHECK(pool.exists(GenTxid::Txid(tx3.GetHash()))); BOOST_CHECK(pool.exists(tx3.GetHash()));
pool.TrimToSize(GetVirtualTransactionSize(CTransaction(tx1))); // mempool is limited to tx1's size in memory usage, so nothing fits pool.TrimToSize(GetVirtualTransactionSize(CTransaction(tx1))); // mempool is limited to tx1's size in memory usage, so nothing fits
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx1.GetHash()))); BOOST_CHECK(!pool.exists(tx1.GetHash()));
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx2.GetHash()))); BOOST_CHECK(!pool.exists(tx2.GetHash()));
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx3.GetHash()))); BOOST_CHECK(!pool.exists(tx3.GetHash()));
CFeeRate maxFeeRateRemoved(25000, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2))); CFeeRate maxFeeRateRemoved(25000, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2)));
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000); BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
@ -539,19 +539,19 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
// we only require this to remove, at max, 2 txn, because it's not clear what we're really optimizing for aside from that // we only require this to remove, at max, 2 txn, because it's not clear what we're really optimizing for aside from that
pool.TrimToSize(pool.DynamicMemoryUsage() - 1); pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
BOOST_CHECK(pool.exists(GenTxid::Txid(tx4.GetHash()))); BOOST_CHECK(pool.exists(tx4.GetHash()));
BOOST_CHECK(pool.exists(GenTxid::Txid(tx6.GetHash()))); BOOST_CHECK(pool.exists(tx6.GetHash()));
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx7.GetHash()))); BOOST_CHECK(!pool.exists(tx7.GetHash()));
if (!pool.exists(GenTxid::Txid(tx5.GetHash()))) if (!pool.exists(tx5.GetHash()))
AddToMempool(pool, entry.Fee(1000LL).FromTx(tx5)); AddToMempool(pool, entry.Fee(1000LL).FromTx(tx5));
AddToMempool(pool, entry.Fee(9000LL).FromTx(tx7)); AddToMempool(pool, entry.Fee(9000LL).FromTx(tx7));
pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7 pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7
BOOST_CHECK(pool.exists(GenTxid::Txid(tx4.GetHash()))); BOOST_CHECK(pool.exists(tx4.GetHash()));
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx5.GetHash()))); BOOST_CHECK(!pool.exists(tx5.GetHash()));
BOOST_CHECK(pool.exists(GenTxid::Txid(tx6.GetHash()))); BOOST_CHECK(pool.exists(tx6.GetHash()));
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx7.GetHash()))); BOOST_CHECK(!pool.exists(tx7.GetHash()));
AddToMempool(pool, entry.Fee(1000LL).FromTx(tx5)); AddToMempool(pool, entry.Fee(1000LL).FromTx(tx5));
AddToMempool(pool, entry.Fee(9000LL).FromTx(tx7)); AddToMempool(pool, entry.Fee(9000LL).FromTx(tx7));

View file

@ -29,7 +29,7 @@ static uint256 BlockBuildMerkleTree(const CBlock& block, bool* fMutated, std::ve
vMerkleTree.clear(); vMerkleTree.clear();
vMerkleTree.reserve(block.vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes. 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) 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; int j = 0;
bool mutated = false; bool mutated = false;
for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) 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> newBranch = TransactionMerklePath(block, mtx);
std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx); std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx);
BOOST_CHECK(oldBranch == newBranch); 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; mtx.nLockTime = 0;
block.vtx[0] = MakeTransactionRef(std::move(mtx)); block.vtx[0] = MakeTransactionRef(std::move(mtx));
uint256 root = BlockMerkleRoot(block, &mutated); 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); BOOST_CHECK_EQUAL(mutated, false);
} }
@ -239,7 +239,7 @@ BOOST_AUTO_TEST_CASE(merkle_test_BlockWitness)
std::vector<uint256> hashes; std::vector<uint256> hashes;
hashes.resize(block.vtx.size()); hashes.resize(block.vtx.size());
hashes[0].SetNull(); hashes[0].SetNull();
hashes[1] = block.vtx[1]->GetHash(); hashes[1] = block.vtx[1]->GetHash().ToUint256();
uint256 merkleRootofHashes = ComputeMerkleRoot(hashes); uint256 merkleRootofHashes = ComputeMerkleRoot(hashes);

View file

@ -591,7 +591,7 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const
tx.vin[0].scriptSig = CScript() << OP_1; tx.vin[0].scriptSig = CScript() << OP_1;
tx.vout.resize(1); tx.vout.resize(1);
tx.vout[0].nValue = 5000000000LL; // 0 fee tx.vout[0].nValue = 5000000000LL; // 0 fee
uint256 hashFreePrioritisedTx = tx.GetHash(); Txid hashFreePrioritisedTx = tx.GetHash();
AddToMempool(tx_mempool, entry.Fee(0).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)); AddToMempool(tx_mempool, entry.Fee(0).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
tx_mempool.PrioritiseTransaction(hashFreePrioritisedTx, 5 * COIN); tx_mempool.PrioritiseTransaction(hashFreePrioritisedTx, 5 * COIN);

View file

@ -103,7 +103,7 @@ BOOST_FIXTURE_TEST_CASE(miniminer_negative, TestChain100Setup)
mini_miner_no_target.BuildMockTemplate(std::nullopt); mini_miner_no_target.BuildMockTemplate(std::nullopt);
const auto template_txids{mini_miner_no_target.GetMockTemplateTxids()}; const auto template_txids{mini_miner_no_target.GetMockTemplateTxids()};
BOOST_CHECK_EQUAL(template_txids.size(), 1); BOOST_CHECK_EQUAL(template_txids.size(), 1);
BOOST_CHECK(template_txids.count(tx_mod_negative->GetHash().ToUint256()) > 0); BOOST_CHECK(template_txids.count(tx_mod_negative->GetHash()) > 0);
} }
BOOST_FIXTURE_TEST_CASE(miniminer_1p1c, TestChain100Setup) BOOST_FIXTURE_TEST_CASE(miniminer_1p1c, TestChain100Setup)
@ -177,7 +177,7 @@ BOOST_FIXTURE_TEST_CASE(miniminer_1p1c, TestChain100Setup)
struct TxDimensions { struct TxDimensions {
int32_t vsize; CAmount mod_fee; CFeeRate feerate; int32_t vsize; CAmount mod_fee; CFeeRate feerate;
}; };
std::map<uint256, TxDimensions> tx_dims; std::map<Txid, TxDimensions> tx_dims;
for (const auto& tx : all_transactions) { for (const auto& tx : all_transactions) {
const auto& entry{*Assert(pool.GetEntry(tx->GetHash()))}; const auto& entry{*Assert(pool.GetEntry(tx->GetHash()))};
tx_dims.emplace(tx->GetHash(), TxDimensions{entry.GetTxSize(), entry.GetModifiedFee(), tx_dims.emplace(tx->GetHash(), TxDimensions{entry.GetTxSize(), entry.GetModifiedFee(),
@ -590,14 +590,6 @@ BOOST_FIXTURE_TEST_CASE(calculate_cluster, TestChain100Setup)
CTxMemPool& pool = *Assert(m_node.mempool); CTxMemPool& pool = *Assert(m_node.mempool);
LOCK2(cs_main, pool.cs); LOCK2(cs_main, pool.cs);
// TODO this can be removed once the mempool interface uses Txid, Wtxid
auto convert_to_uint256_vec = [](const std::vector<Txid>& vec) -> std::vector<uint256> {
std::vector<uint256> out;
std::transform(vec.begin(), vec.end(), std::back_inserter(out),
[](const Txid& txid) { return txid.ToUint256(); });
return out;
};
// Add chain of size 500 // Add chain of size 500
TestMemPoolEntryHelper entry; TestMemPoolEntryHelper entry;
std::vector<Txid> chain_txids; std::vector<Txid> chain_txids;
@ -611,7 +603,7 @@ BOOST_FIXTURE_TEST_CASE(calculate_cluster, TestChain100Setup)
const auto cluster_500tx = pool.GatherClusters({lasttx->GetHash()}); const auto cluster_500tx = pool.GatherClusters({lasttx->GetHash()});
CTxMemPool::setEntries cluster_500tx_set{cluster_500tx.begin(), cluster_500tx.end()}; CTxMemPool::setEntries cluster_500tx_set{cluster_500tx.begin(), cluster_500tx.end()};
BOOST_CHECK_EQUAL(cluster_500tx.size(), cluster_500tx_set.size()); BOOST_CHECK_EQUAL(cluster_500tx.size(), cluster_500tx_set.size());
const auto vec_iters_500 = pool.GetIterVec(convert_to_uint256_vec(chain_txids)); const auto vec_iters_500 = pool.GetIterVec(chain_txids);
for (const auto& iter : vec_iters_500) BOOST_CHECK(cluster_500tx_set.count(iter)); for (const auto& iter : vec_iters_500) BOOST_CHECK(cluster_500tx_set.count(iter));
// GatherClusters stops at 500 transactions. // GatherClusters stops at 500 transactions.
@ -637,7 +629,7 @@ BOOST_FIXTURE_TEST_CASE(calculate_cluster, TestChain100Setup)
AddToMempool(pool, entry.Fee(CENT).FromTx(txc)); AddToMempool(pool, entry.Fee(CENT).FromTx(txc));
zigzag_txids.push_back(txc->GetHash()); zigzag_txids.push_back(txc->GetHash());
} }
const auto vec_iters_zigzag = pool.GetIterVec(convert_to_uint256_vec(zigzag_txids)); const auto vec_iters_zigzag = pool.GetIterVec(zigzag_txids);
// It doesn't matter which tx we calculate cluster for, everybody is in it. // It doesn't matter which tx we calculate cluster for, everybody is in it.
const std::vector<size_t> indices{0, 22, 72, zigzag_txids.size() - 1}; const std::vector<size_t> indices{0, 22, 72, zigzag_txids.size() - 1};
for (const auto index : indices) { for (const auto index : indices) {

View file

@ -50,7 +50,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
uint256 merkleRoot1 = BlockMerkleRoot(block); uint256 merkleRoot1 = BlockMerkleRoot(block);
std::vector<uint256> vTxid(nTx, uint256()); std::vector<uint256> vTxid(nTx, uint256());
for (unsigned int j=0; j<nTx; j++) for (unsigned int j=0; j<nTx; j++)
vTxid[j] = block.vtx[j]->GetHash(); vTxid[j] = block.vtx[j]->GetHash().ToUint256();
int nHeight = 1, nTx_ = nTx; int nHeight = 1, nTx_ = nTx;
while (nTx_ > 1) { while (nTx_ > 1) {
nTx_ = (nTx_+1)/2; nTx_ = (nTx_+1)/2;

View file

@ -37,7 +37,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
// added to the mempool by their associate fee // added to the mempool by their associate fee
// txHashes[j] is populated with transactions either of // txHashes[j] is populated with transactions either of
// fee = basefee * (j+1) // fee = basefee * (j+1)
std::vector<uint256> txHashes[10]; std::vector<Txid> txHashes[10];
// Create a transaction template // Create a transaction template
CScript garbage; CScript garbage;
@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
/*has_no_mempool_parents=*/true)}; /*has_no_mempool_parents=*/true)};
m_node.validation_signals->TransactionAddedToMempool(tx_info, mpool.GetAndIncrementSequence()); m_node.validation_signals->TransactionAddedToMempool(tx_info, mpool.GetAndIncrementSequence());
} }
uint256 hash = tx.GetHash(); Txid hash = tx.GetHash();
txHashes[j].push_back(hash); txHashes[j].push_back(hash);
} }
} }
@ -178,7 +178,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
/*has_no_mempool_parents=*/true)}; /*has_no_mempool_parents=*/true)};
m_node.validation_signals->TransactionAddedToMempool(tx_info, mpool.GetAndIncrementSequence()); m_node.validation_signals->TransactionAddedToMempool(tx_info, mpool.GetAndIncrementSequence());
} }
uint256 hash = tx.GetHash(); Txid hash = tx.GetHash();
txHashes[j].push_back(hash); txHashes[j].push_back(hash);
} }
} }
@ -242,7 +242,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
/*has_no_mempool_parents=*/true)}; /*has_no_mempool_parents=*/true)};
m_node.validation_signals->TransactionAddedToMempool(tx_info, mpool.GetAndIncrementSequence()); m_node.validation_signals->TransactionAddedToMempool(tx_info, mpool.GetAndIncrementSequence());
} }
uint256 hash = tx.GetHash(); Txid hash = tx.GetHash();
CTransactionRef ptx = mpool.get(hash); CTransactionRef ptx = mpool.get(hash);
if (ptx) if (ptx)
block.push_back(ptx); block.push_back(ptx);

View file

@ -196,7 +196,7 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
entry5_low, entry6_low_prioritised, entry7_high, entry8_high}; entry5_low, entry6_low_prioritised, entry7_high, entry8_high};
CTxMemPool::setEntries empty_set; CTxMemPool::setEntries empty_set;
const auto unused_txid{GetRandHash()}; const auto unused_txid = Txid::FromUint256(GetRandHash());
// Tests for PaysMoreThanConflicts // Tests for PaysMoreThanConflicts
// These tests use feerate, not absolute fee. // These tests use feerate, not absolute fee.
@ -293,7 +293,7 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
const auto spends_unconfirmed = make_tx({tx1}, {36 * CENT}); const auto spends_unconfirmed = make_tx({tx1}, {36 * CENT});
for (const auto& input : spends_unconfirmed->vin) { for (const auto& input : spends_unconfirmed->vin) {
// Spends unconfirmed inputs. // Spends unconfirmed inputs.
BOOST_CHECK(pool.exists(GenTxid::Txid(input.prevout.hash))); BOOST_CHECK(pool.exists(input.prevout.hash));
} }
BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(), BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),
/*pool=*/ pool, /*pool=*/ pool,

View file

@ -126,10 +126,10 @@ BOOST_FIXTURE_TEST_CASE(tx_rejection_types, TestChain100Setup)
for (const auto segwit_child : {true, false}) { for (const auto segwit_child : {true, false}) {
const auto ptx_parent = CreatePlaceholderTx(segwit_parent); const auto ptx_parent = CreatePlaceholderTx(segwit_parent);
const auto ptx_child = CreatePlaceholderTx(segwit_child); const auto ptx_child = CreatePlaceholderTx(segwit_child);
const auto& parent_txid = ptx_parent->GetHash().ToUint256(); const auto& parent_txid = ptx_parent->GetHash();
const auto& parent_wtxid = ptx_parent->GetWitnessHash().ToUint256(); const auto& parent_wtxid = ptx_parent->GetWitnessHash();
const auto& child_txid = ptx_child->GetHash().ToUint256(); const auto& child_txid = ptx_child->GetHash();
const auto& child_wtxid = ptx_child->GetWitnessHash().ToUint256(); const auto& child_wtxid = ptx_child->GetWitnessHash();
for (const auto& [result, expected_behavior] : expected_behaviors) { for (const auto& [result, expected_behavior] : expected_behaviors) {
node::TxDownloadManagerImpl txdownload_impl{DEFAULT_OPTS}; node::TxDownloadManagerImpl txdownload_impl{DEFAULT_OPTS};
@ -141,13 +141,13 @@ BOOST_FIXTURE_TEST_CASE(tx_rejection_types, TestChain100Setup)
// No distinction between txid and wtxid caching for nonsegwit transactions, so only test these specific // No distinction between txid and wtxid caching for nonsegwit transactions, so only test these specific
// behaviors for segwit transactions. // behaviors for segwit transactions.
Behaviors actual_behavior{ Behaviors actual_behavior{
/*txid_rejects=*/txdownload_impl.RecentRejectsFilter().contains(parent_txid), /*txid_rejects=*/txdownload_impl.RecentRejectsFilter().contains(parent_txid.ToUint256()),
/*wtxid_rejects=*/txdownload_impl.RecentRejectsFilter().contains(parent_wtxid), /*wtxid_rejects=*/txdownload_impl.RecentRejectsFilter().contains(parent_wtxid.ToUint256()),
/*txid_recon=*/txdownload_impl.RecentRejectsReconsiderableFilter().contains(parent_txid), /*txid_recon=*/txdownload_impl.RecentRejectsReconsiderableFilter().contains(parent_txid.ToUint256()),
/*wtxid_recon=*/txdownload_impl.RecentRejectsReconsiderableFilter().contains(parent_wtxid), /*wtxid_recon=*/txdownload_impl.RecentRejectsReconsiderableFilter().contains(parent_wtxid.ToUint256()),
/*keep=*/keep, /*keep=*/keep,
/*txid_inv=*/txdownload_impl.AddTxAnnouncement(nodeid, GenTxid::Txid(parent_txid), now), /*txid_inv=*/txdownload_impl.AddTxAnnouncement(nodeid, parent_txid, now),
/*wtxid_inv=*/txdownload_impl.AddTxAnnouncement(nodeid, GenTxid::Wtxid(parent_wtxid), now), /*wtxid_inv=*/txdownload_impl.AddTxAnnouncement(nodeid, parent_wtxid, now),
}; };
BOOST_TEST_MESSAGE("Testing behavior for " << result << (segwit_parent ? " segwit " : " nonsegwit")); BOOST_TEST_MESSAGE("Testing behavior for " << result << (segwit_parent ? " segwit " : " nonsegwit"));
actual_behavior.CheckEqual(expected_behavior, /*segwit=*/segwit_parent); actual_behavior.CheckEqual(expected_behavior, /*segwit=*/segwit_parent);
@ -158,8 +158,8 @@ BOOST_FIXTURE_TEST_CASE(tx_rejection_types, TestChain100Setup)
// If parent (by txid) was rejected, child is too. // If parent (by txid) was rejected, child is too.
const bool parent_txid_rejected{segwit_parent ? expected_behavior.m_txid_in_rejects : expected_behavior.m_wtxid_in_rejects}; const bool parent_txid_rejected{segwit_parent ? expected_behavior.m_txid_in_rejects : expected_behavior.m_wtxid_in_rejects};
BOOST_CHECK_EQUAL(parent_txid_rejected, txdownload_impl.RecentRejectsFilter().contains(child_txid)); BOOST_CHECK_EQUAL(parent_txid_rejected, txdownload_impl.RecentRejectsFilter().contains(child_txid.ToUint256()));
BOOST_CHECK_EQUAL(parent_txid_rejected, txdownload_impl.RecentRejectsFilter().contains(child_wtxid)); BOOST_CHECK_EQUAL(parent_txid_rejected, txdownload_impl.RecentRejectsFilter().contains(child_wtxid.ToUint256()));
// Unless rejected, the child should be in orphanage. // Unless rejected, the child should be in orphanage.
BOOST_CHECK_EQUAL(!parent_txid_rejected, txdownload_impl.m_orphanage.HaveTx(ptx_child->GetWitnessHash())); BOOST_CHECK_EQUAL(!parent_txid_rejected, txdownload_impl.m_orphanage.HaveTx(ptx_child->GetWitnessHash()));

View file

@ -1090,7 +1090,7 @@ BOOST_AUTO_TEST_CASE(package_rbf_tests)
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size); BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
// child1 has been replaced // child1 has been replaced
BOOST_CHECK(!m_node.mempool->exists(GenTxid::Txid(tx_child_1->GetHash()))); BOOST_CHECK(!m_node.mempool->exists(tx_child_1->GetHash()));
} }
// Test package rbf. // Test package rbf.

View file

@ -56,7 +56,7 @@ struct Runner
std::set<NodeId> peerset; std::set<NodeId> peerset;
/** Which txhashes have been assigned already (to prevent reuse). */ /** Which txhashes have been assigned already (to prevent reuse). */
std::set<uint256> txhashset; std::set<GenTxid> txhashset;
/** Which (peer, gtxid) combinations are known to be expired. These need to be accumulated here instead of /** Which (peer, gtxid) combinations are known to be expired. These need to be accumulated here instead of
* checked directly in the GetRequestable return value to avoid introducing a dependency between the various * checked directly in the GetRequestable return value to avoid introducing a dependency between the various
@ -100,7 +100,7 @@ public:
} }
/** Schedule a ForgetTxHash call at the Scheduler's current time. */ /** Schedule a ForgetTxHash call at the Scheduler's current time. */
void ForgetTxHash(const uint256& txhash) void ForgetTxHash(const GenTxid& txhash)
{ {
auto& runner = m_runner; auto& runner = m_runner;
runner.actions.emplace_back(m_now, [=,&runner]() { runner.actions.emplace_back(m_now, [=,&runner]() {
@ -130,7 +130,7 @@ public:
} }
/** Schedule a RequestedTx call at the Scheduler's current time. */ /** Schedule a RequestedTx call at the Scheduler's current time. */
void RequestedTx(NodeId peer, const uint256& txhash, std::chrono::microseconds exptime) void RequestedTx(NodeId peer, const GenTxid& txhash, std::chrono::microseconds exptime)
{ {
auto& runner = m_runner; auto& runner = m_runner;
runner.actions.emplace_back(m_now, [=,&runner]() { runner.actions.emplace_back(m_now, [=,&runner]() {
@ -140,7 +140,7 @@ public:
} }
/** Schedule a ReceivedResponse call at the Scheduler's current time. */ /** Schedule a ReceivedResponse call at the Scheduler's current time. */
void ReceivedResponse(NodeId peer, const uint256& txhash) void ReceivedResponse(NodeId peer, const GenTxid& txhash)
{ {
auto& runner = m_runner; auto& runner = m_runner;
runner.actions.emplace_back(m_now, [=,&runner]() { runner.actions.emplace_back(m_now, [=,&runner]() {
@ -208,12 +208,17 @@ public:
* where priority is the predicted internal TxRequestTracker's priority, assuming all announcements * where priority is the predicted internal TxRequestTracker's priority, assuming all announcements
* are within the same preferredness class. * are within the same preferredness class.
*/ */
uint256 NewTxHash(const std::vector<std::vector<NodeId>>& orders = {}) GenTxid NewGTxid(const std::vector<std::vector<NodeId>>& orders = {})
{ {
uint256 ret; GenTxid ret;
bool ok; bool ok;
do { do {
ret = m_rng.rand256(); uint256 hash = m_rng.rand256();
if (m_rng.randbool()) {
ret = Txid::FromUint256(hash);
} else {
ret = Wtxid::FromUint256(hash);
}
ok = true; ok = true;
for (const auto& order : orders) { for (const auto& order : orders) {
for (size_t pos = 1; pos < order.size(); ++pos) { for (size_t pos = 1; pos < order.size(); ++pos) {
@ -233,12 +238,6 @@ public:
return ret; return ret;
} }
/** Generate a random GenTxid; the txhash follows NewTxHash; the is_wtxid flag is random. */
GenTxid NewGTxid(const std::vector<std::vector<NodeId>>& orders = {})
{
return m_rng.randbool() ? GenTxid::Wtxid(NewTxHash(orders)) : GenTxid::Txid(NewTxHash(orders));
}
/** Generate a new random NodeId to use as peer. The same NodeId is never returned twice /** Generate a new random NodeId to use as peer. The same NodeId is never returned twice
* (across all Scenarios combined). */ * (across all Scenarios combined). */
NodeId NewPeer() NodeId NewPeer()
@ -285,7 +284,7 @@ void TxRequestTest::BuildSingleTest(Scenario& scenario, int config)
scenario.AdvanceTime(RandomTime8s()); scenario.AdvanceTime(RandomTime8s());
auto expiry = RandomTime8s(); auto expiry = RandomTime8s();
scenario.Check(peer, {gtxid}, 1, 0, 0, "s5"); scenario.Check(peer, {gtxid}, 1, 0, 0, "s5");
scenario.RequestedTx(peer, gtxid.GetHash(), scenario.Now() + expiry); scenario.RequestedTx(peer, gtxid, scenario.Now() + expiry);
scenario.Check(peer, {}, 0, 1, 0, "s6"); scenario.Check(peer, {}, 0, 1, 0, "s6");
if ((config >> 3) == 1) { // The request will time out if ((config >> 3) == 1) { // The request will time out
@ -299,7 +298,7 @@ void TxRequestTest::BuildSingleTest(Scenario& scenario, int config)
scenario.AdvanceTime(std::chrono::microseconds{m_rng.randrange(expiry.count())}); scenario.AdvanceTime(std::chrono::microseconds{m_rng.randrange(expiry.count())});
scenario.Check(peer, {}, 0, 1, 0, "s9"); scenario.Check(peer, {}, 0, 1, 0, "s9");
if ((config >> 3) == 3) { // A response will arrive for the transaction if ((config >> 3) == 3) { // A response will arrive for the transaction
scenario.ReceivedResponse(peer, gtxid.GetHash()); scenario.ReceivedResponse(peer, gtxid);
scenario.Check(peer, {}, 0, 0, 0, "s10"); scenario.Check(peer, {}, 0, 0, 0, "s10");
return; return;
} }
@ -309,7 +308,7 @@ void TxRequestTest::BuildSingleTest(Scenario& scenario, int config)
if (config & 4) { // The peer will go offline if (config & 4) { // The peer will go offline
scenario.DisconnectedPeer(peer); scenario.DisconnectedPeer(peer);
} else { // The transaction is no longer needed } else { // The transaction is no longer needed
scenario.ForgetTxHash(gtxid.GetHash()); scenario.ForgetTxHash(gtxid);
} }
scenario.Check(peer, {}, 0, 0, 0, "s11"); scenario.Check(peer, {}, 0, 0, 0, "s11");
} }
@ -355,7 +354,7 @@ void TxRequestTest::BuildPriorityTest(Scenario& scenario, int config)
// We possibly request from the selected peer. // We possibly request from the selected peer.
if (config & 8) { if (config & 8) {
scenario.RequestedTx(priopeer, gtxid.GetHash(), MAX_TIME); scenario.RequestedTx(priopeer, gtxid, MAX_TIME);
scenario.Check(priopeer, {}, 0, 1, 0, "p7"); scenario.Check(priopeer, {}, 0, 1, 0, "p7");
scenario.Check(otherpeer, {}, 1, 0, 0, "p8"); scenario.Check(otherpeer, {}, 1, 0, 0, "p8");
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
@ -365,7 +364,7 @@ void TxRequestTest::BuildPriorityTest(Scenario& scenario, int config)
if (config & 16) { if (config & 16) {
scenario.DisconnectedPeer(priopeer); scenario.DisconnectedPeer(priopeer);
} else { } else {
scenario.ReceivedResponse(priopeer, gtxid.GetHash()); scenario.ReceivedResponse(priopeer, gtxid);
} }
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.Check(priopeer, {}, 0, 0, !(config & 16), "p8"); scenario.Check(priopeer, {}, 0, 0, !(config & 16), "p8");
@ -449,7 +448,7 @@ void TxRequestTest::BuildBigPriorityTest(Scenario& scenario, int peers)
scenario.DisconnectedPeer(peer); scenario.DisconnectedPeer(peer);
scenario.Check(peer, {}, 0, 0, 0, "b4"); scenario.Check(peer, {}, 0, 0, 0, "b4");
} else { } else {
scenario.ReceivedResponse(peer, gtxid.GetHash()); scenario.ReceivedResponse(peer, gtxid);
scenario.Check(peer, {}, 0, 0, request_order.size() > 0, "b5"); scenario.Check(peer, {}, 0, 0, request_order.size() > 0, "b5");
} }
if (request_order.size()) { if (request_order.size()) {
@ -509,9 +508,9 @@ void TxRequestTest::BuildWtxidTest(Scenario& scenario, int config)
auto peerT = scenario.NewPeer(); auto peerT = scenario.NewPeer();
auto peerW = scenario.NewPeer(); auto peerW = scenario.NewPeer();
auto txhash = scenario.NewTxHash(); auto gtxid = scenario.NewGTxid();
auto txid{GenTxid::Txid(txhash)}; auto txid = Txid::FromUint256(gtxid.ToUint256());
auto wtxid{GenTxid::Wtxid(txhash)}; auto wtxid = Wtxid::FromUint256(gtxid.ToUint256());
auto reqtimeT = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s(); auto reqtimeT = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s();
auto reqtimeW = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s(); auto reqtimeW = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s();
@ -542,11 +541,11 @@ void TxRequestTest::BuildWtxidTest(Scenario& scenario, int config)
// Let the preferred announcement be requested. It's not going to be delivered. // Let the preferred announcement be requested. It's not going to be delivered.
auto expiry = RandomTime8s(); auto expiry = RandomTime8s();
if (config & 2) { if (config & 2) {
scenario.RequestedTx(peerT, txid.GetHash(), scenario.Now() + expiry); scenario.RequestedTx(peerT, txid, scenario.Now() + expiry);
scenario.Check(peerT, {}, 0, 1, 0, "w5"); scenario.Check(peerT, {}, 0, 1, 0, "w5");
scenario.Check(peerW, {}, 1, 0, 0, "w6"); scenario.Check(peerW, {}, 1, 0, 0, "w6");
} else { } else {
scenario.RequestedTx(peerW, wtxid.GetHash(), scenario.Now() + expiry); scenario.RequestedTx(peerW, wtxid, scenario.Now() + expiry);
scenario.Check(peerT, {}, 1, 0, 0, "w7"); scenario.Check(peerT, {}, 1, 0, 0, "w7");
scenario.Check(peerW, {}, 0, 1, 0, "w8"); scenario.Check(peerW, {}, 0, 1, 0, "w8");
} }
@ -567,7 +566,7 @@ void TxRequestTest::BuildWtxidTest(Scenario& scenario, int config)
// If a good transaction with either that hash as wtxid or txid arrives, both // If a good transaction with either that hash as wtxid or txid arrives, both
// announcements are gone. // announcements are gone.
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.ForgetTxHash(txhash); scenario.ForgetTxHash(gtxid);
scenario.Check(peerT, {}, 0, 0, 0, "w13"); scenario.Check(peerT, {}, 0, 0, 0, "w13");
scenario.Check(peerW, {}, 0, 0, 0, "w14"); scenario.Check(peerW, {}, 0, 0, 0, "w14");
} }
@ -599,7 +598,7 @@ void TxRequestTest::BuildTimeBackwardsTest(Scenario& scenario)
// Request from peer1. // Request from peer1.
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
auto expiry = scenario.Now() + RandomTime8s(); auto expiry = scenario.Now() + RandomTime8s();
scenario.RequestedTx(peer1, gtxid.GetHash(), expiry); scenario.RequestedTx(peer1, gtxid, expiry);
scenario.Check(peer1, {}, 0, 1, 0, "r7"); scenario.Check(peer1, {}, 0, 1, 0, "r7");
scenario.Check(peer2, {}, 1, 0, 0, "r8"); scenario.Check(peer2, {}, 1, 0, 0, "r8");
@ -638,20 +637,20 @@ void TxRequestTest::BuildWeirdRequestsTest(Scenario& scenario)
// We request gtxid2 from *peer1* - no effect. // We request gtxid2 from *peer1* - no effect.
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME); scenario.RequestedTx(peer1, gtxid2, MAX_TIME);
scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q4"); scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q4");
scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q5"); scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q5");
// Now request gtxid1 from peer1 - marks it as REQUESTED. // Now request gtxid1 from peer1 - marks it as REQUESTED.
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
auto expiryA = scenario.Now() + RandomTime8s(); auto expiryA = scenario.Now() + RandomTime8s();
scenario.RequestedTx(peer1, gtxid1.GetHash(), expiryA); scenario.RequestedTx(peer1, gtxid1, expiryA);
scenario.Check(peer1, {}, 0, 1, 0, "q6"); scenario.Check(peer1, {}, 0, 1, 0, "q6");
scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q7"); scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q7");
// Request it a second time - nothing happens, as it's already REQUESTED. // Request it a second time - nothing happens, as it's already REQUESTED.
auto expiryB = expiryA + RandomTime8s(); auto expiryB = expiryA + RandomTime8s();
scenario.RequestedTx(peer1, gtxid1.GetHash(), expiryB); scenario.RequestedTx(peer1, gtxid1, expiryB);
scenario.Check(peer1, {}, 0, 1, 0, "q8"); scenario.Check(peer1, {}, 0, 1, 0, "q8");
scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q9"); scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q9");
@ -668,7 +667,7 @@ void TxRequestTest::BuildWeirdRequestsTest(Scenario& scenario)
// Requesting it yet again from peer1 doesn't do anything, as it's already COMPLETED. // Requesting it yet again from peer1 doesn't do anything, as it's already COMPLETED.
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.RequestedTx(peer1, gtxid1.GetHash(), MAX_TIME); scenario.RequestedTx(peer1, gtxid1, MAX_TIME);
scenario.Check(peer1, {}, 0, 0, 1, "q14"); scenario.Check(peer1, {}, 0, 0, 1, "q14");
scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q15"); scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q15");
@ -680,13 +679,13 @@ void TxRequestTest::BuildWeirdRequestsTest(Scenario& scenario)
// And request it from peer1 (weird as peer2 has the preference). // And request it from peer1 (weird as peer2 has the preference).
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME); scenario.RequestedTx(peer1, gtxid2, MAX_TIME);
scenario.Check(peer1, {}, 0, 1, 1, "q18"); scenario.Check(peer1, {}, 0, 1, 1, "q18");
scenario.Check(peer2, {gtxid1}, 2, 0, 0, "q19"); scenario.Check(peer2, {gtxid1}, 2, 0, 0, "q19");
// If peer2 now (normally) requests gtxid2, the existing request by peer1 becomes COMPLETED. // If peer2 now (normally) requests gtxid2, the existing request by peer1 becomes COMPLETED.
if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.RequestedTx(peer2, gtxid2.GetHash(), MAX_TIME); scenario.RequestedTx(peer2, gtxid2, MAX_TIME);
scenario.Check(peer1, {}, 0, 0, 2, "q20"); scenario.Check(peer1, {}, 0, 0, 2, "q20");
scenario.Check(peer2, {gtxid1}, 1, 1, 0, "q21"); scenario.Check(peer2, {gtxid1}, 1, 1, 0, "q21");

View file

@ -304,7 +304,7 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
Package package_v3_v2{mempool_tx_v3, tx_v2_from_v3}; Package package_v3_v2{mempool_tx_v3, tx_v2_from_v3};
BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), package_v3_v2, empty_ancestors), expected_error_str); BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), package_v3_v2, empty_ancestors), expected_error_str);
CTxMemPool::setEntries entries_mempool_v3{pool.GetIter(mempool_tx_v3->GetHash().ToUint256()).value()}; CTxMemPool::setEntries entries_mempool_v3{pool.GetIter(mempool_tx_v3->GetHash()).value()};
BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), {tx_v2_from_v3}, entries_mempool_v3), expected_error_str); BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), {tx_v2_from_v3}, entries_mempool_v3), expected_error_str);
// mempool_tx_v3 mempool_tx_v2 // mempool_tx_v3 mempool_tx_v2
@ -339,7 +339,7 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
Package package_v2_v3{mempool_tx_v2, tx_v3_from_v2}; Package package_v2_v3{mempool_tx_v2, tx_v3_from_v2};
BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), package_v2_v3, empty_ancestors), expected_error_str); BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), package_v2_v3, empty_ancestors), expected_error_str);
CTxMemPool::setEntries entries_mempool_v2{pool.GetIter(mempool_tx_v2->GetHash().ToUint256()).value()}; CTxMemPool::setEntries entries_mempool_v2{pool.GetIter(mempool_tx_v2->GetHash()).value()};
BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), {tx_v3_from_v2}, entries_mempool_v2), expected_error_str); BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), {tx_v3_from_v2}, entries_mempool_v2), expected_error_str);
// mempool_tx_v3 mempool_tx_v2 // mempool_tx_v3 mempool_tx_v2
@ -536,7 +536,7 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
// Configuration where parent already has 2 other children in mempool (no sibling eviction allowed). This may happen as the result of a reorg. // Configuration where parent already has 2 other children in mempool (no sibling eviction allowed). This may happen as the result of a reorg.
AddToMempool(pool, entry.FromTx(tx_v3_child2)); AddToMempool(pool, entry.FromTx(tx_v3_child2));
auto tx_v3_child3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 24}}, /*version=*/3); auto tx_v3_child3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 24}}, /*version=*/3);
auto entry_mempool_parent = pool.GetIter(mempool_tx_v3->GetHash().ToUint256()).value(); auto entry_mempool_parent = pool.GetIter(mempool_tx_v3->GetHash()).value();
BOOST_CHECK_EQUAL(entry_mempool_parent->GetCountWithDescendants(), 3); BOOST_CHECK_EQUAL(entry_mempool_parent->GetCountWithDescendants(), 3);
auto ancestors_2siblings{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child3), m_limits)}; auto ancestors_2siblings{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child3), m_limits)};

View file

@ -629,3 +629,11 @@ std::ostream& operator<<(std::ostream& os, const uint256& num)
{ {
return os << num.ToString(); 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();
}

View file

@ -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 arith_uint256& num);
std::ostream& operator<<(std::ostream& os, const uint160& 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 uint256& num);
std::ostream& operator<<(std::ostream& os, const Txid& txid);
std::ostream& operator<<(std::ostream& os, const Wtxid& wtxid);
// @} // @}
/** /**

View file

@ -122,17 +122,17 @@ std::optional<std::string> CheckPackageMempoolAcceptResult(const Package& txns,
if (mempool) { if (mempool) {
// The tx by txid should be in the mempool iff the result was not INVALID. // The tx by txid should be in the mempool iff the result was not INVALID.
const bool txid_in_mempool{atmp_result.m_result_type != MempoolAcceptResult::ResultType::INVALID}; const bool txid_in_mempool{atmp_result.m_result_type != MempoolAcceptResult::ResultType::INVALID};
if (mempool->exists(GenTxid::Txid(tx->GetHash())) != txid_in_mempool) { if (mempool->exists(tx->GetHash()) != txid_in_mempool) {
return strprintf("tx %s should %sbe in mempool", wtxid.ToString(), txid_in_mempool ? "" : "not "); return strprintf("tx %s should %sbe in mempool", wtxid.ToString(), txid_in_mempool ? "" : "not ");
} }
// Additionally, if the result was DIFFERENT_WITNESS, we shouldn't be able to find the tx in mempool by wtxid. // Additionally, if the result was DIFFERENT_WITNESS, we shouldn't be able to find the tx in mempool by wtxid.
if (tx->HasWitness() && atmp_result.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS) { if (tx->HasWitness() && atmp_result.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS) {
if (mempool->exists(GenTxid::Wtxid(wtxid))) { if (mempool->exists(wtxid)) {
return strprintf("wtxid %s should not be in mempool", wtxid.ToString()); return strprintf("wtxid %s should not be in mempool", wtxid.ToString());
} }
} }
for (const auto& tx_ref : atmp_result.m_replaced_transactions) { for (const auto& tx_ref : atmp_result.m_replaced_transactions) {
if (mempool->exists(GenTxid::Txid(tx_ref->GetHash()))) { if (mempool->exists(tx_ref->GetHash())) {
return strprintf("tx %s should not be in mempool as it was replaced", tx_ref->GetWitnessHash().ToString()); return strprintf("tx %s should not be in mempool as it was replaced", tx_ref->GetWitnessHash().ToString());
} }
} }

View file

@ -214,9 +214,9 @@ BOOST_AUTO_TEST_CASE(block_malleation)
// Block with a single coinbase tx is mutated if the merkle root is not // Block with a single coinbase tx is mutated if the merkle root is not
// equal to the coinbase tx's hash. // equal to the coinbase tx's hash.
block.vtx.push_back(create_coinbase_tx()); 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)); 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)); BOOST_CHECK(is_not_mutated(block, /*check_witness_root=*/false));
// Block with two transactions is mutated if the merkle root does not // 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.resize(1);
mtx.vout[0].scriptPubKey.resize(4); mtx.vout[0].scriptPubKey.resize(4);
block.vtx.push_back(MakeTransactionRef(mtx)); 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(block.vtx.back()->IsCoinBase());
assert(GetSerializeSize(TX_NO_WITNESS(block.vtx.back())) == 64); assert(GetSerializeSize(TX_NO_WITNESS(block.vtx.back())) == 64);
} }
@ -285,7 +285,7 @@ BOOST_AUTO_TEST_CASE(block_malleation)
HashWriter hasher; HashWriter hasher;
hasher.write(tx1.GetHash()); hasher.write(tx1.GetHash());
hasher.write(tx2.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). // Verify that tx3 is 64 bytes in size (without witness).
assert(GetSerializeSize(TX_NO_WITNESS(tx3)) == 64); assert(GetSerializeSize(TX_NO_WITNESS(tx3)) == 64);
} }

View file

@ -55,7 +55,7 @@ bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp)
} }
void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants, void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants,
const std::set<uint256>& setExclude, std::set<uint256>& descendants_to_remove) const std::set<Txid>& setExclude, std::set<Txid>& descendants_to_remove)
{ {
CTxMemPoolEntry::Children stageEntries, descendants; CTxMemPoolEntry::Children stageEntries, descendants;
stageEntries = updateIt->GetMemPoolChildrenConst(); stageEntries = updateIt->GetMemPoolChildrenConst();
@ -105,7 +105,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendan
mapTx.modify(updateIt, [=](CTxMemPoolEntry& e) { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); }); mapTx.modify(updateIt, [=](CTxMemPoolEntry& e) { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); });
} }
void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<Txid>& vHashesToUpdate)
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
// For each entry in vHashesToUpdate, store the set of in-mempool, but not // For each entry in vHashesToUpdate, store the set of in-mempool, but not
@ -115,29 +115,29 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashes
// Use a set for lookups into vHashesToUpdate (these entries are already // Use a set for lookups into vHashesToUpdate (these entries are already
// accounted for in the state of their ancestors) // accounted for in the state of their ancestors)
std::set<uint256> setAlreadyIncluded(vHashesToUpdate.begin(), vHashesToUpdate.end()); std::set<Txid> setAlreadyIncluded(vHashesToUpdate.begin(), vHashesToUpdate.end());
std::set<uint256> descendants_to_remove; std::set<Txid> descendants_to_remove;
// Iterate in reverse, so that whenever we are looking at a transaction // Iterate in reverse, so that whenever we are looking at a transaction
// we are sure that all in-mempool descendants have already been processed. // we are sure that all in-mempool descendants have already been processed.
// This maximizes the benefit of the descendant cache and guarantees that // This maximizes the benefit of the descendant cache and guarantees that
// CTxMemPoolEntry::m_children will be updated, an assumption made in // CTxMemPoolEntry::m_children will be updated, an assumption made in
// UpdateForDescendants. // UpdateForDescendants.
for (const uint256& hash : vHashesToUpdate | std::views::reverse) { for (const Txid& hash : vHashesToUpdate | std::views::reverse) {
// calculate children from mapNextTx // calculate children from mapNextTx
txiter it = mapTx.find(hash); txiter it = mapTx.find(hash);
if (it == mapTx.end()) { if (it == mapTx.end()) {
continue; continue;
} }
auto iter = mapNextTx.lower_bound(COutPoint(Txid::FromUint256(hash), 0)); auto iter = mapNextTx.lower_bound(COutPoint(hash, 0));
// First calculate the children, and update CTxMemPoolEntry::m_children to // First calculate the children, and update CTxMemPoolEntry::m_children to
// include them, and update their CTxMemPoolEntry::m_parents to include this tx. // include them, and update their CTxMemPoolEntry::m_parents to include this tx.
// we cache the in-mempool children to avoid duplicate updates // we cache the in-mempool children to avoid duplicate updates
{ {
WITH_FRESH_EPOCH(m_epoch); WITH_FRESH_EPOCH(m_epoch);
for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) { for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) {
const uint256 &childHash = iter->second->GetHash(); const Txid &childHash = iter->second->GetHash();
txiter childIter = mapTx.find(childHash); txiter childIter = mapTx.find(childHash);
assert(childIter != mapTx.end()); assert(childIter != mapTx.end());
// We can skip updating entries we've encountered before or that // We can skip updating entries we've encountered before or that
@ -782,7 +782,7 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
AddCoins(mempoolDuplicate, tx, std::numeric_limits<int>::max()); AddCoins(mempoolDuplicate, tx, std::numeric_limits<int>::max());
} }
for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) { for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) {
uint256 hash = it->second->GetHash(); Txid hash = it->second->GetHash();
indexed_transaction_set::const_iterator it2 = mapTx.find(hash); indexed_transaction_set::const_iterator it2 = mapTx.find(hash);
const CTransaction& tx = it2->GetTx(); const CTransaction& tx = it2->GetTx();
assert(it2 != mapTx.end()); assert(it2 != mapTx.end());
@ -794,7 +794,7 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
assert(innerUsage == cachedInnerUsage); assert(innerUsage == cachedInnerUsage);
} }
bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb, bool wtxid) bool CTxMemPool::CompareDepthAndScore(const GenTxid& hasha, const GenTxid& hashb)
{ {
/* Return `true` if hasha should be considered sooner than hashb. Namely when: /* Return `true` if hasha should be considered sooner than hashb. Namely when:
* a is not in the mempool, but b is * a is not in the mempool, but b is
@ -802,10 +802,18 @@ bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb
* both are in the mempool and a has a higher score than b * both are in the mempool and a has a higher score than b
*/ */
LOCK(cs); LOCK(cs);
indexed_transaction_set::const_iterator j = wtxid ? get_iter_from_wtxid(hashb) : mapTx.find(hashb); indexed_transaction_set::const_iterator j = std::visit(util::Overloaded{
[this](const Wtxid& wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs) { return get_iter_from_wtxid(wtxid); },
[this](const Txid& txid) EXCLUSIVE_LOCKS_REQUIRED(cs) { return mapTx.find(txid); }
}, hashb);
if (j == mapTx.end()) return false; if (j == mapTx.end()) return false;
indexed_transaction_set::const_iterator i = wtxid ? get_iter_from_wtxid(hasha) : mapTx.find(hasha);
indexed_transaction_set::const_iterator i = std::visit(util::Overloaded{
[this](const Wtxid& wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs) { return get_iter_from_wtxid(wtxid); },
[this](const Txid& txid) EXCLUSIVE_LOCKS_REQUIRED(cs) { return mapTx.find(txid); }
}, hasha);
if (i == mapTx.end()) return true; if (i == mapTx.end()) return true;
uint64_t counta = i->GetCountWithAncestors(); uint64_t counta = i->GetCountWithAncestors();
uint64_t countb = j->GetCountWithAncestors(); uint64_t countb = j->GetCountWithAncestors();
if (counta == countb) { if (counta == countb) {
@ -881,7 +889,7 @@ const CTxMemPoolEntry* CTxMemPool::GetEntry(const Txid& txid) const
return i == mapTx.end() ? nullptr : &(*i); return i == mapTx.end() ? nullptr : &(*i);
} }
CTransactionRef CTxMemPool::get(const uint256& hash) const CTransactionRef CTxMemPool::get(const Txid& hash) const
{ {
LOCK(cs); LOCK(cs);
indexed_transaction_set::const_iterator i = mapTx.find(hash); indexed_transaction_set::const_iterator i = mapTx.find(hash);
@ -893,7 +901,11 @@ CTransactionRef CTxMemPool::get(const uint256& hash) const
TxMempoolInfo CTxMemPool::info(const GenTxid& gtxid) const TxMempoolInfo CTxMemPool::info(const GenTxid& gtxid) const
{ {
LOCK(cs); LOCK(cs);
indexed_transaction_set::const_iterator i = (gtxid.IsWtxid() ? get_iter_from_wtxid(gtxid.GetHash()) : mapTx.find(gtxid.GetHash())); indexed_transaction_set::const_iterator i = std::visit(util::Overloaded{
[this](const Wtxid& wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs) { return get_iter_from_wtxid(wtxid); },
[this](const Txid& txid) EXCLUSIVE_LOCKS_REQUIRED(cs) { return mapTx.find(txid); }
}, gtxid);
if (i == mapTx.end()) if (i == mapTx.end())
return TxMempoolInfo(); return TxMempoolInfo();
return GetInfo(i); return GetInfo(i);
@ -902,7 +914,11 @@ TxMempoolInfo CTxMemPool::info(const GenTxid& gtxid) const
TxMempoolInfo CTxMemPool::info_for_relay(const GenTxid& gtxid, uint64_t last_sequence) const TxMempoolInfo CTxMemPool::info_for_relay(const GenTxid& gtxid, uint64_t last_sequence) const
{ {
LOCK(cs); LOCK(cs);
indexed_transaction_set::const_iterator i = (gtxid.IsWtxid() ? get_iter_from_wtxid(gtxid.GetHash()) : mapTx.find(gtxid.GetHash())); indexed_transaction_set::const_iterator i = std::visit(util::Overloaded{
[this](const Wtxid& wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs) { return get_iter_from_wtxid(wtxid); },
[this](const Txid& txid) EXCLUSIVE_LOCKS_REQUIRED(cs) { return mapTx.find(txid); }
}, gtxid);
if (i != mapTx.end() && i->GetSequence() < last_sequence) { if (i != mapTx.end() && i->GetSequence() < last_sequence) {
return GetInfo(i); return GetInfo(i);
} else { } else {
@ -910,7 +926,7 @@ TxMempoolInfo CTxMemPool::info_for_relay(const GenTxid& gtxid, uint64_t last_seq
} }
} }
void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta) void CTxMemPool::PrioritiseTransaction(const Txid& hash, const CAmount& nFeeDelta)
{ {
{ {
LOCK(cs); LOCK(cs);
@ -946,17 +962,17 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeD
} }
} }
void CTxMemPool::ApplyDelta(const uint256& hash, CAmount &nFeeDelta) const void CTxMemPool::ApplyDelta(const Txid& hash, CAmount &nFeeDelta) const
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash); std::map<Txid, CAmount>::const_iterator pos = mapDeltas.find(hash);
if (pos == mapDeltas.end()) if (pos == mapDeltas.end())
return; return;
const CAmount &delta = pos->second; const CAmount &delta = pos->second;
nFeeDelta += delta; nFeeDelta += delta;
} }
void CTxMemPool::ClearPrioritisation(const uint256& hash) void CTxMemPool::ClearPrioritisation(const Txid& hash)
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
mapDeltas.erase(hash); mapDeltas.erase(hash);
@ -984,7 +1000,7 @@ const CTransaction* CTxMemPool::GetConflictTx(const COutPoint& prevout) const
return it == mapNextTx.end() ? nullptr : it->second; return it == mapNextTx.end() ? nullptr : it->second;
} }
std::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const uint256& txid) const std::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const Txid& txid) const
{ {
auto it = mapTx.find(txid); auto it = mapTx.find(txid);
if (it != mapTx.end()) return it; if (it != mapTx.end()) return it;
@ -1001,7 +1017,7 @@ CTxMemPool::setEntries CTxMemPool::GetIterSet(const std::set<Txid>& hashes) cons
return ret; return ret;
} }
std::vector<CTxMemPool::txiter> CTxMemPool::GetIterVec(const std::vector<uint256>& txids) const std::vector<CTxMemPool::txiter> CTxMemPool::GetIterVec(const std::vector<Txid>& txids) const
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
std::vector<txiter> ret; std::vector<txiter> ret;
@ -1017,7 +1033,7 @@ std::vector<CTxMemPool::txiter> CTxMemPool::GetIterVec(const std::vector<uint256
bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
{ {
for (unsigned int i = 0; i < tx.vin.size(); i++) for (unsigned int i = 0; i < tx.vin.size(); i++)
if (exists(GenTxid::Txid(tx.vin[i].prevout.hash))) if (exists(tx.vin[i].prevout.hash))
return false; return false;
return true; return true;
} }
@ -1066,7 +1082,7 @@ size_t CTxMemPool::DynamicMemoryUsage() const {
return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(txns_randomized) + cachedInnerUsage; return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(txns_randomized) + cachedInnerUsage;
} }
void CTxMemPool::RemoveUnbroadcastTx(const uint256& txid, const bool unchecked) { void CTxMemPool::RemoveUnbroadcastTx(const Txid& txid, const bool unchecked) {
LOCK(cs); LOCK(cs);
if (m_unbroadcast_txids.erase(txid)) if (m_unbroadcast_txids.erase(txid))
@ -1187,7 +1203,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends
if (pvNoSpendsRemaining) { if (pvNoSpendsRemaining) {
for (const CTransaction& tx : txn) { for (const CTransaction& tx : txn) {
for (const CTxIn& txin : tx.vin) { for (const CTxIn& txin : tx.vin) {
if (exists(GenTxid::Txid(txin.prevout.hash))) continue; if (exists(txin.prevout.hash)) continue;
pvNoSpendsRemaining->push_back(txin.prevout); pvNoSpendsRemaining->push_back(txin.prevout);
} }
} }
@ -1221,7 +1237,7 @@ uint64_t CTxMemPool::CalculateDescendantMaximum(txiter entry) const {
return maximum; return maximum;
} }
void CTxMemPool::GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* const ancestorsize, CAmount* const ancestorfees) const { void CTxMemPool::GetTransactionAncestry(const Txid& txid, size_t& ancestors, size_t& descendants, size_t* const ancestorsize, CAmount* const ancestorfees) const {
LOCK(cs); LOCK(cs);
auto it = mapTx.find(txid); auto it = mapTx.find(txid);
ancestors = descendants = 0; ancestors = descendants = 0;
@ -1245,7 +1261,7 @@ void CTxMemPool::SetLoadTried(bool load_tried)
m_load_tried = load_tried; m_load_tried = load_tried;
} }
std::vector<CTxMemPool::txiter> CTxMemPool::GatherClusters(const std::vector<uint256>& txids) const std::vector<CTxMemPool::txiter> CTxMemPool::GatherClusters(const std::vector<Txid>& txids) const
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
std::vector<txiter> clustered_txs{GetIterVec(txids)}; std::vector<txiter> clustered_txs{GetIterVec(txids)};

View file

@ -20,6 +20,7 @@
#include <sync.h> #include <sync.h>
#include <util/epochguard.h> #include <util/epochguard.h>
#include <util/hasher.h> #include <util/hasher.h>
#include <util/overloaded.h>
#include <util/result.h> #include <util/result.h>
#include <util/feefrac.h> #include <util/feefrac.h>
@ -38,6 +39,7 @@
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <utility> #include <utility>
#include <variant>
#include <vector> #include <vector>
class CChain; class CChain;
@ -56,7 +58,7 @@ bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp) EXCLUSIVE
// extracts a transaction hash from CTxMemPoolEntry or CTransactionRef // extracts a transaction hash from CTxMemPoolEntry or CTransactionRef
struct mempoolentry_txid struct mempoolentry_txid
{ {
typedef uint256 result_type; typedef Txid result_type;
result_type operator() (const CTxMemPoolEntry &entry) const result_type operator() (const CTxMemPoolEntry &entry) const
{ {
return entry.GetTx().GetHash(); return entry.GetTx().GetHash();
@ -71,7 +73,7 @@ struct mempoolentry_txid
// extracts a transaction witness-hash from CTxMemPoolEntry or CTransactionRef // extracts a transaction witness-hash from CTxMemPoolEntry or CTransactionRef
struct mempoolentry_wtxid struct mempoolentry_wtxid
{ {
typedef uint256 result_type; typedef Wtxid result_type;
result_type operator() (const CTxMemPoolEntry &entry) const result_type operator() (const CTxMemPoolEntry &entry) const
{ {
return entry.GetTx().GetWitnessHash(); return entry.GetTx().GetWitnessHash();
@ -410,7 +412,7 @@ private:
/** /**
* Track locally submitted transactions to periodically retry initial broadcast. * Track locally submitted transactions to periodically retry initial broadcast.
*/ */
std::set<uint256> m_unbroadcast_txids GUARDED_BY(cs); std::set<Txid> m_unbroadcast_txids GUARDED_BY(cs);
/** /**
@ -432,7 +434,7 @@ private:
public: public:
indirectmap<COutPoint, const CTransaction*> mapNextTx GUARDED_BY(cs); indirectmap<COutPoint, const CTransaction*> mapNextTx GUARDED_BY(cs);
std::map<uint256, CAmount> mapDeltas GUARDED_BY(cs); std::map<Txid, CAmount> mapDeltas GUARDED_BY(cs);
using Options = kernel::MemPoolOptions; using Options = kernel::MemPoolOptions;
@ -466,7 +468,7 @@ public:
void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(cs);
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb, bool wtxid=false); bool CompareDepthAndScore(const GenTxid& hasha, const GenTxid& hashb);
bool isSpent(const COutPoint& outpoint) const; bool isSpent(const COutPoint& outpoint) const;
unsigned int GetTransactionsUpdated() const; unsigned int GetTransactionsUpdated() const;
void AddTransactionsUpdated(unsigned int n); void AddTransactionsUpdated(unsigned int n);
@ -477,9 +479,9 @@ public:
bool HasNoInputsOf(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs); bool HasNoInputsOf(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Affect CreateNewBlock prioritisation of transactions */ /** Affect CreateNewBlock prioritisation of transactions */
void PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta); void PrioritiseTransaction(const Txid& hash, const CAmount& nFeeDelta);
void ApplyDelta(const uint256& hash, CAmount &nFeeDelta) const EXCLUSIVE_LOCKS_REQUIRED(cs); void ApplyDelta(const Txid& hash, CAmount &nFeeDelta) const EXCLUSIVE_LOCKS_REQUIRED(cs);
void ClearPrioritisation(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs); void ClearPrioritisation(const Txid& hash) EXCLUSIVE_LOCKS_REQUIRED(cs);
struct delta_info { struct delta_info {
/** Whether this transaction is in the mempool. */ /** Whether this transaction is in the mempool. */
@ -489,7 +491,7 @@ public:
/** The modified fee (base fee + delta) of this entry. Only present if in_mempool=true. */ /** The modified fee (base fee + delta) of this entry. Only present if in_mempool=true. */
std::optional<CAmount> modified_fee; std::optional<CAmount> modified_fee;
/** The prioritised transaction's txid. */ /** The prioritised transaction's txid. */
const uint256 txid; const Txid txid;
}; };
/** Return a vector of all entries in mapDeltas with their corresponding delta_info. */ /** Return a vector of all entries in mapDeltas with their corresponding delta_info. */
std::vector<delta_info> GetPrioritisedTransactions() const EXCLUSIVE_LOCKS_REQUIRED(!cs); std::vector<delta_info> GetPrioritisedTransactions() const EXCLUSIVE_LOCKS_REQUIRED(!cs);
@ -498,7 +500,7 @@ public:
const CTransaction* GetConflictTx(const COutPoint& prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs); const CTransaction* GetConflictTx(const COutPoint& prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Returns an iterator to the given hash, if found */ /** Returns an iterator to the given hash, if found */
std::optional<txiter> GetIter(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs); std::optional<txiter> GetIter(const Txid& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Translate a set of hashes into a set of pool iterators to avoid repeated lookups. /** Translate a set of hashes into a set of pool iterators to avoid repeated lookups.
* Does not require that all of the hashes correspond to actual transactions in the mempool, * Does not require that all of the hashes correspond to actual transactions in the mempool,
@ -508,7 +510,7 @@ public:
/** Translate a list of hashes into a list of mempool iterators to avoid repeated lookups. /** Translate a list of hashes into a list of mempool iterators to avoid repeated lookups.
* The nth element in txids becomes the nth element in the returned vector. If any of the txids * The nth element in txids becomes the nth element in the returned vector. If any of the txids
* don't actually exist in the mempool, returns an empty vector. */ * don't actually exist in the mempool, returns an empty vector. */
std::vector<txiter> GetIterVec(const std::vector<uint256>& txids) const EXCLUSIVE_LOCKS_REQUIRED(cs); std::vector<txiter> GetIterVec(const std::vector<Txid>& txids) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** UpdateTransactionsFromBlock is called when adding transactions from a /** UpdateTransactionsFromBlock is called when adding transactions from a
* disconnected block back to the mempool, new mempool entries may have * disconnected block back to the mempool, new mempool entries may have
@ -523,7 +525,7 @@ public:
* @param[in] vHashesToUpdate The set of txids from the * @param[in] vHashesToUpdate The set of txids from the
* disconnected block that have been accepted back into the mempool. * disconnected block that have been accepted back into the mempool.
*/ */
void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main) LOCKS_EXCLUDED(m_epoch); void UpdateTransactionsFromBlock(const std::vector<Txid>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main) LOCKS_EXCLUDED(m_epoch);
/** /**
* Try to calculate all in-mempool ancestors of entry. * Try to calculate all in-mempool ancestors of entry.
@ -565,7 +567,7 @@ public:
* All txids must correspond to transaction entries in the mempool, otherwise this returns an * All txids must correspond to transaction entries in the mempool, otherwise this returns an
* empty vector. This call will also exit early and return an empty vector if it collects 500 or * empty vector. This call will also exit early and return an empty vector if it collects 500 or
* more transactions as a DoS protection. */ * more transactions as a DoS protection. */
std::vector<txiter> GatherClusters(const std::vector<uint256>& txids) const EXCLUSIVE_LOCKS_REQUIRED(cs); std::vector<txiter> GatherClusters(const std::vector<Txid>& txids) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Calculate all in-mempool ancestors of a set of transactions not already in the mempool and /** Calculate all in-mempool ancestors of a set of transactions not already in the mempool and
* check ancestor and descendant limits. Heuristics are used to estimate the ancestor and * check ancestor and descendant limits. Heuristics are used to estimate the ancestor and
@ -612,7 +614,7 @@ public:
* When ancestors is non-zero (ie, the transaction itself is in the mempool), * When ancestors is non-zero (ie, the transaction itself is in the mempool),
* ancestorsize and ancestorfees will also be set to the appropriate values. * ancestorsize and ancestorfees will also be set to the appropriate values.
*/ */
void GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize = nullptr, CAmount* ancestorfees = nullptr) const; void GetTransactionAncestry(const Txid& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize = nullptr, CAmount* ancestorfees = nullptr) const;
/** /**
* @returns true if an initial attempt to load the persisted mempool was made, regardless of * @returns true if an initial attempt to load the persisted mempool was made, regardless of
@ -647,16 +649,16 @@ public:
bool exists(const GenTxid& gtxid) const bool exists(const GenTxid& gtxid) const
{ {
LOCK(cs); LOCK(cs);
if (gtxid.IsWtxid()) { return std::visit(util::Overloaded{
return (mapTx.get<index_by_wtxid>().count(gtxid.GetHash()) != 0); [this](const Wtxid& wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs) { return (mapTx.get<index_by_wtxid>().count(wtxid) != 0); },
} [this](const Txid& txid) EXCLUSIVE_LOCKS_REQUIRED(cs) { return (mapTx.count(txid) != 0); }
return (mapTx.count(gtxid.GetHash()) != 0); }, gtxid);
} }
const CTxMemPoolEntry* GetEntry(const Txid& txid) const LIFETIMEBOUND EXCLUSIVE_LOCKS_REQUIRED(cs); const CTxMemPoolEntry* GetEntry(const Txid& txid) const LIFETIMEBOUND EXCLUSIVE_LOCKS_REQUIRED(cs);
CTransactionRef get(const uint256& hash) const; CTransactionRef get(const Txid& hash) const;
txiter get_iter_from_wtxid(const uint256& wtxid) const EXCLUSIVE_LOCKS_REQUIRED(cs) txiter get_iter_from_wtxid(const Wtxid& wtxid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
return mapTx.project<0>(mapTx.get<index_by_wtxid>().find(wtxid)); return mapTx.project<0>(mapTx.get<index_by_wtxid>().find(wtxid));
@ -672,26 +674,26 @@ public:
size_t DynamicMemoryUsage() const; size_t DynamicMemoryUsage() const;
/** Adds a transaction to the unbroadcast set */ /** Adds a transaction to the unbroadcast set */
void AddUnbroadcastTx(const uint256& txid) void AddUnbroadcastTx(const Txid& txid)
{ {
LOCK(cs); LOCK(cs);
// Sanity check the transaction is in the mempool & insert into // Sanity check the transaction is in the mempool & insert into
// unbroadcast set. // unbroadcast set.
if (exists(GenTxid::Txid(txid))) m_unbroadcast_txids.insert(txid); if (exists(txid)) m_unbroadcast_txids.insert(txid);
}; };
/** Removes a transaction from the unbroadcast set */ /** Removes a transaction from the unbroadcast set */
void RemoveUnbroadcastTx(const uint256& txid, const bool unchecked = false); void RemoveUnbroadcastTx(const Txid& txid, const bool unchecked = false);
/** Returns transactions in unbroadcast set */ /** Returns transactions in unbroadcast set */
std::set<uint256> GetUnbroadcastTxs() const std::set<Txid> GetUnbroadcastTxs() const
{ {
LOCK(cs); LOCK(cs);
return m_unbroadcast_txids; return m_unbroadcast_txids;
} }
/** Returns whether a txid is in the unbroadcast set */ /** Returns whether a txid is in the unbroadcast set */
bool IsUnbroadcastTx(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs) bool IsUnbroadcastTx(const Txid& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
return m_unbroadcast_txids.count(txid) != 0; return m_unbroadcast_txids.count(txid) != 0;
@ -750,7 +752,7 @@ private:
* removeRecursive them. * removeRecursive them.
*/ */
void UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants, void UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants,
const std::set<uint256>& setExclude, std::set<uint256>& descendants_to_remove) EXCLUSIVE_LOCKS_REQUIRED(cs); const std::set<Txid>& setExclude, std::set<Txid>& descendants_to_remove) EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Update ancestors of hash to add/remove it as a descendant transaction. */ /** Update ancestors of hash to add/remove it as a descendant transaction. */
void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors) EXCLUSIVE_LOCKS_REQUIRED(cs); void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors) EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Set ancestor state for an entry */ /** Set ancestor state for an entry */

View file

@ -60,7 +60,7 @@ using SequenceNumber = uint64_t;
/** An announcement. This is the data we track for each txid or wtxid that is announced to us by each peer. */ /** An announcement. This is the data we track for each txid or wtxid that is announced to us by each peer. */
struct Announcement { struct Announcement {
/** Txid or wtxid that was announced. */ /** Txid or wtxid that was announced. */
const uint256 m_txhash; const GenTxid m_txhash;
/** For CANDIDATE_{DELAYED,BEST,READY} the reqtime; for REQUESTED the expiry. */ /** For CANDIDATE_{DELAYED,BEST,READY} the reqtime; for REQUESTED the expiry. */
std::chrono::microseconds m_time; std::chrono::microseconds m_time;
/** What peer the request was from. */ /** What peer the request was from. */
@ -70,7 +70,7 @@ struct Announcement {
/** Whether the request is preferred. */ /** Whether the request is preferred. */
const bool m_preferred : 1; const bool m_preferred : 1;
/** Whether this is a wtxid request. */ /** Whether this is a wtxid request. */
const bool m_is_wtxid : 1; //const bool m_is_wtxid : 1;
/** What state this announcement is in. */ /** What state this announcement is in. */
State m_state : 3 {State::CANDIDATE_DELAYED}; State m_state : 3 {State::CANDIDATE_DELAYED};
@ -98,8 +98,7 @@ struct Announcement {
/** Construct a new announcement from scratch, initially in CANDIDATE_DELAYED state. */ /** Construct a new announcement from scratch, initially in CANDIDATE_DELAYED state. */
Announcement(const GenTxid& gtxid, NodeId peer, bool preferred, std::chrono::microseconds reqtime, Announcement(const GenTxid& gtxid, NodeId peer, bool preferred, std::chrono::microseconds reqtime,
SequenceNumber sequence) SequenceNumber sequence)
: m_txhash(gtxid.GetHash()), m_time(reqtime), m_peer(peer), m_sequence(sequence), m_preferred(preferred), : m_txhash(gtxid), m_time(reqtime), m_peer(peer), m_sequence(sequence), m_preferred(preferred) {}
m_is_wtxid{gtxid.IsWtxid()} {}
}; };
//! Type alias for priorities. //! Type alias for priorities.
@ -116,9 +115,9 @@ public:
m_k0{deterministic ? 0 : FastRandomContext().rand64()}, m_k0{deterministic ? 0 : FastRandomContext().rand64()},
m_k1{deterministic ? 0 : FastRandomContext().rand64()} {} m_k1{deterministic ? 0 : FastRandomContext().rand64()} {}
Priority operator()(const uint256& txhash, NodeId peer, bool preferred) const Priority operator()(const GenTxid& txhash, NodeId peer, bool preferred) const
{ {
uint64_t low_bits = CSipHasher(m_k0, m_k1).Write(txhash).Write(peer).Finalize() >> 1; uint64_t low_bits = CSipHasher(m_k0, m_k1).Write(txhash.ToUint256()).Write(peer).Finalize() >> 1;
return low_bits | uint64_t{preferred} << 63; return low_bits | uint64_t{preferred} << 63;
} }
@ -142,7 +141,7 @@ public:
// (peer, true, txhash). // (peer, true, txhash).
// * Finding all CANDIDATE_BEST announcements for a given peer in GetRequestable. // * Finding all CANDIDATE_BEST announcements for a given peer in GetRequestable.
struct ByPeer {}; struct ByPeer {};
using ByPeerView = std::tuple<NodeId, bool, const uint256&>; using ByPeerView = std::tuple<NodeId, bool, const GenTxid&>;
struct ByPeerViewExtractor struct ByPeerViewExtractor
{ {
using result_type = ByPeerView; using result_type = ByPeerView;
@ -163,7 +162,7 @@ struct ByPeerViewExtractor
// * Determining when no more non-COMPLETED announcements for a given txhash exist, so the COMPLETED ones can be // * Determining when no more non-COMPLETED announcements for a given txhash exist, so the COMPLETED ones can be
// deleted. // deleted.
struct ByTxHash {}; struct ByTxHash {};
using ByTxHashView = std::tuple<const uint256&, State, Priority>; using ByTxHashView = std::tuple<const GenTxid&, State, Priority>;
class ByTxHashViewExtractor { class ByTxHashViewExtractor {
const PriorityComputer& m_computer; const PriorityComputer& m_computer;
public: public:
@ -276,9 +275,9 @@ std::unordered_map<NodeId, PeerInfo> RecomputePeerInfo(const Index& index)
} }
/** Compute the TxHashInfo map. Only used for sanity checking. */ /** Compute the TxHashInfo map. Only used for sanity checking. */
std::map<uint256, TxHashInfo> ComputeTxHashInfo(const Index& index, const PriorityComputer& computer) std::map<GenTxid, TxHashInfo> ComputeTxHashInfo(const Index& index, const PriorityComputer& computer)
{ {
std::map<uint256, TxHashInfo> ret; std::map<GenTxid, TxHashInfo> ret;
for (const Announcement& ann : index) { for (const Announcement& ann : index) {
TxHashInfo& info = ret[ann.m_txhash]; TxHashInfo& info = ret[ann.m_txhash];
// Classify how many announcements of each state we have for this txhash. // Classify how many announcements of each state we have for this txhash.
@ -299,11 +298,6 @@ std::map<uint256, TxHashInfo> ComputeTxHashInfo(const Index& index, const Priori
return ret; return ret;
} }
GenTxid ToGenTxid(const Announcement& ann)
{
return ann.m_is_wtxid ? GenTxid::Wtxid(ann.m_txhash) : GenTxid::Txid(ann.m_txhash);
}
} // namespace } // namespace
/** Actual implementation for TxRequestTracker's data structure. */ /** Actual implementation for TxRequestTracker's data structure. */
@ -472,7 +466,7 @@ private:
if (IsOnlyNonCompleted(it)) { if (IsOnlyNonCompleted(it)) {
// This is the last non-COMPLETED announcement for this txhash. Delete all. // This is the last non-COMPLETED announcement for this txhash. Delete all.
uint256 txhash = it->m_txhash; GenTxid txhash = it->m_txhash;
do { do {
it = Erase<ByTxHash>(it); it = Erase<ByTxHash>(it);
} while (it != m_index.get<ByTxHash>().end() && it->m_txhash == txhash); } while (it != m_index.get<ByTxHash>().end() && it->m_txhash == txhash);
@ -501,7 +495,7 @@ private:
if (it->GetState() == State::CANDIDATE_DELAYED && it->m_time <= now) { if (it->GetState() == State::CANDIDATE_DELAYED && it->m_time <= now) {
PromoteCandidateReady(m_index.project<ByTxHash>(it)); PromoteCandidateReady(m_index.project<ByTxHash>(it));
} else if (it->GetState() == State::REQUESTED && it->m_time <= now) { } else if (it->GetState() == State::REQUESTED && it->m_time <= now) {
if (expired) expired->emplace_back(it->m_peer, ToGenTxid(*it)); if (expired) expired->emplace_back(it->m_peer, it->m_txhash);
MakeCompleted(m_index.project<ByTxHash>(it)); MakeCompleted(m_index.project<ByTxHash>(it));
} else { } else {
break; break;
@ -538,7 +532,8 @@ public:
void DisconnectedPeer(NodeId peer) void DisconnectedPeer(NodeId peer)
{ {
auto& index = m_index.get<ByPeer>(); auto& index = m_index.get<ByPeer>();
auto it = index.lower_bound(ByPeerView{peer, false, uint256::ZERO}); GenTxid lowerzero = Txid::FromUint256(uint256::ZERO);
auto it = index.lower_bound(ByPeerView{peer, false, lowerzero});
while (it != index.end() && it->m_peer == peer) { while (it != index.end() && it->m_peer == peer) {
// Check what to continue with after this iteration. 'it' will be deleted in what follows, so we need to // Check what to continue with after this iteration. 'it' will be deleted in what follows, so we need to
// decide what to continue with afterwards. There are a number of cases to consider: // decide what to continue with afterwards. There are a number of cases to consider:
@ -566,7 +561,7 @@ public:
} }
} }
void ForgetTxHash(const uint256& txhash) void ForgetTxHash(const GenTxid& txhash)
{ {
auto it = m_index.get<ByTxHash>().lower_bound(ByTxHashView{txhash, State::CANDIDATE_DELAYED, 0}); auto it = m_index.get<ByTxHash>().lower_bound(ByTxHashView{txhash, State::CANDIDATE_DELAYED, 0});
while (it != m_index.get<ByTxHash>().end() && it->m_txhash == txhash) { while (it != m_index.get<ByTxHash>().end() && it->m_txhash == txhash) {
@ -574,7 +569,7 @@ public:
} }
} }
void GetCandidatePeers(const uint256& txhash, std::vector<NodeId>& result_peers) const void GetCandidatePeers(const GenTxid& txhash, std::vector<NodeId>& result_peers) const
{ {
auto it = m_index.get<ByTxHash>().lower_bound(ByTxHashView{txhash, State::CANDIDATE_DELAYED, 0}); auto it = m_index.get<ByTxHash>().lower_bound(ByTxHashView{txhash, State::CANDIDATE_DELAYED, 0});
while (it != m_index.get<ByTxHash>().end() && it->m_txhash == txhash && it->GetState() != State::COMPLETED) { while (it != m_index.get<ByTxHash>().end() && it->m_txhash == txhash && it->GetState() != State::COMPLETED) {
@ -589,7 +584,7 @@ public:
// Bail out if we already have a CANDIDATE_BEST announcement for this (txhash, peer) combination. The case // Bail out if we already have a CANDIDATE_BEST announcement for this (txhash, peer) combination. The case
// where there is a non-CANDIDATE_BEST announcement already will be caught by the uniqueness property of the // where there is a non-CANDIDATE_BEST announcement already will be caught by the uniqueness property of the
// ByPeer index when we try to emplace the new object below. // ByPeer index when we try to emplace the new object below.
if (m_index.get<ByPeer>().count(ByPeerView{peer, true, gtxid.GetHash()})) return; if (m_index.get<ByPeer>().count(ByPeerView{peer, true, gtxid})) return;
// Try creating the announcement with CANDIDATE_DELAYED state (which will fail due to the uniqueness // Try creating the announcement with CANDIDATE_DELAYED state (which will fail due to the uniqueness
// of the ByPeer index if a non-CANDIDATE_BEST announcement already exists with the same txhash and peer). // of the ByPeer index if a non-CANDIDATE_BEST announcement already exists with the same txhash and peer).
@ -611,7 +606,8 @@ public:
// Find all CANDIDATE_BEST announcements for this peer. // Find all CANDIDATE_BEST announcements for this peer.
std::vector<const Announcement*> selected; std::vector<const Announcement*> selected;
auto it_peer = m_index.get<ByPeer>().lower_bound(ByPeerView{peer, true, uint256::ZERO}); GenTxid lowerzero = Txid::FromUint256(uint256::ZERO);
auto it_peer = m_index.get<ByPeer>().lower_bound(ByPeerView{peer, true, lowerzero});
while (it_peer != m_index.get<ByPeer>().end() && it_peer->m_peer == peer && while (it_peer != m_index.get<ByPeer>().end() && it_peer->m_peer == peer &&
it_peer->GetState() == State::CANDIDATE_BEST) { it_peer->GetState() == State::CANDIDATE_BEST) {
selected.emplace_back(&*it_peer); selected.emplace_back(&*it_peer);
@ -627,12 +623,12 @@ public:
std::vector<GenTxid> ret; std::vector<GenTxid> ret;
ret.reserve(selected.size()); ret.reserve(selected.size());
std::transform(selected.begin(), selected.end(), std::back_inserter(ret), [](const Announcement* ann) { std::transform(selected.begin(), selected.end(), std::back_inserter(ret), [](const Announcement* ann) {
return ToGenTxid(*ann); return ann->m_txhash;
}); });
return ret; return ret;
} }
void RequestedTx(NodeId peer, const uint256& txhash, std::chrono::microseconds expiry) void RequestedTx(NodeId peer, const GenTxid& txhash, std::chrono::microseconds expiry)
{ {
auto it = m_index.get<ByPeer>().find(ByPeerView{peer, true, txhash}); auto it = m_index.get<ByPeer>().find(ByPeerView{peer, true, txhash});
if (it == m_index.get<ByPeer>().end()) { if (it == m_index.get<ByPeer>().end()) {
@ -677,7 +673,7 @@ public:
}); });
} }
void ReceivedResponse(NodeId peer, const uint256& txhash) void ReceivedResponse(NodeId peer, const GenTxid& txhash)
{ {
// We need to search the ByPeer index for both (peer, false, txhash) and (peer, true, txhash). // We need to search the ByPeer index for both (peer, false, txhash) and (peer, true, txhash).
auto it = m_index.get<ByPeer>().find(ByPeerView{peer, false, txhash}); auto it = m_index.get<ByPeer>().find(ByPeerView{peer, false, txhash});
@ -711,7 +707,7 @@ public:
//! Count how many announcements are being tracked in total across all peers and transactions. //! Count how many announcements are being tracked in total across all peers and transactions.
size_t Size() const { return m_index.size(); } size_t Size() const { return m_index.size(); }
uint64_t ComputePriority(const uint256& txhash, NodeId peer, bool preferred) const uint64_t ComputePriority(const GenTxid& txhash, NodeId peer, bool preferred) const
{ {
// Return Priority as a uint64_t as Priority is internal. // Return Priority as a uint64_t as Priority is internal.
return uint64_t{m_computer(txhash, peer, preferred)}; return uint64_t{m_computer(txhash, peer, preferred)};
@ -724,13 +720,13 @@ TxRequestTracker::TxRequestTracker(bool deterministic) :
TxRequestTracker::~TxRequestTracker() = default; TxRequestTracker::~TxRequestTracker() = default;
void TxRequestTracker::ForgetTxHash(const uint256& txhash) { m_impl->ForgetTxHash(txhash); } void TxRequestTracker::ForgetTxHash(const GenTxid& txhash) { m_impl->ForgetTxHash(txhash); }
void TxRequestTracker::DisconnectedPeer(NodeId peer) { m_impl->DisconnectedPeer(peer); } void TxRequestTracker::DisconnectedPeer(NodeId peer) { m_impl->DisconnectedPeer(peer); }
size_t TxRequestTracker::CountInFlight(NodeId peer) const { return m_impl->CountInFlight(peer); } size_t TxRequestTracker::CountInFlight(NodeId peer) const { return m_impl->CountInFlight(peer); }
size_t TxRequestTracker::CountCandidates(NodeId peer) const { return m_impl->CountCandidates(peer); } size_t TxRequestTracker::CountCandidates(NodeId peer) const { return m_impl->CountCandidates(peer); }
size_t TxRequestTracker::Count(NodeId peer) const { return m_impl->Count(peer); } size_t TxRequestTracker::Count(NodeId peer) const { return m_impl->Count(peer); }
size_t TxRequestTracker::Size() const { return m_impl->Size(); } size_t TxRequestTracker::Size() const { return m_impl->Size(); }
void TxRequestTracker::GetCandidatePeers(const uint256& txhash, std::vector<NodeId>& result_peers) const { return m_impl->GetCandidatePeers(txhash, result_peers); } void TxRequestTracker::GetCandidatePeers(const GenTxid& txhash, std::vector<NodeId>& result_peers) const { return m_impl->GetCandidatePeers(txhash, result_peers); }
void TxRequestTracker::SanityCheck() const { m_impl->SanityCheck(); } void TxRequestTracker::SanityCheck() const { m_impl->SanityCheck(); }
void TxRequestTracker::PostGetRequestableSanityCheck(std::chrono::microseconds now) const void TxRequestTracker::PostGetRequestableSanityCheck(std::chrono::microseconds now) const
@ -744,12 +740,12 @@ void TxRequestTracker::ReceivedInv(NodeId peer, const GenTxid& gtxid, bool prefe
m_impl->ReceivedInv(peer, gtxid, preferred, reqtime); m_impl->ReceivedInv(peer, gtxid, preferred, reqtime);
} }
void TxRequestTracker::RequestedTx(NodeId peer, const uint256& txhash, std::chrono::microseconds expiry) void TxRequestTracker::RequestedTx(NodeId peer, const GenTxid& txhash, std::chrono::microseconds expiry)
{ {
m_impl->RequestedTx(peer, txhash, expiry); m_impl->RequestedTx(peer, txhash, expiry);
} }
void TxRequestTracker::ReceivedResponse(NodeId peer, const uint256& txhash) void TxRequestTracker::ReceivedResponse(NodeId peer, const GenTxid& txhash)
{ {
m_impl->ReceivedResponse(peer, txhash); m_impl->ReceivedResponse(peer, txhash);
} }
@ -760,7 +756,7 @@ std::vector<GenTxid> TxRequestTracker::GetRequestable(NodeId peer, std::chrono::
return m_impl->GetRequestable(peer, now, expired); return m_impl->GetRequestable(peer, now, expired);
} }
uint64_t TxRequestTracker::ComputePriority(const uint256& txhash, NodeId peer, bool preferred) const uint64_t TxRequestTracker::ComputePriority(const GenTxid& txhash, NodeId peer, bool preferred) const
{ {
return m_impl->ComputePriority(txhash, peer, preferred); return m_impl->ComputePriority(txhash, peer, preferred);
} }

View file

@ -146,7 +146,7 @@ public:
* This should be called when a transaction is no longer needed. The caller should ensure that new announcements * This should be called when a transaction is no longer needed. The caller should ensure that new announcements
* for the same txhash will not trigger new ReceivedInv calls, at least in the short term after this call. * for the same txhash will not trigger new ReceivedInv calls, at least in the short term after this call.
*/ */
void ForgetTxHash(const uint256& txhash); void ForgetTxHash(const GenTxid& txhash);
/** Find the txids to request now from peer. /** Find the txids to request now from peer.
* *
@ -175,7 +175,7 @@ public:
* was made (GetRequestable will never advise doing so). In this case it is converted to COMPLETED, as we're * was made (GetRequestable will never advise doing so). In this case it is converted to COMPLETED, as we're
* no longer waiting for a response to it. * no longer waiting for a response to it.
*/ */
void RequestedTx(NodeId peer, const uint256& txhash, std::chrono::microseconds expiry); void RequestedTx(NodeId peer, const GenTxid& txhash, std::chrono::microseconds expiry);
/** Converts a CANDIDATE or REQUESTED announcement to a COMPLETED one. If no such announcement exists for the /** Converts a CANDIDATE or REQUESTED announcement to a COMPLETED one. If no such announcement exists for the
* provided peer and txhash, nothing happens. * provided peer and txhash, nothing happens.
@ -183,7 +183,7 @@ public:
* It should be called whenever a transaction or NOTFOUND was received from a peer. When the transaction is * It should be called whenever a transaction or NOTFOUND was received from a peer. When the transaction is
* not needed entirely anymore, ForgetTxhash should be called instead of, or in addition to, this call. * not needed entirely anymore, ForgetTxhash should be called instead of, or in addition to, this call.
*/ */
void ReceivedResponse(NodeId peer, const uint256& txhash); void ReceivedResponse(NodeId peer, const GenTxid& txhash);
// The operations below inspect the data structure. // The operations below inspect the data structure.
@ -201,10 +201,10 @@ public:
/** For some txhash (txid or wtxid), finds all peers with non-COMPLETED announcements and appends them to /** For some txhash (txid or wtxid), finds all peers with non-COMPLETED announcements and appends them to
* result_peers. Does not try to ensure that result_peers contains no duplicates. */ * result_peers. Does not try to ensure that result_peers contains no duplicates. */
void GetCandidatePeers(const uint256& txhash, std::vector<NodeId>& result_peers) const; void GetCandidatePeers(const GenTxid& txhash, std::vector<NodeId>& result_peers) const;
/** Access to the internal priority computation (testing only) */ /** Access to the internal priority computation (testing only) */
uint64_t ComputePriority(const uint256& txhash, NodeId peer, bool preferred) const; uint64_t ComputePriority(const GenTxid& txhash, NodeId peer, bool preferred) const;
/** Run internal consistency check (testing only). */ /** Run internal consistency check (testing only). */
void SanityCheck() const; void SanityCheck() const;

View file

@ -7,6 +7,10 @@
#include <span.h> #include <span.h>
#include <util/hasher.h> #include <util/hasher.h>
SaltedUint256Hasher::SaltedUint256Hasher() :
k0{FastRandomContext().rand64()},
k1{FastRandomContext().rand64()} {}
SaltedTxidHasher::SaltedTxidHasher() : SaltedTxidHasher::SaltedTxidHasher() :
k0{FastRandomContext().rand64()}, k0{FastRandomContext().rand64()},
k1{FastRandomContext().rand64()} {} k1{FastRandomContext().rand64()} {}

View file

@ -11,9 +11,24 @@
#include <span.h> #include <span.h>
#include <uint256.h> #include <uint256.h>
#include <concepts>
#include <cstdint> #include <cstdint>
#include <cstring> #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 class SaltedTxidHasher
{ {
private: private:
@ -23,8 +38,10 @@ private:
public: public:
SaltedTxidHasher(); SaltedTxidHasher();
size_t operator()(const uint256& txid) const { template <typename T>
return SipHashUint256(k0, k1, txid); requires std::same_as<T, Txid> || std::same_as<T, Wtxid>
size_t operator()(const T& txid) const {
return SipHashUint256(k0, k1, txid.ToUint256());
} }
}; };
@ -47,7 +64,7 @@ public:
* @see https://gcc.gnu.org/onlinedocs/gcc-13.2.0/libstdc++/manual/manual/unordered_associative.html * @see https://gcc.gnu.org/onlinedocs/gcc-13.2.0/libstdc++/manual/manual/unordered_associative.html
*/ */
size_t operator()(const COutPoint& id) const noexcept { 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);
} }
}; };

View file

@ -5,6 +5,8 @@
#include <uint256.h> #include <uint256.h>
#include <util/types.h> #include <util/types.h>
#include <variant>
/** transaction_identifier represents the two canonical transaction identifier /** transaction_identifier represents the two canonical transaction identifier
* types (txid, wtxid).*/ * types (txid, wtxid).*/
template <bool has_witness> template <bool has_witness>
@ -15,9 +17,6 @@ class transaction_identifier
// Note: Use FromUint256 externally instead. // Note: Use FromUint256 externally instead.
transaction_identifier(const uint256& wrapped) : m_wrapped{wrapped} {} transaction_identifier(const uint256& wrapped) : m_wrapped{wrapped} {}
// TODO: Comparisons with uint256 should be disallowed once we have
// converted most of the code to using the new txid types.
constexpr int Compare(const uint256& other) const { return m_wrapped.Compare(other); }
constexpr int Compare(const transaction_identifier<has_witness>& other) const { return m_wrapped.Compare(other.m_wrapped); } constexpr int Compare(const transaction_identifier<has_witness>& other) const { return m_wrapped.Compare(other.m_wrapped); }
template <typename Other> template <typename Other>
constexpr int Compare(const Other& other) const constexpr int Compare(const Other& other) const
@ -56,15 +55,6 @@ public:
constexpr const std::byte* end() const { return reinterpret_cast<const std::byte*>(m_wrapped.end()); } constexpr const std::byte* end() const { return reinterpret_cast<const std::byte*>(m_wrapped.end()); }
template <typename Stream> void Serialize(Stream& s) const { m_wrapped.Serialize(s); } template <typename Stream> void Serialize(Stream& s) const { m_wrapped.Serialize(s); }
template <typename Stream> void Unserialize(Stream& s) { m_wrapped.Unserialize(s); } template <typename Stream> void Unserialize(Stream& s) { m_wrapped.Unserialize(s); }
/** Conversion function to `uint256`.
*
* Note: new code should use `ToUint256`.
*
* TODO: This should be removed once the majority of the code has switched
* to using the Txid and Wtxid types. Until then it makes for a smoother
* transition to allow this conversion. */
operator const uint256&() const LIFETIMEBOUND { return m_wrapped; }
}; };
/** Txid commits to all transaction fields except the witness. */ /** Txid commits to all transaction fields except the witness. */
@ -72,4 +62,25 @@ using Txid = transaction_identifier<false>;
/** Wtxid commits to all transaction fields including the witness. */ /** Wtxid commits to all transaction fields including the witness. */
using Wtxid = transaction_identifier<true>; using Wtxid = transaction_identifier<true>;
/** A generic txid reference (txid or wtxid). */
class GenTxid : public std::variant<Txid, Wtxid>
{
public:
using variant::variant;
const uint256& ToUint256() const LIFETIMEBOUND {
return std::visit([](const auto& id) -> const uint256& { return id.ToUint256(); }, *this);
}
friend bool operator==(const GenTxid& a, const GenTxid& b) {
//return a.index() == b.index() && a.ToUint256() == b.ToUint256();
return a.ToUint256() == b.ToUint256();
}
friend bool operator<(const GenTxid& a, const GenTxid& b) {
//return std::tuple(a.index(), a.ToUint256()) < std::tuple(b.index(), b.ToUint256());
return a.ToUint256() < b.ToUint256();
}
};
#endif // BITCOIN_UTIL_TRANSACTION_IDENTIFIER_H #endif // BITCOIN_UTIL_TRANSACTION_IDENTIFIER_H

View file

@ -301,7 +301,7 @@ void Chainstate::MaybeUpdateMempoolForReorg(
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
AssertLockHeld(m_mempool->cs); AssertLockHeld(m_mempool->cs);
std::vector<uint256> vHashUpdate; std::vector<Txid> vHashUpdate;
{ {
// disconnectpool is ordered so that the front is the most recently-confirmed // disconnectpool is ordered so that the front is the most recently-confirmed
// transaction (the last tx of the block at the tip) in the disconnected chain. // transaction (the last tx of the block at the tip) in the disconnected chain.
@ -319,7 +319,7 @@ void Chainstate::MaybeUpdateMempoolForReorg(
// If the transaction doesn't make it in to the mempool, remove any // If the transaction doesn't make it in to the mempool, remove any
// transactions that depend on it (which would now be orphans). // transactions that depend on it (which would now be orphans).
m_mempool->removeRecursive(**it, MemPoolRemovalReason::REORG); m_mempool->removeRecursive(**it, MemPoolRemovalReason::REORG);
} else if (m_mempool->exists(GenTxid::Txid((*it)->GetHash()))) { } else if (m_mempool->exists((*it)->GetHash())) {
vHashUpdate.push_back((*it)->GetHash()); vHashUpdate.push_back((*it)->GetHash());
} }
++it; ++it;
@ -370,7 +370,7 @@ void Chainstate::MaybeUpdateMempoolForReorg(
// If the transaction spends any coinbase outputs, it must be mature. // If the transaction spends any coinbase outputs, it must be mature.
if (it->GetSpendsCoinbase()) { if (it->GetSpendsCoinbase()) {
for (const CTxIn& txin : tx.vin) { for (const CTxIn& txin : tx.vin) {
if (m_mempool->exists(GenTxid::Txid(txin.prevout.hash))) continue; if (m_mempool->exists(txin.prevout.hash)) continue;
const Coin& coin{CoinsTip().AccessCoin(txin.prevout)}; const Coin& coin{CoinsTip().AccessCoin(txin.prevout)};
assert(!coin.IsSpent()); assert(!coin.IsSpent());
const auto mempool_spend_height{m_chain.Tip()->nHeight + 1}; const auto mempool_spend_height{m_chain.Tip()->nHeight + 1};
@ -805,10 +805,10 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-final"); return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-final");
} }
if (m_pool.exists(GenTxid::Wtxid(tx.GetWitnessHash()))) { if (m_pool.exists(tx.GetWitnessHash())) {
// Exact transaction already exists in the mempool. // Exact transaction already exists in the mempool.
return state.Invalid(TxValidationResult::TX_CONFLICT, "txn-already-in-mempool"); return state.Invalid(TxValidationResult::TX_CONFLICT, "txn-already-in-mempool");
} else if (m_pool.exists(GenTxid::Txid(tx.GetHash()))) { } else if (m_pool.exists(tx.GetHash())) {
// Transaction with the same non-witness data but different witness (same txid, different // Transaction with the same non-witness data but different witness (same txid, different
// wtxid) already exists in the mempool. // wtxid) already exists in the mempool.
return state.Invalid(TxValidationResult::TX_CONFLICT, "txn-same-nonwitness-data-in-mempool"); return state.Invalid(TxValidationResult::TX_CONFLICT, "txn-same-nonwitness-data-in-mempool");
@ -1069,7 +1069,7 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
AssertLockHeld(m_pool.cs); AssertLockHeld(m_pool.cs);
const CTransaction& tx = *ws.m_ptx; const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash; const Txid& hash = ws.m_hash;
TxValidationState& state = ws.m_state; TxValidationState& state = ws.m_state;
CFeeRate newFeeRate(ws.m_modified_fees, ws.m_vsize); CFeeRate newFeeRate(ws.m_modified_fees, ws.m_vsize);
@ -1134,7 +1134,7 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
// CheckPackageLimits expects the package transactions to not already be in the mempool. // CheckPackageLimits expects the package transactions to not already be in the mempool.
assert(std::all_of(txns.cbegin(), txns.cend(), [this](const auto& tx) assert(std::all_of(txns.cbegin(), txns.cend(), [this](const auto& tx)
{ return !m_pool.exists(GenTxid::Txid(tx->GetHash()));})); { return !m_pool.exists(tx->GetHash());}));
assert(txns.size() == workspaces.size()); assert(txns.size() == workspaces.size());
@ -1257,7 +1257,7 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws)
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
AssertLockHeld(m_pool.cs); AssertLockHeld(m_pool.cs);
const CTransaction& tx = *ws.m_ptx; const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash; const Txid& hash = ws.m_hash;
TxValidationState& state = ws.m_state; TxValidationState& state = ws.m_state;
// Check again against the current block tip's script verification // Check again against the current block tip's script verification
@ -1304,7 +1304,7 @@ void MemPoolAccept::FinalizeSubpackage(const ATMPArgs& args)
const bool replaced_with_tx{m_subpackage.m_changeset->GetTxCount() == 1}; const bool replaced_with_tx{m_subpackage.m_changeset->GetTxCount() == 1};
if (replaced_with_tx) { if (replaced_with_tx) {
const CTransaction& tx = m_subpackage.m_changeset->GetAddedTxn(0); 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)", log_string += strprintf("New tx %s (wtxid=%s, fees=%s, vsize=%s)",
tx.GetHash().ToString(), tx.GetHash().ToString(),
tx.GetWitnessHash().ToString(), tx.GetWitnessHash().ToString(),
@ -1345,7 +1345,7 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
// Sanity check: none of the transactions should be in the mempool, and none of the transactions // Sanity check: none of the transactions should be in the mempool, and none of the transactions
// should have a same-txid-different-witness equivalent in the mempool. // should have a same-txid-different-witness equivalent in the mempool.
assert(std::all_of(workspaces.cbegin(), workspaces.cend(), [this](const auto& ws){ assert(std::all_of(workspaces.cbegin(), workspaces.cend(), [this](const auto& ws){
return !m_pool.exists(GenTxid::Txid(ws.m_ptx->GetHash())); })); return !m_pool.exists(ws.m_ptx->GetHash()); }));
bool all_submitted = true; bool all_submitted = true;
FinalizeSubpackage(args); FinalizeSubpackage(args);
@ -1470,7 +1470,7 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
// Limit the mempool, if appropriate. // Limit the mempool, if appropriate.
if (!args.m_package_submission && !args.m_bypass_limits) { if (!args.m_package_submission && !args.m_bypass_limits) {
LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip()); LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip());
if (!m_pool.exists(GenTxid::Txid(ws.m_hash))) { if (!m_pool.exists(ws.m_hash)) {
// The tx no longer meets our (new) mempool minimum feerate but could be reconsidered in a package. // The tx no longer meets our (new) mempool minimum feerate but could be reconsidered in a package.
ws.m_state.Invalid(TxValidationResult::TX_RECONSIDERABLE, "mempool full"); ws.m_state.Invalid(TxValidationResult::TX_RECONSIDERABLE, "mempool full");
return MempoolAcceptResult::FeeFailure(ws.m_state, CFeeRate(ws.m_modified_fees, ws.m_vsize), {ws.m_ptx->GetWitnessHash()}); return MempoolAcceptResult::FeeFailure(ws.m_state, CFeeRate(ws.m_modified_fees, ws.m_vsize), {ws.m_ptx->GetWitnessHash()});
@ -1716,7 +1716,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
// The package must be 1 child with all of its unconfirmed parents. The package is expected to // The package must be 1 child with all of its unconfirmed parents. The package is expected to
// be sorted, so the last transaction is the child. // be sorted, so the last transaction is the child.
const auto& child = package.back(); const auto& child = package.back();
std::unordered_set<uint256, SaltedTxidHasher> unconfirmed_parent_txids; std::unordered_set<Txid, SaltedTxidHasher> unconfirmed_parent_txids;
std::transform(package.cbegin(), package.cend() - 1, std::transform(package.cbegin(), package.cend() - 1,
std::inserter(unconfirmed_parent_txids, unconfirmed_parent_txids.end()), std::inserter(unconfirmed_parent_txids, unconfirmed_parent_txids.end()),
[](const auto& tx) { return tx->GetHash(); }); [](const auto& tx) { return tx->GetHash(); });
@ -1765,7 +1765,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
// There are 3 possibilities: already in mempool, same-txid-diff-wtxid already in mempool, // There are 3 possibilities: already in mempool, same-txid-diff-wtxid already in mempool,
// or not in mempool. An already confirmed tx is treated as one not in mempool, because all // or not in mempool. An already confirmed tx is treated as one not in mempool, because all
// we know is that the inputs aren't available. // we know is that the inputs aren't available.
if (m_pool.exists(GenTxid::Wtxid(wtxid))) { if (m_pool.exists(wtxid)) {
// Exact transaction already exists in the mempool. // Exact transaction already exists in the mempool.
// Node operators are free to set their mempool policies however they please, nodes may receive // Node operators are free to set their mempool policies however they please, nodes may receive
// transactions in different orders, and malicious counterparties may try to take advantage of // transactions in different orders, and malicious counterparties may try to take advantage of
@ -1777,7 +1777,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
// checking ancestor/descendant limits, or double-count transaction fees for fee-related policy. // checking ancestor/descendant limits, or double-count transaction fees for fee-related policy.
const auto& entry{*Assert(m_pool.GetEntry(txid))}; const auto& entry{*Assert(m_pool.GetEntry(txid))};
results_final.emplace(wtxid, MempoolAcceptResult::MempoolTx(entry.GetTxSize(), entry.GetFee())); results_final.emplace(wtxid, MempoolAcceptResult::MempoolTx(entry.GetTxSize(), entry.GetFee()));
} else if (m_pool.exists(GenTxid::Txid(txid))) { } else if (m_pool.exists(txid)) {
// Transaction with the same non-witness data but different witness (same txid, // Transaction with the same non-witness data but different witness (same txid,
// different wtxid) already exists in the mempool. // different wtxid) already exists in the mempool.
// //
@ -1796,7 +1796,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
if (single_res.m_result_type == MempoolAcceptResult::ResultType::VALID) { if (single_res.m_result_type == MempoolAcceptResult::ResultType::VALID) {
// The transaction succeeded on its own and is now in the mempool. Don't include it // The transaction succeeded on its own and is now in the mempool. Don't include it
// in package validation, because its fees should only be "used" once. // in package validation, because its fees should only be "used" once.
assert(m_pool.exists(GenTxid::Wtxid(wtxid))); assert(m_pool.exists(wtxid));
results_final.emplace(wtxid, single_res); results_final.emplace(wtxid, single_res);
} else if (package.size() == 1 || // If there is only one transaction, no need to retry it "as a package" } else if (package.size() == 1 || // If there is only one transaction, no need to retry it "as a package"
(single_res.m_state.GetResult() != TxValidationResult::TX_RECONSIDERABLE && (single_res.m_state.GetResult() != TxValidationResult::TX_RECONSIDERABLE &&
@ -1841,7 +1841,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
// If it was submitted, check to see if the tx is still in the mempool. It could have // If it was submitted, check to see if the tx is still in the mempool. It could have
// been evicted due to LimitMempoolSize() above. // been evicted due to LimitMempoolSize() above.
const auto& txresult = multi_submission_result.m_tx_results.at(wtxid); const auto& txresult = multi_submission_result.m_tx_results.at(wtxid);
if (txresult.m_result_type == MempoolAcceptResult::ResultType::VALID && !m_pool.exists(GenTxid::Wtxid(wtxid))) { if (txresult.m_result_type == MempoolAcceptResult::ResultType::VALID && !m_pool.exists(wtxid)) {
package_state_final.Invalid(PackageValidationResult::PCKG_TX, "transaction failed"); package_state_final.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");
TxValidationState mempool_full_state; TxValidationState mempool_full_state;
mempool_full_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full"); mempool_full_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full");
@ -1855,7 +1855,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
Assume(it->second.m_result_type != MempoolAcceptResult::ResultType::INVALID); Assume(it->second.m_result_type != MempoolAcceptResult::ResultType::INVALID);
Assume(individual_results_nonfinal.count(wtxid) == 0); Assume(individual_results_nonfinal.count(wtxid) == 0);
// Query by txid to include the same-txid-different-witness ones. // Query by txid to include the same-txid-different-witness ones.
if (!m_pool.exists(GenTxid::Txid(tx->GetHash()))) { if (!m_pool.exists(tx->GetHash())) {
package_state_final.Invalid(PackageValidationResult::PCKG_TX, "transaction failed"); package_state_final.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");
TxValidationState mempool_full_state; TxValidationState mempool_full_state;
mempool_full_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full"); mempool_full_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full");

View file

@ -146,7 +146,7 @@ static CFeeRate EstimateFeeRate(const CWallet& wallet, const CWalletTx& wtx, con
namespace feebumper { namespace feebumper {
bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid) bool TransactionCanBeBumped(const CWallet& wallet, const Txid& txid)
{ {
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
const CWalletTx* wtx = wallet.GetWalletTx(txid); const CWalletTx* wtx = wallet.GetWalletTx(txid);
@ -157,7 +157,7 @@ bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid)
return res == feebumper::Result::OK; return res == feebumper::Result::OK;
} }
Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCoinControl& coin_control, std::vector<bilingual_str>& errors, Result CreateRateBumpTransaction(CWallet& wallet, const Txid& txid, const CCoinControl& coin_control, std::vector<bilingual_str>& errors,
CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx, bool require_mine, const std::vector<CTxOut>& outputs, std::optional<uint32_t> original_change_index) CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx, bool require_mine, const std::vector<CTxOut>& outputs, std::optional<uint32_t> original_change_index)
{ {
// For now, cannot specify both new outputs to use and an output index to send change // For now, cannot specify both new outputs to use and an output index to send change
@ -348,7 +348,7 @@ bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx) {
} }
} }
Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<bilingual_str>& errors, uint256& bumped_txid) Result CommitTransaction(CWallet& wallet, const Txid& txid, CMutableTransaction&& mtx, std::vector<bilingual_str>& errors, Txid& bumped_txid)
{ {
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
if (!errors.empty()) { if (!errors.empty()) {

View file

@ -31,7 +31,7 @@ enum class Result
}; };
//! Return whether transaction can be bumped. //! Return whether transaction can be bumped.
bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid); bool TransactionCanBeBumped(const CWallet& wallet, const Txid& txid);
/** Create bumpfee transaction based on feerate estimates. /** Create bumpfee transaction based on feerate estimates.
* *
@ -47,7 +47,7 @@ bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid);
* @param[in] original_change_index The position of the change output to deduct the fee from in the transaction being bumped * @param[in] original_change_index The position of the change output to deduct the fee from in the transaction being bumped
*/ */
Result CreateRateBumpTransaction(CWallet& wallet, Result CreateRateBumpTransaction(CWallet& wallet,
const uint256& txid, const Txid& txid,
const CCoinControl& coin_control, const CCoinControl& coin_control,
std::vector<bilingual_str>& errors, std::vector<bilingual_str>& errors,
CAmount& old_fee, CAmount& old_fee,
@ -67,10 +67,10 @@ bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx);
//! but sets errors if the tx could not be added to the mempool (will try later) //! but sets errors if the tx could not be added to the mempool (will try later)
//! or if the old transaction could not be marked as replaced. //! or if the old transaction could not be marked as replaced.
Result CommitTransaction(CWallet& wallet, Result CommitTransaction(CWallet& wallet,
const uint256& txid, const Txid& txid,
CMutableTransaction&& mtx, CMutableTransaction&& mtx,
std::vector<bilingual_str>& errors, std::vector<bilingual_str>& errors,
uint256& bumped_txid); Txid& bumped_txid);
struct SignatureWeights struct SignatureWeights
{ {

View file

@ -299,17 +299,17 @@ public:
LOCK(m_wallet->cs_wallet); LOCK(m_wallet->cs_wallet);
m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form)); m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form));
} }
bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet->TransactionCanBeAbandoned(txid); } bool transactionCanBeAbandoned(const Txid& txid) override { return m_wallet->TransactionCanBeAbandoned(txid); }
bool abandonTransaction(const uint256& txid) override bool abandonTransaction(const Txid& txid) override
{ {
LOCK(m_wallet->cs_wallet); LOCK(m_wallet->cs_wallet);
return m_wallet->AbandonTransaction(txid); return m_wallet->AbandonTransaction(txid);
} }
bool transactionCanBeBumped(const uint256& txid) override bool transactionCanBeBumped(const Txid& txid) override
{ {
return feebumper::TransactionCanBeBumped(*m_wallet.get(), txid); return feebumper::TransactionCanBeBumped(*m_wallet.get(), txid);
} }
bool createBumpTransaction(const uint256& txid, bool createBumpTransaction(const Txid& txid,
const CCoinControl& coin_control, const CCoinControl& coin_control,
std::vector<bilingual_str>& errors, std::vector<bilingual_str>& errors,
CAmount& old_fee, CAmount& old_fee,
@ -320,15 +320,15 @@ public:
return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx, /* require_mine= */ true, outputs) == feebumper::Result::OK; return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx, /* require_mine= */ true, outputs) == feebumper::Result::OK;
} }
bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(*m_wallet.get(), mtx); } bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(*m_wallet.get(), mtx); }
bool commitBumpTransaction(const uint256& txid, bool commitBumpTransaction(const Txid& txid,
CMutableTransaction&& mtx, CMutableTransaction&& mtx,
std::vector<bilingual_str>& errors, std::vector<bilingual_str>& errors,
uint256& bumped_txid) override Txid& bumped_txid) override
{ {
return feebumper::CommitTransaction(*m_wallet.get(), txid, std::move(mtx), errors, bumped_txid) == return feebumper::CommitTransaction(*m_wallet.get(), txid, std::move(mtx), errors, bumped_txid) ==
feebumper::Result::OK; feebumper::Result::OK;
} }
CTransactionRef getTx(const uint256& txid) override CTransactionRef getTx(const Txid& txid) override
{ {
LOCK(m_wallet->cs_wallet); LOCK(m_wallet->cs_wallet);
auto mi = m_wallet->mapWallet.find(txid); auto mi = m_wallet->mapWallet.find(txid);
@ -337,7 +337,7 @@ public:
} }
return {}; return {};
} }
WalletTx getWalletTx(const uint256& txid) override WalletTx getWalletTx(const Txid& txid) override
{ {
LOCK(m_wallet->cs_wallet); LOCK(m_wallet->cs_wallet);
auto mi = m_wallet->mapWallet.find(txid); auto mi = m_wallet->mapWallet.find(txid);
@ -355,7 +355,7 @@ public:
} }
return result; return result;
} }
bool tryGetTxStatus(const uint256& txid, bool tryGetTxStatus(const Txid& txid,
interfaces::WalletTxStatus& tx_status, interfaces::WalletTxStatus& tx_status,
int& num_blocks, int& num_blocks,
int64_t& block_time) override int64_t& block_time) override
@ -374,7 +374,7 @@ public:
tx_status = MakeWalletTxStatus(*m_wallet, mi->second); tx_status = MakeWalletTxStatus(*m_wallet, mi->second);
return true; return true;
} }
WalletTx getWalletTxDetails(const uint256& txid, WalletTx getWalletTxDetails(const Txid& txid,
WalletTxStatus& tx_status, WalletTxStatus& tx_status,
WalletOrderForm& order_form, WalletOrderForm& order_form,
bool& in_mempool, bool& in_mempool,
@ -548,7 +548,7 @@ public:
std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override
{ {
return MakeSignalHandler(m_wallet->NotifyTransactionChanged.connect( return MakeSignalHandler(m_wallet->NotifyTransactionChanged.connect(
[fn](const uint256& txid, ChangeType status) { fn(txid, status); })); [fn](const Txid& txid, ChangeType status) { fn(txid, status); }));
} }
std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) override std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) override
{ {

View file

@ -254,7 +254,7 @@ bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminef
} }
// NOLINTNEXTLINE(misc-no-recursion) // NOLINTNEXTLINE(misc-no-recursion)
bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<uint256>& trusted_parents) bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<Txid>& trusted_parents)
{ {
AssertLockHeld(wallet.cs_wallet); AssertLockHeld(wallet.cs_wallet);
if (wtx.isConfirmed()) return true; if (wtx.isConfirmed()) return true;
@ -285,7 +285,7 @@ bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<uin
bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx) bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx)
{ {
std::set<uint256> trusted_parents; std::set<Txid> trusted_parents;
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
return CachedTxIsTrusted(wallet, wtx, trusted_parents); return CachedTxIsTrusted(wallet, wtx, trusted_parents);
} }
@ -296,7 +296,7 @@ Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED; isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED;
{ {
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
std::set<uint256> trusted_parents; std::set<Txid> trusted_parents;
for (const auto& entry : wallet.mapWallet) for (const auto& entry : wallet.mapWallet)
{ {
const CWalletTx& wtx = entry.second; const CWalletTx& wtx = entry.second;
@ -325,7 +325,7 @@ std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet)
{ {
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
std::set<uint256> trusted_parents; std::set<Txid> trusted_parents;
for (const auto& walletEntry : wallet.mapWallet) for (const auto& walletEntry : wallet.mapWallet)
{ {
const CWalletTx& wtx = walletEntry.second; const CWalletTx& wtx = walletEntry.second;
@ -348,7 +348,7 @@ std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet)
if(!ExtractDestination(output.scriptPubKey, addr)) if(!ExtractDestination(output.scriptPubKey, addr))
continue; continue;
CAmount n = wallet.IsSpent(COutPoint(Txid::FromUint256(walletEntry.first), i)) ? 0 : output.nValue; CAmount n = wallet.IsSpent(COutPoint(walletEntry.first, i)) ? 0 : output.nValue;
balances[addr] += n; balances[addr] += n;
} }
} }

View file

@ -45,7 +45,7 @@ void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
CAmount& nFee, const isminefilter& filter, CAmount& nFee, const isminefilter& filter,
bool include_change); bool include_change);
bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter); bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter);
bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<uint256>& trusted_parents) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<Txid>& trusted_parents) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx); bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx);
struct Balance { struct Balance {

View file

@ -337,7 +337,7 @@ RPCHelpMan importprunedfunds()
if (!DecodeHexTx(tx, request.params[0].get_str())) { if (!DecodeHexTx(tx, request.params[0].get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
} }
uint256 hashTx = tx.GetHash(); Txid hashTx = tx.GetHash();
DataStream ssMB{ParseHexV(request.params[1], "proof")}; DataStream ssMB{ParseHexV(request.params[1], "proof")};
CMerkleBlock merkleBlock; CMerkleBlock merkleBlock;
@ -357,7 +357,7 @@ RPCHelpMan importprunedfunds()
} }
std::vector<uint256>::const_iterator it; std::vector<uint256>::const_iterator it;
if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx)) == vMatch.end()) { if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx.ToUint256())) == vMatch.end()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof");
} }
@ -394,8 +394,8 @@ RPCHelpMan removeprunedfunds()
LOCK(pwallet->cs_wallet); LOCK(pwallet->cs_wallet);
uint256 hash(ParseHashV(request.params[0], "txid")); Txid hash = Txid::FromUint256((ParseHashV(request.params[0], "txid")));
std::vector<uint256> vHash; std::vector<Txid> vHash;
vHash.push_back(hash); vHash.push_back(hash);
if (auto res = pwallet->RemoveTxs(vHash); !res) { if (auto res = pwallet->RemoveTxs(vHash); !res) {
throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original); throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);

View file

@ -56,7 +56,7 @@ static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool b
// Tally // Tally
CAmount amount = 0; CAmount amount = 0;
for (const std::pair<const uint256, CWalletTx>& wtx_pair : wallet.mapWallet) { for (const std::pair<const Txid, CWalletTx>& wtx_pair : wallet.mapWallet) {
const CWalletTx& wtx = wtx_pair.second; const CWalletTx& wtx = wtx_pair.second;
int depth{wallet.GetTxDepthInMainChain(wtx)}; int depth{wallet.GetTxDepthInMainChain(wtx)};
if (depth < min_depth if (depth < min_depth

View file

@ -1068,7 +1068,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead."); throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.");
} }
uint256 hash(ParseHashV(request.params[0], "txid")); Txid hash = Txid::FromUint256((ParseHashV(request.params[0], "txid")));
CCoinControl coin_control; CCoinControl coin_control;
coin_control.fAllowWatchOnly = pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); coin_control.fAllowWatchOnly = pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
@ -1166,7 +1166,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction."); throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
} }
uint256 txid; Txid txid;
if (feebumper::CommitTransaction(*pwallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) { if (feebumper::CommitTransaction(*pwallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
throw JSONRPCError(RPC_WALLET_ERROR, errors[0].original); throw JSONRPCError(RPC_WALLET_ERROR, errors[0].original);
} }

View file

@ -7,6 +7,7 @@
#include <policy/rbf.h> #include <policy/rbf.h>
#include <rpc/util.h> #include <rpc/util.h>
#include <rpc/blockchain.h> #include <rpc/blockchain.h>
#include <util/transaction_identifier.h>
#include <util/vector.h> #include <util/vector.h>
#include <wallet/receive.h> #include <wallet/receive.h>
#include <wallet/rpc/util.h> #include <wallet/rpc/util.h>
@ -34,11 +35,11 @@ static void WalletTxToJSON(const CWallet& wallet, const CWalletTx& wtx, UniValue
} else { } else {
entry.pushKV("trusted", CachedTxIsTrusted(wallet, wtx)); entry.pushKV("trusted", CachedTxIsTrusted(wallet, wtx));
} }
uint256 hash = wtx.GetHash(); Txid hash = wtx.GetHash();
entry.pushKV("txid", hash.GetHex()); entry.pushKV("txid", hash.GetHex());
entry.pushKV("wtxid", wtx.GetWitnessHash().GetHex()); entry.pushKV("wtxid", wtx.GetWitnessHash().GetHex());
UniValue conflicts(UniValue::VARR); UniValue conflicts(UniValue::VARR);
for (const uint256& conflict : wallet.GetTxConflicts(wtx)) for (const Txid& conflict : wallet.GetTxConflicts(wtx))
conflicts.push_back(conflict.GetHex()); conflicts.push_back(conflict.GetHex());
entry.pushKV("walletconflicts", std::move(conflicts)); entry.pushKV("walletconflicts", std::move(conflicts));
UniValue mempool_conflicts(UniValue::VARR); UniValue mempool_conflicts(UniValue::VARR);
@ -67,7 +68,7 @@ struct tallyitem
{ {
CAmount nAmount{0}; CAmount nAmount{0};
int nConf{std::numeric_limits<int>::max()}; int nConf{std::numeric_limits<int>::max()};
std::vector<uint256> txids; std::vector<Txid> txids;
bool fIsWatchonly{false}; bool fIsWatchonly{false};
tallyitem() = default; tallyitem() = default;
}; };
@ -100,7 +101,7 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons
// Tally // Tally
std::map<CTxDestination, tallyitem> mapTally; std::map<CTxDestination, tallyitem> mapTally;
for (const std::pair<const uint256, CWalletTx>& pairWtx : wallet.mapWallet) { for (const std::pair<const Txid, CWalletTx>& pairWtx : wallet.mapWallet) {
const CWalletTx& wtx = pairWtx.second; const CWalletTx& wtx = pairWtx.second;
int nDepth = wallet.GetTxDepthInMainChain(wtx); int nDepth = wallet.GetTxDepthInMainChain(wtx);
@ -169,7 +170,7 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons
obj.pushKV("label", label); obj.pushKV("label", label);
UniValue transactions(UniValue::VARR); UniValue transactions(UniValue::VARR);
if (it != mapTally.end()) { if (it != mapTally.end()) {
for (const uint256& _item : (*it).second.txids) { for (const Txid& _item : (*it).second.txids) {
transactions.push_back(_item.GetHex()); transactions.push_back(_item.GetHex());
} }
} }
@ -650,7 +651,7 @@ RPCHelpMan listsinceblock()
UniValue transactions(UniValue::VARR); UniValue transactions(UniValue::VARR);
for (const std::pair<const uint256, CWalletTx>& pairWtx : wallet.mapWallet) { for (const std::pair<const Txid, CWalletTx>& pairWtx : wallet.mapWallet) {
const CWalletTx& tx = pairWtx.second; const CWalletTx& tx = pairWtx.second;
if (depth == -1 || abs(wallet.GetTxDepthInMainChain(tx)) < depth) { if (depth == -1 || abs(wallet.GetTxDepthInMainChain(tx)) < depth) {
@ -760,7 +761,7 @@ RPCHelpMan gettransaction()
LOCK(pwallet->cs_wallet); LOCK(pwallet->cs_wallet);
uint256 hash(ParseHashV(request.params[0], "txid")); Txid hash = Txid::FromUint256((ParseHashV(request.params[0], "txid")));
isminefilter filter = ISMINE_SPENDABLE; isminefilter filter = ISMINE_SPENDABLE;
@ -833,7 +834,7 @@ RPCHelpMan abandontransaction()
LOCK(pwallet->cs_wallet); LOCK(pwallet->cs_wallet);
uint256 hash(ParseHashV(request.params[0], "txid")); Txid hash = Txid::FromUint256((ParseHashV(request.params[0], "txid")));
if (!pwallet->mapWallet.count(hash)) { if (!pwallet->mapWallet.count(hash)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");

View file

@ -328,10 +328,10 @@ CoinsResult AvailableCoins(const CWallet& wallet,
const bool can_grind_r = wallet.CanGrindR(); const bool can_grind_r = wallet.CanGrindR();
std::vector<COutPoint> outpoints; std::vector<COutPoint> outpoints;
std::set<uint256> trusted_parents; std::set<Txid> trusted_parents;
for (const auto& entry : wallet.mapWallet) for (const auto& entry : wallet.mapWallet)
{ {
const uint256& txid = entry.first; const Txid& txid = entry.first;
const CWalletTx& wtx = entry.second; const CWalletTx& wtx = entry.second;
if (wallet.IsTxImmatureCoinBase(wtx) && !params.include_immature_coinbase) if (wallet.IsTxImmatureCoinBase(wtx) && !params.include_immature_coinbase)
@ -391,7 +391,7 @@ CoinsResult AvailableCoins(const CWallet& wallet,
for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) { for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
const CTxOut& output = wtx.tx->vout[i]; const CTxOut& output = wtx.tx->vout[i];
const COutPoint outpoint(Txid::FromUint256(txid), i); const COutPoint outpoint(txid, i);
if (output.nValue < params.min_amount || output.nValue > params.max_amount) if (output.nValue < params.min_amount || output.nValue > params.max_amount)
continue; continue;

View file

@ -80,7 +80,7 @@ static void add_coin(CoinsResult& available_coins, CWallet& wallet, const CAmoun
if (spendable) { if (spendable) {
tx.vout[nInput].scriptPubKey = GetScriptForDestination(*Assert(wallet.GetNewDestination(OutputType::BECH32, ""))); tx.vout[nInput].scriptPubKey = GetScriptForDestination(*Assert(wallet.GetNewDestination(OutputType::BECH32, "")));
} }
uint256 txid = tx.GetHash(); Txid txid = tx.GetHash();
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
auto ret = wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(txid), std::forward_as_tuple(MakeTransactionRef(std::move(tx)), TxStateInactive{})); auto ret = wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(txid), std::forward_as_tuple(MakeTransactionRef(std::move(tx)), TxStateInactive{}));

View file

@ -40,7 +40,7 @@ static void addCoin(CoinsResult& coins,
tx.vout[0].nValue = nValue; tx.vout[0].nValue = nValue;
tx.vout[0].scriptPubKey = GetScriptForDestination(dest); tx.vout[0].scriptPubKey = GetScriptForDestination(dest);
const auto txid{tx.GetHash().ToUint256()}; const auto txid{tx.GetHash()};
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
auto ret = wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(txid), std::forward_as_tuple(MakeTransactionRef(std::move(tx)), TxStateInactive{})); auto ret = wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(txid), std::forward_as_tuple(MakeTransactionRef(std::move(tx)), TxStateInactive{}));
assert(ret.second); assert(ret.second);

View file

@ -726,7 +726,7 @@ BOOST_FIXTURE_TEST_CASE(RemoveTxs, TestChain100Setup)
BOOST_CHECK(wallet->HasWalletSpend(prev_tx)); BOOST_CHECK(wallet->HasWalletSpend(prev_tx));
BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_hash), 1u); BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_hash), 1u);
std::vector<uint256> vHashIn{ block_hash }; std::vector<Txid> vHashIn{ block_hash };
BOOST_CHECK(wallet->RemoveTxs(vHashIn)); BOOST_CHECK(wallet->RemoveTxs(vHashIn));
BOOST_CHECK(!wallet->HasWalletSpend(prev_tx)); BOOST_CHECK(!wallet->HasWalletSpend(prev_tx));
@ -776,7 +776,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
{ {
// Verify balance update for the new tx and the old one // Verify balance update for the new tx and the old one
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
const CWalletTx* new_wtx = wallet.GetWalletTx(good_tx_id.ToUint256()); const CWalletTx* new_wtx = wallet.GetWalletTx(good_tx_id);
BOOST_CHECK_EQUAL(CachedTxGetAvailableCredit(wallet, *new_wtx), 1 * COIN); BOOST_CHECK_EQUAL(CachedTxGetAvailableCredit(wallet, *new_wtx), 1 * COIN);
// Now the old wtx // Now the old wtx

View file

@ -539,7 +539,7 @@ std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& b
* @{ * @{
*/ */
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const const CWalletTx* CWallet::GetWalletTx(const Txid& hash) const
{ {
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
const auto it = mapWallet.find(hash); const auto it = mapWallet.find(hash);
@ -676,9 +676,9 @@ void CWallet::SetMinVersion(enum WalletFeature nVersion, WalletBatch* batch_in)
} }
} }
std::set<uint256> CWallet::GetConflicts(const uint256& txid) const std::set<Txid> CWallet::GetConflicts(const Txid& txid) const
{ {
std::set<uint256> result; std::set<Txid> result;
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
const auto it = mapWallet.find(txid); const auto it = mapWallet.find(txid);
@ -744,7 +744,7 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran
// Now copy data from copyFrom to rest: // Now copy data from copyFrom to rest:
for (TxSpends::iterator it = range.first; it != range.second; ++it) for (TxSpends::iterator it = range.first; it != range.second; ++it)
{ {
const uint256& hash = it->second; const Txid& hash = it->second;
CWalletTx* copyTo = &mapWallet.at(hash); CWalletTx* copyTo = &mapWallet.at(hash);
if (copyFrom == copyTo) continue; if (copyFrom == copyTo) continue;
assert(copyFrom && "Oldest wallet transaction in range assumed to have been found."); assert(copyFrom && "Oldest wallet transaction in range assumed to have been found.");
@ -770,7 +770,7 @@ bool CWallet::IsSpent(const COutPoint& outpoint) const
range = mapTxSpends.equal_range(outpoint); range = mapTxSpends.equal_range(outpoint);
for (TxSpends::const_iterator it = range.first; it != range.second; ++it) { for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
const uint256& wtxid = it->second; const Txid& wtxid = it->second;
const auto mit = mapWallet.find(wtxid); const auto mit = mapWallet.find(wtxid);
if (mit != mapWallet.end()) { if (mit != mapWallet.end()) {
const auto& wtx = mit->second; const auto& wtx = mit->second;
@ -781,7 +781,7 @@ bool CWallet::IsSpent(const COutPoint& outpoint) const
return false; return false;
} }
void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid, WalletBatch* batch) void CWallet::AddToSpends(const COutPoint& outpoint, const Txid& wtxid, WalletBatch* batch)
{ {
mapTxSpends.insert(std::make_pair(outpoint, wtxid)); mapTxSpends.insert(std::make_pair(outpoint, wtxid));
@ -983,12 +983,12 @@ void CWallet::MarkDirty()
{ {
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
for (std::pair<const uint256, CWalletTx>& item : mapWallet) for (std::pair<const Txid, CWalletTx>& item : mapWallet)
item.second.MarkDirty(); item.second.MarkDirty();
} }
} }
bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash) bool CWallet::MarkReplaced(const Txid& originalHash, const Txid& newHash)
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
@ -1020,7 +1020,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
return success; return success;
} }
void CWallet::SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations) void CWallet::SetSpentKeyState(WalletBatch& batch, const Txid& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations)
{ {
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
const CWalletTx* srctx = GetWalletTx(hash); const CWalletTx* srctx = GetWalletTx(hash);
@ -1075,7 +1075,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
WalletBatch batch(GetDatabase(), fFlushOnClose); WalletBatch batch(GetDatabase(), fFlushOnClose);
uint256 hash = tx->GetHash(); Txid hash = tx->GetHash();
if (IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) { if (IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
// Mark used destinations // Mark used destinations
@ -1197,7 +1197,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
return &wtx; return &wtx;
} }
bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) bool CWallet::LoadToWallet(const Txid& hash, const UpdateWalletTxFn& fill_wtx)
{ {
const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(nullptr, TxStateInactive{})); const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(nullptr, TxStateInactive{}));
CWalletTx& wtx = ins.first->second; CWalletTx& wtx = ins.first->second;
@ -1295,7 +1295,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxS
return false; return false;
} }
bool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const bool CWallet::TransactionCanBeAbandoned(const Txid& hashTx) const
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
const CWalletTx* wtx = GetWalletTx(hashTx); const CWalletTx* wtx = GetWalletTx(hashTx);
@ -1312,7 +1312,7 @@ void CWallet::MarkInputsDirty(const CTransactionRef& tx)
} }
} }
bool CWallet::AbandonTransaction(const uint256& hashTx) bool CWallet::AbandonTransaction(const Txid& hashTx)
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
auto it = mapWallet.find(hashTx); auto it = mapWallet.find(hashTx);
@ -1350,7 +1350,7 @@ bool CWallet::AbandonTransaction(CWalletTx& tx)
return true; return true;
} }
void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, const uint256& hashTx) void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, const Txid& hashTx)
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
@ -1380,20 +1380,20 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
} }
void CWallet::RecursiveUpdateTxState(const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) { void CWallet::RecursiveUpdateTxState(const Txid& tx_hash, const TryUpdatingStateFn& try_updating_state) {
// Do not flush the wallet here for performance reasons // Do not flush the wallet here for performance reasons
WalletBatch batch(GetDatabase(), false); WalletBatch batch(GetDatabase(), false);
RecursiveUpdateTxState(&batch, tx_hash, try_updating_state); RecursiveUpdateTxState(&batch, tx_hash, try_updating_state);
} }
void CWallet::RecursiveUpdateTxState(WalletBatch* batch, const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) { void CWallet::RecursiveUpdateTxState(WalletBatch* batch, const Txid& tx_hash, const TryUpdatingStateFn& try_updating_state) {
std::set<uint256> todo; std::set<Txid> todo;
std::set<uint256> done; std::set<Txid> done;
todo.insert(tx_hash); todo.insert(tx_hash);
while (!todo.empty()) { while (!todo.empty()) {
uint256 now = *todo.begin(); Txid now = *todo.begin();
todo.erase(now); todo.erase(now);
done.insert(now); done.insert(now);
auto it = mapWallet.find(now); auto it = mapWallet.find(now);
@ -1406,7 +1406,7 @@ void CWallet::RecursiveUpdateTxState(WalletBatch* batch, const uint256& tx_hash,
if (batch) batch->WriteTx(wtx); if (batch) batch->WriteTx(wtx);
// Iterate over all its outputs, and update those tx states as well (if applicable) // Iterate over all its outputs, and update those tx states as well (if applicable)
for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) { for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(COutPoint(Txid::FromUint256(now), i)); std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(COutPoint(now, i));
for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) { for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
if (!done.count(iter->second)) { if (!done.count(iter->second)) {
todo.insert(iter->second); todo.insert(iter->second);
@ -1450,7 +1450,7 @@ void CWallet::transactionAddedToMempool(const CTransactionRef& tx) {
for (const CTxIn& tx_in : tx->vin) { for (const CTxIn& tx_in : tx->vin) {
// For each wallet transaction spending this prevout.. // For each wallet transaction spending this prevout..
for (auto range = mapTxSpends.equal_range(tx_in.prevout); range.first != range.second; range.first++) { for (auto range = mapTxSpends.equal_range(tx_in.prevout); range.first != range.second; range.first++) {
const uint256& spent_id = range.first->second; const Txid& spent_id = range.first->second;
// Skip the recently added tx // Skip the recently added tx
if (spent_id == txid) continue; if (spent_id == txid) continue;
RecursiveUpdateTxState(/*batch=*/nullptr, spent_id, [&txid](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { RecursiveUpdateTxState(/*batch=*/nullptr, spent_id, [&txid](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
@ -1503,7 +1503,7 @@ void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRe
// and recursively mark them as no longer conflicting with // and recursively mark them as no longer conflicting with
// txid // txid
for (auto range = mapTxSpends.equal_range(tx_in.prevout); range.first != range.second; range.first++) { for (auto range = mapTxSpends.equal_range(tx_in.prevout); range.first != range.second; range.first++) {
const uint256& spent_id = range.first->second; const Txid& spent_id = range.first->second;
RecursiveUpdateTxState(/*batch=*/nullptr, spent_id, [&txid](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { RecursiveUpdateTxState(/*batch=*/nullptr, spent_id, [&txid](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
return wtx.mempool_conflicts.erase(txid) ? TxUpdate::CHANGED : TxUpdate::UNCHANGED; return wtx.mempool_conflicts.erase(txid) ? TxUpdate::CHANGED : TxUpdate::UNCHANGED;
@ -2072,12 +2072,12 @@ bool CWallet::SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string
return ret; return ret;
} }
std::set<uint256> CWallet::GetTxConflicts(const CWalletTx& wtx) const std::set<Txid> CWallet::GetTxConflicts(const CWalletTx& wtx) const
{ {
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
const uint256 myHash{wtx.GetHash()}; const Txid myHash{wtx.GetHash()};
std::set<uint256> result{GetConflicts(myHash)}; std::set<Txid> result{GetConflicts(myHash)};
result.erase(myHash); result.erase(myHash);
return result; return result;
} }
@ -2228,7 +2228,7 @@ std::optional<PSBTError> CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bo
// If we have no utxo, grab it from the wallet. // If we have no utxo, grab it from the wallet.
if (!input.non_witness_utxo) { if (!input.non_witness_utxo) {
const uint256& txhash = txin.prevout.hash; const Txid& txhash = txin.prevout.hash;
const auto it = mapWallet.find(txhash); const auto it = mapWallet.find(txhash);
if (it != mapWallet.end()) { if (it != mapWallet.end()) {
const CWalletTx& wtx = it->second; const CWalletTx& wtx = it->second;
@ -2405,7 +2405,7 @@ DBErrors CWallet::LoadWallet()
return nLoadWalletRet; return nLoadWalletRet;
} }
util::Result<void> CWallet::RemoveTxs(std::vector<uint256>& txs_to_remove) util::Result<void> CWallet::RemoveTxs(std::vector<Txid>& txs_to_remove)
{ {
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
bilingual_str str_err; // future: make RunWithinTxn return a util::Result bilingual_str str_err; // future: make RunWithinTxn return a util::Result
@ -2419,16 +2419,16 @@ util::Result<void> CWallet::RemoveTxs(std::vector<uint256>& txs_to_remove)
return {}; // all good return {}; // all good
} }
util::Result<void> CWallet::RemoveTxs(WalletBatch& batch, std::vector<uint256>& txs_to_remove) util::Result<void> CWallet::RemoveTxs(WalletBatch& batch, std::vector<Txid>& txs_to_remove)
{ {
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
if (!batch.HasActiveTxn()) return util::Error{strprintf(_("The transactions removal process can only be executed within a db txn"))}; if (!batch.HasActiveTxn()) return util::Error{strprintf(_("The transactions removal process can only be executed within a db txn"))};
// Check for transaction existence and remove entries from disk // Check for transaction existence and remove entries from disk
using TxIterator = std::unordered_map<uint256, CWalletTx, SaltedTxidHasher>::const_iterator; using TxIterator = std::unordered_map<Txid, CWalletTx, SaltedTxidHasher>::const_iterator;
std::vector<TxIterator> erased_txs; std::vector<TxIterator> erased_txs;
bilingual_str str_err; bilingual_str str_err;
for (const uint256& hash : txs_to_remove) { for (const Txid& hash : txs_to_remove) {
auto it_wtx = mapWallet.find(hash); auto it_wtx = mapWallet.find(hash);
if (it_wtx == mapWallet.end()) { if (it_wtx == mapWallet.end()) {
return util::Error{strprintf(_("Transaction %s does not belong to this wallet"), hash.GetHex())}; return util::Error{strprintf(_("Transaction %s does not belong to this wallet"), hash.GetHex())};
@ -2443,7 +2443,7 @@ util::Result<void> CWallet::RemoveTxs(WalletBatch& batch, std::vector<uint256>&
batch.RegisterTxnListener({.on_commit=[&, erased_txs]() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { batch.RegisterTxnListener({.on_commit=[&, erased_txs]() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
// Update the in-memory state and notify upper layers about the removals // Update the in-memory state and notify upper layers about the removals
for (const auto& it : erased_txs) { for (const auto& it : erased_txs) {
const uint256 hash{it->first}; const Txid hash{it->first};
wtxOrdered.erase(it->second.m_it_wtxOrdered); wtxOrdered.erase(it->second.m_it_wtxOrdered);
for (const auto& txin : it->second.tx->vin) for (const auto& txin : it->second.tx->vin)
mapTxSpends.erase(txin.prevout); mapTxSpends.erase(txin.prevout);
@ -4164,7 +4164,7 @@ util::Result<void> CWallet::ApplyMigrationData(WalletBatch& local_wallet_batch,
// Check if the transactions in the wallet are still ours. Either they belong here, or they belong in the watchonly wallet. // Check if the transactions in the wallet are still ours. Either they belong here, or they belong in the watchonly wallet.
// We need to go through these in the tx insertion order so that lookups to spends works. // We need to go through these in the tx insertion order so that lookups to spends works.
std::vector<uint256> txids_to_delete; std::vector<Txid> txids_to_delete;
std::unique_ptr<WalletBatch> watchonly_batch; std::unique_ptr<WalletBatch> watchonly_batch;
if (data.watchonly_wallet) { if (data.watchonly_wallet) {
watchonly_batch = std::make_unique<WalletBatch>(data.watchonly_wallet->GetDatabase()); watchonly_batch = std::make_unique<WalletBatch>(data.watchonly_wallet->GetDatabase());
@ -4195,7 +4195,7 @@ util::Result<void> CWallet::ApplyMigrationData(WalletBatch& local_wallet_batch,
LOCK(data.watchonly_wallet->cs_wallet); LOCK(data.watchonly_wallet->cs_wallet);
if (data.watchonly_wallet->IsMine(*wtx->tx) || data.watchonly_wallet->IsFromMe(*wtx->tx)) { if (data.watchonly_wallet->IsMine(*wtx->tx) || data.watchonly_wallet->IsFromMe(*wtx->tx)) {
// Add to watchonly wallet // Add to watchonly wallet
const uint256& hash = wtx->GetHash(); const Txid& hash = wtx->GetHash();
const CWalletTx& to_copy_wtx = *wtx; const CWalletTx& to_copy_wtx = *wtx;
if (!data.watchonly_wallet->LoadToWallet(hash, [&](CWalletTx& ins_wtx, bool new_tx) EXCLUSIVE_LOCKS_REQUIRED(data.watchonly_wallet->cs_wallet) { if (!data.watchonly_wallet->LoadToWallet(hash, [&](CWalletTx& ins_wtx, bool new_tx) EXCLUSIVE_LOCKS_REQUIRED(data.watchonly_wallet->cs_wallet) {
if (!new_tx) return false; if (!new_tx) return false;

View file

@ -331,9 +331,9 @@ private:
* detect and report conflicts (double-spends or * detect and report conflicts (double-spends or
* mutated transactions where the mutant gets mined). * mutated transactions where the mutant gets mined).
*/ */
typedef std::unordered_multimap<COutPoint, uint256, SaltedOutpointHasher> TxSpends; typedef std::unordered_multimap<COutPoint, Txid, SaltedOutpointHasher> TxSpends;
TxSpends mapTxSpends GUARDED_BY(cs_wallet); TxSpends mapTxSpends GUARDED_BY(cs_wallet);
void AddToSpends(const COutPoint& outpoint, const uint256& wtxid, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void AddToSpends(const COutPoint& outpoint, const Txid& wtxid, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void AddToSpends(const CWalletTx& wtx, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void AddToSpends(const CWalletTx& wtx, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** /**
@ -355,15 +355,15 @@ private:
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const SyncTxState& state, bool fUpdate, bool rescanning_old_block) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const SyncTxState& state, bool fUpdate, bool rescanning_old_block) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */ /** Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */
void MarkConflicted(const uint256& hashBlock, int conflicting_height, const uint256& hashTx); void MarkConflicted(const uint256& hashBlock, int conflicting_height, const Txid& hashTx);
enum class TxUpdate { UNCHANGED, CHANGED, NOTIFY_CHANGED }; enum class TxUpdate { UNCHANGED, CHANGED, NOTIFY_CHANGED };
using TryUpdatingStateFn = std::function<TxUpdate(CWalletTx& wtx)>; using TryUpdatingStateFn = std::function<TxUpdate(CWalletTx& wtx)>;
/** Mark a transaction (and its in-wallet descendants) as a particular tx state. */ /** Mark a transaction (and its in-wallet descendants) as a particular tx state. */
void RecursiveUpdateTxState(const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void RecursiveUpdateTxState(const Txid& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void RecursiveUpdateTxState(WalletBatch* batch, const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void RecursiveUpdateTxState(WalletBatch* batch, const Txid& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed */ /** Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed */
void MarkInputsDirty(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void MarkInputsDirty(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@ -481,7 +481,7 @@ public:
/** Map from txid to CWalletTx for all transactions this wallet is /** Map from txid to CWalletTx for all transactions this wallet is
* interested in, including received and sent transactions. */ * interested in, including received and sent transactions. */
std::unordered_map<uint256, CWalletTx, SaltedTxidHasher> mapWallet GUARDED_BY(cs_wallet); std::unordered_map<Txid, CWalletTx, SaltedTxidHasher> mapWallet GUARDED_BY(cs_wallet);
typedef std::multimap<int64_t, CWalletTx*> TxItems; typedef std::multimap<int64_t, CWalletTx*> TxItems;
TxItems wtxOrdered; TxItems wtxOrdered;
@ -503,9 +503,9 @@ public:
/** Interface for accessing chain state. */ /** Interface for accessing chain state. */
interfaces::Chain& chain() const { assert(m_chain); return *m_chain; } interfaces::Chain& chain() const { assert(m_chain); return *m_chain; }
const CWalletTx* GetWalletTx(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); const CWalletTx* GetWalletTx(const Txid& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
std::set<uint256> GetTxConflicts(const CWalletTx& wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); std::set<Txid> GetTxConflicts(const CWalletTx& wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** /**
* Return depth of transaction in blockchain: * Return depth of transaction in blockchain:
@ -537,7 +537,7 @@ public:
// Whether this or any known scriptPubKey with the same single key has been spent. // Whether this or any known scriptPubKey with the same single key has been spent.
bool IsSpentKey(const CScript& scriptPubKey) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool IsSpentKey(const CScript& scriptPubKey) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void SetSpentKeyState(WalletBatch& batch, const Txid& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** Display address on an external signer. */ /** Display address on an external signer. */
util::Result<void> DisplayAddress(const CTxDestination& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); util::Result<void> DisplayAddress(const CTxDestination& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@ -608,7 +608,7 @@ public:
* @return the recently added wtx pointer or nullptr if there was a db write error. * @return the recently added wtx pointer or nullptr if there was a db write error.
*/ */
CWalletTx* AddToWallet(CTransactionRef tx, const TxState& state, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true, bool rescanning_old_block = false); CWalletTx* AddToWallet(CTransactionRef tx, const TxState& state, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true, bool rescanning_old_block = false);
bool LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool LoadToWallet(const Txid& hash, const UpdateWalletTxFn& fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void transactionAddedToMempool(const CTransactionRef& tx) override; void transactionAddedToMempool(const CTransactionRef& tx) override;
void blockConnected(ChainstateRole role, const interfaces::BlockInfo& block) override; void blockConnected(ChainstateRole role, const interfaces::BlockInfo& block) override;
void blockDisconnected(const interfaces::BlockInfo& block) override; void blockDisconnected(const interfaces::BlockInfo& block) override;
@ -793,8 +793,8 @@ public:
DBErrors LoadWallet(); DBErrors LoadWallet();
/** Erases the provided transactions from the wallet. */ /** Erases the provided transactions from the wallet. */
util::Result<void> RemoveTxs(std::vector<uint256>& txs_to_remove) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); util::Result<void> RemoveTxs(std::vector<Txid>& txs_to_remove) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
util::Result<void> RemoveTxs(WalletBatch& batch, std::vector<uint256>& txs_to_remove) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); util::Result<void> RemoveTxs(WalletBatch& batch, std::vector<Txid>& txs_to_remove) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& purpose); bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& purpose);
@ -817,7 +817,7 @@ public:
int GetVersion() const { LOCK(cs_wallet); return nWalletVersion; } int GetVersion() const { LOCK(cs_wallet); return nWalletVersion; }
//! Get wallet transactions that conflict with given transaction (spend same outputs) //! Get wallet transactions that conflict with given transaction (spend same outputs)
std::set<uint256> GetConflicts(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); std::set<Txid> GetConflicts(const Txid& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Check if a given transaction has any of its outputs spent by another transaction in the wallet //! Check if a given transaction has any of its outputs spent by another transaction in the wallet
bool HasWalletSpend(const CTransactionRef& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool HasWalletSpend(const CTransactionRef& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@ -844,7 +844,7 @@ public:
* Wallet transaction added, removed or updated. * Wallet transaction added, removed or updated.
* @note called with lock cs_wallet held. * @note called with lock cs_wallet held.
*/ */
boost::signals2::signal<void(const uint256& hashTx, ChangeType status)> NotifyTransactionChanged; boost::signals2::signal<void(const Txid& hashTx, ChangeType status)> NotifyTransactionChanged;
/** Show progress e.g. for rescan */ /** Show progress e.g. for rescan */
boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress; boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress;
@ -867,14 +867,14 @@ public:
void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; } void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; }
/** Return whether transaction can be abandoned */ /** Return whether transaction can be abandoned */
bool TransactionCanBeAbandoned(const uint256& hashTx) const; bool TransactionCanBeAbandoned(const Txid& hashTx) const;
/* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */ /* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
bool AbandonTransaction(const uint256& hashTx); bool AbandonTransaction(const Txid& hashTx);
bool AbandonTransaction(CWalletTx& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool AbandonTransaction(CWalletTx& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** Mark a transaction as replaced by another transaction. */ /** Mark a transaction as replaced by another transaction. */
bool MarkReplaced(const uint256& originalHash, const uint256& newHash); bool MarkReplaced(const Txid& originalHash, const Txid& newHash);
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */ /* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
static std::shared_ptr<CWallet> Create(WalletContext& context, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings); static std::shared_ptr<CWallet> Create(WalletContext& context, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings);

View file

@ -16,6 +16,7 @@
#include <util/bip32.h> #include <util/bip32.h>
#include <util/check.h> #include <util/check.h>
#include <util/fs.h> #include <util/fs.h>
#include <util/transaction_identifier.h>
#include <util/time.h> #include <util/time.h>
#include <util/translation.h> #include <util/translation.h>
#ifdef USE_BDB #ifdef USE_BDB
@ -96,9 +97,9 @@ bool WalletBatch::WriteTx(const CWalletTx& wtx)
return WriteIC(std::make_pair(DBKeys::TX, wtx.GetHash()), wtx); return WriteIC(std::make_pair(DBKeys::TX, wtx.GetHash()), wtx);
} }
bool WalletBatch::EraseTx(uint256 hash) bool WalletBatch::EraseTx(Txid hash)
{ {
return EraseIC(std::make_pair(DBKeys::TX, hash)); return EraseIC(std::make_pair(DBKeys::TX, hash.ToUint256()));
} }
bool WalletBatch::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite) bool WalletBatch::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite)
@ -1048,7 +1049,7 @@ static DBErrors LoadAddressBookRecords(CWallet* pwallet, DatabaseBatch& batch) E
return result; return result;
} }
static DBErrors LoadTxRecords(CWallet* pwallet, DatabaseBatch& batch, std::vector<uint256>& upgraded_txs, bool& any_unordered) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) static DBErrors LoadTxRecords(CWallet* pwallet, DatabaseBatch& batch, std::vector<Txid>& upgraded_txs, bool& any_unordered) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{ {
AssertLockHeld(pwallet->cs_wallet); AssertLockHeld(pwallet->cs_wallet);
DBErrors result = DBErrors::LOAD_OK; DBErrors result = DBErrors::LOAD_OK;
@ -1058,7 +1059,7 @@ static DBErrors LoadTxRecords(CWallet* pwallet, DatabaseBatch& batch, std::vecto
LoadResult tx_res = LoadRecords(pwallet, batch, DBKeys::TX, LoadResult tx_res = LoadRecords(pwallet, batch, DBKeys::TX,
[&any_unordered, &upgraded_txs] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) { [&any_unordered, &upgraded_txs] (CWallet* pwallet, DataStream& key, DataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
DBErrors result = DBErrors::LOAD_OK; DBErrors result = DBErrors::LOAD_OK;
uint256 hash; Txid hash;
key >> hash; key >> hash;
// LoadToWallet call below creates a new CWalletTx that fill_wtx // LoadToWallet call below creates a new CWalletTx that fill_wtx
// callback fills with transaction metadata. // callback fills with transaction metadata.
@ -1192,7 +1193,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
{ {
DBErrors result = DBErrors::LOAD_OK; DBErrors result = DBErrors::LOAD_OK;
bool any_unordered = false; bool any_unordered = false;
std::vector<uint256> upgraded_txs; std::vector<Txid> upgraded_txs;
LOCK(pwallet->cs_wallet); LOCK(pwallet->cs_wallet);
@ -1247,7 +1248,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
if (result != DBErrors::LOAD_OK) if (result != DBErrors::LOAD_OK)
return result; return result;
for (const uint256& hash : upgraded_txs) for (const Txid& hash : upgraded_txs)
WriteTx(pwallet->mapWallet.at(hash)); WriteTx(pwallet->mapWallet.at(hash));
if (!has_last_client || last_client != CLIENT_VERSION) // Update if (!has_last_client || last_client != CLIENT_VERSION) // Update

View file

@ -238,7 +238,7 @@ public:
bool ErasePurpose(const std::string& strAddress); bool ErasePurpose(const std::string& strAddress);
bool WriteTx(const CWalletTx& wtx); bool WriteTx(const CWalletTx& wtx);
bool EraseTx(uint256 hash); bool EraseTx(Txid hash);
bool WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite); bool WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite);
bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta); bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta);

View file

@ -230,7 +230,7 @@ bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction) 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); LogDebug(BCLog::ZMQ, "Publish hashtx %s to %s\n", hash.GetHex(), this->address);
uint8_t data[32]; uint8_t data[32];
for (unsigned int i = 0; i < 32; i++) { for (unsigned int i = 0; i < 32; i++) {
@ -254,7 +254,7 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction) 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); LogDebug(BCLog::ZMQ, "Publish rawtx %s to %s\n", hash.GetHex(), this->address);
DataStream ss; DataStream ss;
ss << TX_WITH_WITNESS(transaction); 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) 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); 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); return SendSequenceMsg(*this, hash, /* Mempool (A)cceptance */ 'A', mempool_sequence);
} }
bool CZMQPublishSequenceNotifier::NotifyTransactionRemoval(const CTransaction &transaction, uint64_t 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); 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); return SendSequenceMsg(*this, hash, /* Mempool (R)emoval */ 'R', mempool_sequence);
} }