Daemon: relay empty fluffy block on found block
What changed, and why it matters
This commit changes how a Monero node announces a newly found block to peers. Previously, the node would fetch and attach the actual transaction data to the announcement. After the change, it sends an 'empty fluffy block' announcement that contains only the block header and a list of transaction hashes, leaving peers to request missing transactions themselves. This is a network-efficiency optimization, but it removes a local consistency check and shifts responsibility for transaction availability to peers.
Review whether the remaining have_tx() loop and the removed size assertion are sufficient to prevent a miner from relaying a block it cannot fully validate. Consider adding a check that the node actually has all transactions referenced by the block before relaying, or ensure that fluffy-block handling on peers robustly falls back to requesting the full block when transactions are missing.
Security signals we found
Removal of local transaction presence assertion before relay
Change from full-block relay to empty fluffy-block relay on newly found blocks
Reduced local validation/availability guarantee propagated to the network
Potential for a mining node to announce a block whose transactions it does not itself possess
Evidence from the diff
The patch modifies the block-relay path in cryptonote_core.cpp. It replaces a call to get_transactions_blobs() (which populated txs and missed_txs) with a simple have_tx() loop that only records missing hashes. It then removes the assertion that the number of fetched transactions matches the number in the block, and clears arg.b.txs before relaying. The result is that a node that has just mined a block will relay a fluffy block containing no transactions, relying on the peer-to-peer transaction pool synchronization to supply the actual transactions.
Changed components
src/cryptonote_core/cryptonote_core.cppMonero daemon block relay / fluffy block propagationP2P new-block notification (NOTIFY_NEW_FLUFFY_BLOCK)Inspect captured patch +10 / −7
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 42fdc25..e636014 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -1312,20 +1312,23 @@ namespace cryptonote
NOTIFY_NEW_FLUFFY_BLOCK::request arg{};
arg.current_blockchain_height = m_blockchain_storage.get_current_blockchain_height();
std::vector<crypto::hash> missed_txs;
- std::vector<cryptonote::blobdata> txs;
- m_blockchain_storage.get_transactions_blobs(b.tx_hashes, txs, missed_txs);
+ for (const auto &tx_hash : b.tx_hashes)
+ {
+ if (m_blockchain_storage.have_tx(tx_hash))
+ continue;
+ missed_txs.push_back(tx_hash);
+ }
if(missed_txs.size() && m_blockchain_storage.get_block_id_by_height(get_block_height(b)) != get_block_hash(b))
{
LOG_PRINT_L1("Block found but, seems that reorganize just happened after that, do not relay this block");
return true;
}
- CHECK_AND_ASSERT_MES(txs.size() == b.tx_hashes.size() && !missed_txs.size(), false, "can't find some transactions in found block:" << get_block_hash(b) << " txs.size()=" << txs.size()
- << ", b.tx_hashes.size()=" << b.tx_hashes.size() << ", missed_txs.size()" << missed_txs.size());
+ CHECK_AND_ASSERT_MES(!missed_txs.size(), false, "can't find some transactions in found block:" << get_block_hash(b)
+ << " b.tx_hashes.size()=" << b.tx_hashes.size() << ", missed_txs.size()" << missed_txs.size());
block_to_blob(b, arg.b.block);
- //pack transactions
- for(auto& tx: txs)
- arg.b.txs.push_back({tx, crypto::null_hash});
+ // Relay an empty fluffy block
+ arg.b.txs.clear();
m_pprotocol->relay_block(arg, exclude_context);
}
Why this scored 44/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.