net_processing: store transactions for private broadcast in PeerManager

Extend `PeerManager` with a transaction storage and a new method
`InitiateTxBroadcastPrivate()` which:
* adds a transaction to that storage and
* calls `CConnman::PrivateBroadcast::NumToOpenAdd()` to open dedicated
  privacy connections that will pick an entry from the transaction
  storage and broadcast it.
This commit is contained in:
Vasil Dimov 2024-01-30 10:01:24 +01:00
parent a3faa6f944
commit 679ce3a0b8
No known key found for this signature in database
GPG Key ID: 54DF06F64B55CBBF
6 changed files with 104 additions and 0 deletions

View File

@ -244,6 +244,7 @@ add_library(bitcoin_node STATIC EXCLUDE_FROM_ALL
policy/rbf.cpp
policy/settings.cpp
policy/truc_policy.cpp
private_broadcast.cpp
rest.cpp
rpc/blockchain.cpp
rpc/external_signer.cpp

View File

@ -44,6 +44,7 @@
#include <policy/policy.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <private_broadcast.h>
#include <protocol.h>
#include <random.h>
#include <scheduler.h>
@ -196,6 +197,8 @@ static constexpr double MAX_ADDR_RATE_PER_SECOND{0.1};
static constexpr size_t MAX_ADDR_PROCESSING_TOKEN_BUCKET{MAX_ADDR_TO_SEND};
/** The compactblocks version we support. See BIP 152. */
static constexpr uint64_t CMPCTBLOCKS_VERSION{2};
/** For private broadcast, send a transaction to this many peers. */
static constexpr size_t NUM_PRIVATE_BROADCAST_PER_TX{3};
// Internal stuff
namespace {
@ -538,6 +541,7 @@ public:
PeerManagerInfo GetInfo() const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void SendPings() override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void InitiateTxBroadcastToAll(const Txid& txid, const Wtxid& wtxid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void InitiateTxBroadcastPrivate(const CTransactionRef& tx) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void SetBestBlock(int height, std::chrono::seconds time) override
{
m_best_height = height;
@ -1070,6 +1074,9 @@ private:
void PushAddress(Peer& peer, const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
void LogBlockHeader(const CBlockIndex& index, const CNode& peer, bool via_compact_block);
/// The transactions to be broadcast privately.
PrivateBroadcast m_tx_for_private_broadcast;
};
const CNodeState* PeerManagerImpl::State(NodeId pnode) const
@ -2147,6 +2154,17 @@ void PeerManagerImpl::InitiateTxBroadcastToAll(const Txid& txid, const Wtxid& wt
}
}
void PeerManagerImpl::InitiateTxBroadcastPrivate(const CTransactionRef& tx)
{
const auto txstr{strprintf("txid=%s, wtxid=%s", tx->GetHash().ToString(), tx->GetWitnessHash().ToString())};
if (m_tx_for_private_broadcast.Add(tx)) {
LogDebug(BCLog::PRIVBROADCAST, "Requesting %d new connections due to %s", NUM_PRIVATE_BROADCAST_PER_TX, txstr);
m_connman.m_private_broadcast.NumToOpenAdd(NUM_PRIVATE_BROADCAST_PER_TX);
} else {
LogDebug(BCLog::PRIVBROADCAST, "Ignoring unnecessary request to schedule an already scheduled transaction: %s", txstr);
}
}
void PeerManagerImpl::RelayAddress(NodeId originator,
const CAddress& addr,
bool fReachable)

View File

@ -124,6 +124,12 @@ public:
*/
virtual void InitiateTxBroadcastToAll(const Txid& txid, const Wtxid& wtxid) = 0;
/**
* Initiate a private transaction broadcast. This is done
* asynchronously via short-lived connections to peers on privacy networks.
*/
virtual void InitiateTxBroadcastPrivate(const CTransactionRef& tx) = 0;
/** Send ping message to all peers */
virtual void SendPings() = 0;

View File

@ -139,6 +139,7 @@ TransactionError BroadcastTransaction(NodeContext& node,
node.peerman->InitiateTxBroadcastToAll(txid, wtxid);
break;
case TxBroadcast::NO_MEMPOOL_PRIVATE_BROADCAST:
node.peerman->InitiateTxBroadcastPrivate(tx);
break;
}

13
src/private_broadcast.cpp Normal file
View File

@ -0,0 +1,13 @@
// Copyright (c) 2023-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://opensource.org/license/mit/.
#include <private_broadcast.h>
bool PrivateBroadcast::Add(const CTransactionRef& tx)
EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
LOCK(m_mutex);
const bool inserted{m_transactions.try_emplace(tx).second};
return inserted;
}

65
src/private_broadcast.h Normal file
View File

@ -0,0 +1,65 @@
// Copyright (c) 2023-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://opensource.org/license/mit/.
#ifndef BITCOIN_PRIVATE_BROADCAST_H
#define BITCOIN_PRIVATE_BROADCAST_H
#include <net.h>
#include <primitives/transaction.h>
#include <sync.h>
#include <threadsafety.h>
#include <util/time.h>
#include <optional>
#include <unordered_map>
#include <vector>
/**
* Store a list of transactions to be broadcast privately. Supports the following operations:
* - Add a new transaction
*/
class PrivateBroadcast
{
public:
/**
* Add a transaction to the storage.
* @param[in] tx The transaction to add.
* @retval true The transaction was added.
* @retval false The transaction was already present.
*/
bool Add(const CTransactionRef& tx)
EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
private:
/// Status of a transaction sent to a given node.
struct SendStatus {
const NodeId nodeid; /// Node to which the transaction will be sent (or was sent).
const NodeClock::time_point picked; ///< When was the transaction picked for sending to the node.
std::optional<NodeClock::time_point> confirmed; ///< When was the transaction reception confirmed by the node (by PONG).
SendStatus(const NodeId& nodeid, const NodeClock::time_point& picked) : nodeid{nodeid}, picked{picked} {}
};
// No need for salted hasher because we are going to store just a bunch of locally originating transactions.
struct CTransactionRefHash {
size_t operator()(const CTransactionRef& tx) const
{
return static_cast<size_t>(tx->GetWitnessHash().ToUint256().GetUint64(0));
}
};
struct CTransactionRefComp {
bool operator()(const CTransactionRef& a, const CTransactionRef& b) const
{
return a->GetWitnessHash() == b->GetWitnessHash(); // If wtxid equals, then txid also equals.
}
};
mutable Mutex m_mutex;
std::unordered_map<CTransactionRef, std::vector<SendStatus>, CTransactionRefHash, CTransactionRefComp>
m_transactions GUARDED_BY(m_mutex);
};
#endif // BITCOIN_PRIVATE_BROADCAST_H