Repository: bitcoin/bitcoin
File: src/net_processing.cpp (C++)

Code before:
{
    return PeerManagerInfo{
        .median_outbound_time_offset = m_outbound_time_offsets.Median(),
        .ignores_incoming_txs = m_opts.ignore_incoming_txs,
    };
}

void PeerManagerImpl::AddToCompactExtraTransactions(const CTransactionRef& tx)
{
    if (m_opts.max_extra_txs <= 0)
        return;
    if (!vExtraTxnForCompact.size())
        vExtraTxnForCompact.resize(m_opts.max_extra_txs);
    vExtraTxnForCompact[vExtraTxnForCompactIt] = std::make_pair(tx->GetWitnessHash(), tx);
    vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
}

void PeerManagerImpl::Misbehaving(Peer& peer, const std::string& message)
{
    LOCK(peer.m_misbehavior_mutex);

    const std::string message_prefixed = message.empty() ? "" : (": " + message);
    peer.m_should_discourage = true;
    LogDebug(BCLog::NET, "Misbehaving: peer=%d%s\n", peer.m_id, message_prefixed);
    TRACEPOINT(net, misbehaving_connection,
        peer.m_id,
        message.c_str()
    );
}

void PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state,
                                              bool via_compact_block, const std::string& message)
{
    PeerRef peer{GetPeerRef(nodeid)};
    switch (state.GetResult()) {
    case BlockValidationResult::BLOCK_RESULT_UNSET:
        break;
    case BlockValidationResult::BLOCK_HEADER_LOW_WORK:
        // We didn't try to process the block because the header chain may have
        // too little work.
        break;
    // The node is providing invalid data:
    case BlockValidationResult::BLOCK_CONSENSUS:
    case BlockValidationResult::BLOCK_MUTATED:
        if (!via_compact_block) {
            if (peer) Misbehaving(*peer, message);
            return;
        }
        break;
    case BlockValidationResult::BLOCK_CACHED_INVALID:
        {

Review comment (suggestion):
I think this might end up closing more connections than needed, but it's not a big deal because `ReattemptPrivateBroadcast` will take care of re-opening them.

For example:

- We send a transaction with `sendrawtransaction`, `NumToOpenAdd(3)` is called, `m_num_to_open = 3`
- One connection is opened in `ThreadPrivateBroadcast`, `NumToOpenSub(1)` is called, `m_num_to_open = 2`
- One connection is opened in `ThreadPrivateBroadcast`, `NumToOpenSub(1)` is called, `m_num_to_open = 1`
- We abort the broadcast before any peer acked the transaction. We will call `NumToOpenSub(NUM_PRIVATE_BROADCAST_PER_TX - *peer_acks)`, so `NumToOpenSub(3)`. In this specific case, `m_num_to_open` would end up being equal to zero. However, if we were broadcasting multiple transactions at the same time, we would not open some connections for some other transaction.



Code after:

PeerManagerInfo PeerManagerImpl::GetInfo() const
{
    return PeerManagerInfo{
        .median_outbound_time_offset = m_outbound_time_offsets.Median(),
        .ignores_incoming_txs = m_opts.ignore_incoming_txs,
    };
}

std::vector<PrivateBroadcast::TxBroadcastInfo> PeerManagerImpl::GetPrivateBroadcastInfo() const
{
    return m_tx_for_private_broadcast.GetBroadcastInfo();
}

std::vector<CTransactionRef> PeerManagerImpl::AbortPrivateBroadcast(const uint256& id)
{
    const auto snapshot{m_tx_for_private_broadcast.GetBroadcastInfo()};
    std::vector<CTransactionRef> removed_txs;

    size_t connections_cancelled{0};
    for (const auto& [tx, _] : snapshot) {
        if (tx->GetHash().ToUint256() != id && tx->GetWitnessHash().ToUint256() != id) continue;
        if (const auto peer_acks{m_tx_for_private_broadcast.Remove(tx)}) {
            removed_txs.push_back(tx);
            if (NUM_PRIVATE_BROADCAST_PER_TX > *peer_acks) {
                connections_cancelled += (NUM_PRIVATE_BROADCAST_PER_TX - *peer_acks);
            }
        }
    }
    m_connman.m_private_broadcast.NumToOpenSub(connections_cancelled);

    return removed_txs;
}

void PeerManagerImpl::AddToCompactExtraTransactions(const CTransactionRef& tx)
{
    if (m_opts.max_extra_txs <= 0)
        return;
    if (!vExtraTxnForCompact.size())
        vExtraTxnForCompact.resize(m_opts.max_extra_txs);
    vExtraTxnForCompact[vExtraTxnForCompactIt] = std::make_pair(tx->GetWitnessHash(), tx);
    vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
}

void PeerManagerImpl::Misbehaving(Peer& peer, const std::string& message)
{
    LOCK(peer.m_misbehavior_mutex);

    const std::string message_prefixed = message.empty() ? "" : (": " + message);
    peer.m_should_discourage = true;
    LogDebug(BCLog::NET, "Misbehaving: peer=%d%s\n", peer.m_id, message_prefixed);