aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Chow <github@achow101.com>2023-08-31 12:47:13 -0400
committerAndrew Chow <github@achow101.com>2023-08-31 12:55:38 -0400
commit5666966dffeb620b4a628679d667346e02fd3b19 (patch)
treeb81da8a23eef8d6811dc434dc54f01a59fba06ee
parenta4e0bcb6c9a8db5a74c74c5cddbb065ba9182482 (diff)
parenta3b55c94b9ffde07386aa887149ddca91b364967 (diff)
Merge bitcoin/bitcoin#28364: log: log wtxids when possible, add TXPACKAGES category
a3b55c94b9ffde07386aa887149ddca91b364967 [doc] move comment about AlreadyHaveTx DoS score to the right place (glozow) 3b8c17838a561616fd7c933753c7b98b6c6c7c99 [log] add more logs related to orphan handling (glozow) 51b3275cd1de467933f13d8b71286bf5ebd12b4b [log] add category TXPACKAGES for orphanage and package relay (glozow) a33dde1e41d8923a46db84b50550175fa6149c48 [log] include wtxid in tx {relay,validation,orphanage} logging (glozow) Pull request description: This was taken from #28031 (see #27463 for project tracking). - Log wtxids in addition to txids when possible. This allows us to track the fate of a transaction from inv to mempool accept/reject through logs. - Additional orphan-related logging to make testing and debugging easier. Suggested in https://github.com/bitcoin/bitcoin/pull/28031#pullrequestreview-1531022386 and https://github.com/bitcoin/bitcoin/pull/28031#discussion_r1269622220 - Add `TXPACKAGES` category for logging. - Move a nearby comment block that was in the wrong place. ACKs for top commit: instagibbs: reACK https://github.com/bitcoin/bitcoin/pull/28364/commits/a3b55c94b9ffde07386aa887149ddca91b364967 achow101: ACK a3b55c94b9ffde07386aa887149ddca91b364967 brunoerg: crACK a3b55c94b9ffde07386aa887149ddca91b364967 mzumsande: Code review ACK a3b55c94b9ffde07386aa887149ddca91b364967 Tree-SHA512: 21884ef7c2ea2fd006e715574a9dd3e6cbbe8f82d62c6187fe1d39aad5a834051203fda5f355a06ca40c3e2b9561aec50d7c922a662b1edc96f7b552c9f4b24d
-rw-r--r--src/logging.cpp3
-rw-r--r--src/logging.h1
-rw-r--r--src/net_processing.cpp67
-rw-r--r--src/txorphanage.cpp17
-rw-r--r--src/validation.cpp4
-rwxr-xr-xtest/functional/p2p_permissions.py6
6 files changed, 63 insertions, 35 deletions
diff --git a/src/logging.cpp b/src/logging.cpp
index a5cfb0d28e..08bfa1f7a4 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -182,6 +182,7 @@ const CLogCategoryDesc LogCategories[] =
{BCLog::BLOCKSTORAGE, "blockstorage"},
{BCLog::TXRECONCILIATION, "txreconciliation"},
{BCLog::SCAN, "scan"},
+ {BCLog::TXPACKAGES, "txpackages"},
{BCLog::ALL, "1"},
{BCLog::ALL, "all"},
};
@@ -286,6 +287,8 @@ std::string LogCategoryToStr(BCLog::LogFlags category)
return "txreconciliation";
case BCLog::LogFlags::SCAN:
return "scan";
+ case BCLog::LogFlags::TXPACKAGES:
+ return "txpackages";
case BCLog::LogFlags::ALL:
return "all";
}
diff --git a/src/logging.h b/src/logging.h
index fc03c8eac3..f7380d8928 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -68,6 +68,7 @@ namespace BCLog {
BLOCKSTORAGE = (1 << 26),
TXRECONCILIATION = (1 << 27),
SCAN = (1 << 28),
+ TXPACKAGES = (1 << 29),
ALL = ~(uint32_t)0,
};
enum class Level {
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 8189d6c9f3..c5a22f258a 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -2919,9 +2919,15 @@ bool PeerManagerImpl::ProcessOrphanTx(Peer& peer)
const MempoolAcceptResult result = m_chainman.ProcessTransaction(porphanTx);
const TxValidationState& state = result.m_state;
const uint256& orphanHash = porphanTx->GetHash();
+ const uint256& orphan_wtxid = porphanTx->GetWitnessHash();
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
- LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
+ LogPrint(BCLog::TXPACKAGES, " accepted orphan tx %s (wtxid=%s)\n", orphanHash.ToString(), orphan_wtxid.ToString());
+ LogPrint(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s (wtxid=%s) (poolsz %u txn, %u kB)\n",
+ peer.m_id,
+ orphanHash.ToString(),
+ orphan_wtxid.ToString(),
+ m_mempool.size(), m_mempool.DynamicMemoryUsage() / 1000);
RelayTransaction(orphanHash, porphanTx->GetWitnessHash());
m_orphanage.AddChildrenToWorkSet(*porphanTx);
m_orphanage.EraseTx(orphanHash);
@@ -2931,8 +2937,14 @@ bool PeerManagerImpl::ProcessOrphanTx(Peer& peer)
return true;
} else if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) {
if (state.IsInvalid()) {
- LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s from peer=%d. %s\n",
+ LogPrint(BCLog::TXPACKAGES, " invalid orphan tx %s (wtxid=%s) from peer=%d. %s\n",
orphanHash.ToString(),
+ orphan_wtxid.ToString(),
+ peer.m_id,
+ state.ToString());
+ LogPrint(BCLog::MEMPOOLREJ, "%s (wtxid=%s) from peer=%d was not accepted: %s\n",
+ orphanHash.ToString(),
+ orphan_wtxid.ToString(),
peer.m_id,
state.ToString());
// Maybe punish peer that gave us an invalid orphan tx
@@ -2940,7 +2952,7 @@ bool PeerManagerImpl::ProcessOrphanTx(Peer& peer)
}
// Has inputs but not accepted to mempool
// Probably non-standard or insufficient fee
- LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
+ LogPrint(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s)\n", orphanHash.ToString(), orphan_wtxid.ToString());
if (state.GetResult() != TxValidationResult::TX_WITNESS_STRIPPED) {
// We can add the wtxid of this transaction to our reject filter.
// Do not add txids of witness transactions or witness-stripped
@@ -4115,12 +4127,29 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// permission, even if they were already in the mempool, allowing
// the node to function as a gateway for nodes hidden behind it.
if (!m_mempool.exists(GenTxid::Txid(tx.GetHash()))) {
- LogPrintf("Not relaying non-mempool transaction %s from forcerelay peer=%d\n", tx.GetHash().ToString(), pfrom.GetId());
+ LogPrintf("Not relaying non-mempool transaction %s (wtxid=%s) from forcerelay peer=%d\n",
+ tx.GetHash().ToString(), tx.GetWitnessHash().ToString(), pfrom.GetId());
} else {
- LogPrintf("Force relaying tx %s from peer=%d\n", tx.GetHash().ToString(), pfrom.GetId());
+ LogPrintf("Force relaying tx %s (wtxid=%s) from peer=%d\n",
+ tx.GetHash().ToString(), tx.GetWitnessHash().ToString(), pfrom.GetId());
RelayTransaction(tx.GetHash(), tx.GetWitnessHash());
}
}
+ // If a tx is detected by m_recent_rejects it is ignored. Because we haven't
+ // submitted the tx to our mempool, we won't have computed a DoS
+ // score for it or determined exactly why we consider it invalid.
+ //
+ // This means we won't penalize any peer subsequently relaying a DoSy
+ // tx (even if we penalized the first peer who gave it to us) because
+ // we have to account for m_recent_rejects showing false positives. In
+ // other words, we shouldn't penalize a peer if we aren't *sure* they
+ // submitted a DoSy tx.
+ //
+ // Note that m_recent_rejects doesn't just record DoSy or invalid
+ // transactions, but any tx not accepted by the mempool, which may be
+ // due to node policy (vs. consensus). So we can't blanket penalize a
+ // peer simply for relaying a tx that our m_recent_rejects has caught,
+ // regardless of false positives.
return;
}
@@ -4137,9 +4166,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
pfrom.m_last_tx_time = GetTime<std::chrono::seconds>();
- LogPrint(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
+ LogPrint(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s (wtxid=%s) (poolsz %u txn, %u kB)\n",
pfrom.GetId(),
tx.GetHash().ToString(),
+ tx.GetWitnessHash().ToString(),
m_mempool.size(), m_mempool.DynamicMemoryUsage() / 1000);
for (const CTransactionRef& removedTx : result.m_replaced_transactions.value()) {
@@ -4191,7 +4221,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// DoS prevention: do not allow m_orphanage to grow unbounded (see CVE-2012-3789)
m_orphanage.LimitOrphans(m_opts.max_orphan_txs);
} else {
- LogPrint(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
+ LogPrint(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n",
+ tx.GetHash().ToString(),
+ tx.GetWitnessHash().ToString());
// We will continue to reject this tx since it has rejected
// parents so avoid re-requesting it from other peers.
// Here we add both the txid and the wtxid, as we know that
@@ -4238,25 +4270,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
}
- // If a tx has been detected by m_recent_rejects, we will have reached
- // this point and the tx will have been ignored. Because we haven't
- // submitted the tx to our mempool, we won't have computed a DoS
- // score for it or determined exactly why we consider it invalid.
- //
- // This means we won't penalize any peer subsequently relaying a DoSy
- // tx (even if we penalized the first peer who gave it to us) because
- // we have to account for m_recent_rejects showing false positives. In
- // other words, we shouldn't penalize a peer if we aren't *sure* they
- // submitted a DoSy tx.
- //
- // Note that m_recent_rejects doesn't just record DoSy or invalid
- // transactions, but any tx not accepted by the mempool, which may be
- // due to node policy (vs. consensus). So we can't blanket penalize a
- // peer simply for relaying a tx that our m_recent_rejects has caught,
- // regardless of false positives.
-
if (state.IsInvalid()) {
- LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
+ LogPrint(BCLog::MEMPOOLREJ, "%s (wtxid=%s) from peer=%d was not accepted: %s\n",
+ tx.GetHash().ToString(),
+ tx.GetWitnessHash().ToString(),
pfrom.GetId(),
state.ToString());
MaybePunishNodeForTx(pfrom.GetId(), state);
diff --git a/src/txorphanage.cpp b/src/txorphanage.cpp
index af86baa8ac..7455d914e8 100644
--- a/src/txorphanage.cpp
+++ b/src/txorphanage.cpp
@@ -21,6 +21,7 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer)
LOCK(m_mutex);
const uint256& hash = tx->GetHash();
+ const uint256& wtxid = tx->GetWitnessHash();
if (m_orphans.count(hash))
return false;
@@ -34,7 +35,7 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer)
unsigned int sz = GetTransactionWeight(*tx);
if (sz > MAX_STANDARD_TX_WEIGHT)
{
- LogPrint(BCLog::MEMPOOL, "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString());
+ LogPrint(BCLog::TXPACKAGES, "ignoring large orphan tx (size: %u, txid: %s, wtxid: %s)\n", sz, hash.ToString(), wtxid.ToString());
return false;
}
@@ -47,7 +48,7 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer)
m_outpoint_to_orphan_it[txin.prevout].insert(ret.first);
}
- LogPrint(BCLog::MEMPOOL, "stored orphan tx %s (mapsz %u outsz %u)\n", hash.ToString(),
+ LogPrint(BCLog::TXPACKAGES, "stored orphan tx %s (wtxid=%s) (mapsz %u outsz %u)\n", hash.ToString(), wtxid.ToString(),
m_orphans.size(), m_outpoint_to_orphan_it.size());
return true;
}
@@ -83,6 +84,8 @@ int TxOrphanage::EraseTxNoLock(const uint256& txid)
m_orphan_list[old_pos] = it_last;
it_last->second.list_pos = old_pos;
}
+ const auto& wtxid = it->second.tx->GetWitnessHash();
+ LogPrint(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s)\n", txid.ToString(), wtxid.ToString());
m_orphan_list.pop_back();
m_wtxid_to_orphan_it.erase(it->second.tx->GetWitnessHash());
@@ -106,7 +109,7 @@ void TxOrphanage::EraseForPeer(NodeId peer)
nErased += EraseTxNoLock(maybeErase->second.tx->GetHash());
}
}
- if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, peer);
+ if (nErased > 0) LogPrint(BCLog::TXPACKAGES, "Erased %d orphan tx from peer=%d\n", nErased, peer);
}
void TxOrphanage::LimitOrphans(unsigned int max_orphans)
@@ -132,7 +135,7 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans)
}
// Sweep again 5 minutes after the next entry that expires in order to batch the linear scan.
nNextSweep = nMinExpTime + ORPHAN_TX_EXPIRE_INTERVAL;
- if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx due to expiration\n", nErased);
+ if (nErased > 0) LogPrint(BCLog::TXPACKAGES, "Erased %d orphan tx due to expiration\n", nErased);
}
FastRandomContext rng;
while (m_orphans.size() > max_orphans)
@@ -142,7 +145,7 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans)
EraseTxNoLock(m_orphan_list[randompos]->first);
++nEvicted;
}
- if (nEvicted > 0) LogPrint(BCLog::MEMPOOL, "orphanage overflow, removed %u tx\n", nEvicted);
+ if (nEvicted > 0) LogPrint(BCLog::TXPACKAGES, "orphanage overflow, removed %u tx\n", nEvicted);
}
void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx)
@@ -159,6 +162,8 @@ void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx)
std::set<uint256>& orphan_work_set = m_peer_work_set.try_emplace(elem->second.fromPeer).first->second;
// Add this tx to the work set
orphan_work_set.insert(elem->first);
+ LogPrint(BCLog::TXPACKAGES, "added %s (wtxid=%s) to peer %d workset\n",
+ tx.GetHash().ToString(), tx.GetWitnessHash().ToString(), elem->second.fromPeer);
}
}
}
@@ -233,6 +238,6 @@ void TxOrphanage::EraseForBlock(const CBlock& block)
for (const uint256& orphanHash : vOrphanErase) {
nErased += EraseTxNoLock(orphanHash);
}
- LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased);
+ LogPrint(BCLog::TXPACKAGES, "Erased %d orphan tx included or conflicted by block\n", nErased);
}
}
diff --git a/src/validation.cpp b/src/validation.cpp
index ed9889d9dd..0b6327ec55 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1079,9 +1079,11 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
// Remove conflicting transactions from the mempool
for (CTxMemPool::txiter it : ws.m_all_conflicting)
{
- LogPrint(BCLog::MEMPOOL, "replacing tx %s with %s for %s additional fees, %d delta bytes\n",
+ LogPrint(BCLog::MEMPOOL, "replacing tx %s (wtxid=%s) with %s (wtxid=%s) for %s additional fees, %d delta bytes\n",
it->GetTx().GetHash().ToString(),
+ it->GetTx().GetWitnessHash().ToString(),
hash.ToString(),
+ tx.GetWitnessHash().ToString(),
FormatMoney(ws.m_modified_fees - ws.m_conflicting_fees),
(int)entry->GetTxSize() - (int)ws.m_conflicting_size);
TRACE7(mempool, replaced,
diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py
index f84bbf67e6..6153e4a156 100755
--- a/test/functional/p2p_permissions.py
+++ b/test/functional/p2p_permissions.py
@@ -106,7 +106,7 @@ class P2PPermissionsTests(BitcoinTestFramework):
self.log.debug("Check that node[1] will send the tx to node[0] even though it is already in the mempool")
self.connect_nodes(1, 0)
- with self.nodes[1].assert_debug_log(["Force relaying tx {} from peer=0".format(txid)]):
+ with self.nodes[1].assert_debug_log(["Force relaying tx {} (wtxid={}) from peer=0".format(txid, tx.getwtxid())]):
p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1])
self.wait_until(lambda: txid in self.nodes[0].getrawmempool())
@@ -119,14 +119,14 @@ class P2PPermissionsTests(BitcoinTestFramework):
[tx],
self.nodes[1],
success=False,
- reject_reason='{} from peer=0 was not accepted: txn-mempool-conflict'.format(txid)
+ reject_reason='{} (wtxid={}) from peer=0 was not accepted: txn-mempool-conflict'.format(txid, tx.getwtxid())
)
p2p_rebroadcast_wallet.send_txs_and_test(
[tx],
self.nodes[1],
success=False,
- reject_reason='Not relaying non-mempool transaction {} from forcerelay peer=0'.format(txid)
+ reject_reason='Not relaying non-mempool transaction {} (wtxid={}) from forcerelay peer=0'.format(txid, tx.getwtxid())
)
def checkpermission(self, args, expectedPermissions):