tx_pool: notify txpool event when stem bumps to fluff
What changed, and why it matters
This small Monero patch fixes a notification bug in the transaction pool. When a privacy-protecting 'stem' transaction is later re-broadcast as a normal 'fluff' transaction, the code now correctly reports the updated relay method to external listeners (such as the ZMQ event stream). Previously, the notification used the original relay method, which could mislead external tools about how the transaction was actually being relayed. There is no direct evidence this enables theft or remote code execution, but it could confuse monitoring systems or weaken privacy-related analytics.
Apply the patch. Review any external tools or monitoring that consume ZMQ txpool events to ensure they handle stem-to-fluff transitions correctly. Consider whether the previous behavior could have caused missed or duplicated events in production deployments.
Security signals we found
Incorrect event notification based on stale relay method
Privacy-relevant metadata (stem vs fluff) not propagated to listeners
Possible missed txpool event for stem-to-fluff transitions
Evidence from the diff
The change moves the assignment tvc.m_relay = tx_relay outside the if (tvc.m_added_to_pool) block in tx_pool.cpp, so the transaction verification context always reflects the requested relay method when the fee is non-zero and the method is not forward. In cryptonote_core.cpp, the ZMQ txpool event is now triggered based on tvc.m_relay rather than the input tx_relay. This ensures that a transaction which was already in the pool but is being bumped from stem to fluff emits a legacy txpool event, keeping external subscribers informed of the actual relay state.
Changed components
src/cryptonote_core/tx_pool.cppsrc/cryptonote_core/cryptonote_core.cppZMQ txpool event notificationInspect captured patch +5 / −5
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 2fb2a1a..a22edca 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -1146,7 +1146,7 @@ namespace cryptonote
const bool res = m_mempool.add_tx(tx, tx_hash, blob, tx_weight, tvc, tx_relay, relayed, version);
// If new incoming tx passed verification and entered the pool, notify ZMQ
- if (!tvc.m_verifivation_failed && res && matches_category(tx_relay, relay_category::legacy))
+ if (!tvc.m_verifivation_failed && res && matches_category(tvc.m_relay, relay_category::legacy))
{
m_blockchain_storage.notify_txpool_event({txpool_event{
.tx = tx,
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 1890ef9..94ce764 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -339,16 +339,16 @@ namespace cryptonote
MERROR("internal error: error adding transaction to txpool: " << e.what());
return false;
}
-
- static_assert(unsigned(relay_method::none) == 0, "expected relay_method::none value to be zero");
- if(meta.fee > 0 && tx_relay != relay_method::forward)
- tvc.m_relay = tx_relay;
}
tvc.m_verifivation_failed = false;
if (tvc.m_added_to_pool)
m_txpool_weight += tx_weight;
+ static_assert(unsigned(relay_method::none) == 0, "expected relay_method::none value to be zero");
+ if (meta.fee > 0 && tx_relay != relay_method::forward)
+ tvc.m_relay = tx_relay;
+
++m_cookie;
MINFO("Transaction added to pool: txid " << id << " weight: " << tx_weight << " fee/byte: " << (fee / (double)(tx_weight ? tx_weight : 1)) << ", count: " << m_added_txs_by_id.size());
Why this scored 25/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.