mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-08 10:31:50 -05:00
p2p: Announce reconciliation support
If we're connecting to the peer which might support transaction reconciliation, we announce we want to reconcile with them. We store the reconciliation salt so that when the peer responds with their salt, we are able to compute the full reconciliation salt. This behavior is enabled with a CLI flag.
This commit is contained in:
parent
24e36fac0a
commit
3fcf78ee6a
8 changed files with 173 additions and 2 deletions
|
@ -209,6 +209,7 @@ BITCOIN_CORE_H = \
|
|||
node/minisketchwrapper.h \
|
||||
node/psbt.h \
|
||||
node/transaction.h \
|
||||
node/txreconciliation.h \
|
||||
node/utxo_snapshot.h \
|
||||
node/validation_cache_args.h \
|
||||
noui.h \
|
||||
|
@ -396,6 +397,7 @@ libbitcoin_node_a_SOURCES = \
|
|||
node/minisketchwrapper.cpp \
|
||||
node/psbt.cpp \
|
||||
node/transaction.cpp \
|
||||
node/txreconciliation.cpp \
|
||||
node/utxo_snapshot.cpp \
|
||||
node/validation_cache_args.cpp \
|
||||
noui.cpp \
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <node/mempool_args.h>
|
||||
#include <node/mempool_persist_args.h>
|
||||
#include <node/miner.h>
|
||||
#include <node/txreconciliation.h>
|
||||
#include <node/validation_cache_args.h>
|
||||
#include <policy/feerate.h>
|
||||
#include <policy/fees.h>
|
||||
|
@ -484,6 +485,7 @@ void SetupServerArgs(ArgsManager& argsman)
|
|||
argsman.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-networkactive", "Enable all P2P network activity (default: 1). Can be changed by the setnetworkactive RPC command", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-timeout=<n>", strprintf("Specify socket connection timeout in milliseconds. If an initial attempt to connect is unsuccessful after this amount of time, drop it (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-peertimeout=<n>", strprintf("Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: %d)", DEFAULT_PEER_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-torcontrol=<ip>:<port>", strprintf("Tor control port to use if onion listening enabled (default: %s)", DEFAULT_TOR_CONTROL), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-torpassword=<pass>", "Tor control port password (default: empty)", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::CONNECTION);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <netbase.h>
|
||||
#include <netmessagemaker.h>
|
||||
#include <node/blockstorage.h>
|
||||
#include <node/txreconciliation.h>
|
||||
#include <policy/fees.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
|
@ -703,6 +704,7 @@ private:
|
|||
ChainstateManager& m_chainman;
|
||||
CTxMemPool& m_mempool;
|
||||
TxRequestTracker m_txrequest GUARDED_BY(::cs_main);
|
||||
std::unique_ptr<TxReconciliationTracker> m_txreconciliation;
|
||||
|
||||
/** The height of the best chain */
|
||||
std::atomic<int> m_best_height{-1};
|
||||
|
@ -1776,6 +1778,11 @@ PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman,
|
|||
m_mempool(pool),
|
||||
m_ignore_incoming_txs(ignore_incoming_txs)
|
||||
{
|
||||
// While Erlay support is incomplete, it must be enabled explicitly via -txreconciliation.
|
||||
// This argument can go away after Erlay support is complete.
|
||||
if (gArgs.GetBoolArg("-txreconciliation", DEFAULT_TXRECONCILIATION_ENABLE)) {
|
||||
m_txreconciliation = std::make_unique<TxReconciliationTracker>();
|
||||
}
|
||||
}
|
||||
|
||||
void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler)
|
||||
|
@ -3236,8 +3243,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
|||
m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::SENDADDRV2));
|
||||
}
|
||||
|
||||
m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::VERACK));
|
||||
|
||||
pfrom.m_has_all_wanted_services = HasAllDesirableServiceFlags(nServices);
|
||||
peer->m_their_services = nServices;
|
||||
pfrom.SetAddrLocal(addrMe);
|
||||
|
@ -3262,6 +3267,25 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
|||
if (fRelay) pfrom.m_relays_txs = true;
|
||||
}
|
||||
|
||||
if (greatest_common_version >= WTXID_RELAY_VERSION && m_txreconciliation) {
|
||||
// Per BIP-330, we announce txreconciliation support if:
|
||||
// - protocol version per the VERSION message supports WTXID_RELAY;
|
||||
// - we intended to exchange transactions over this connection while establishing it
|
||||
// and the peer indicated support for transaction relay in the VERSION message;
|
||||
// - we are not in -blocksonly mode.
|
||||
if (pfrom.m_relays_txs && !m_ignore_incoming_txs) {
|
||||
const uint64_t recon_salt = m_txreconciliation->PreRegisterPeer(pfrom.GetId());
|
||||
// We suggest our txreconciliation role (initiator/responder) based on
|
||||
// the connection direction.
|
||||
m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::SENDTXRCNCL,
|
||||
!pfrom.IsInboundConn(),
|
||||
pfrom.IsInboundConn(),
|
||||
TXRECONCILIATION_VERSION, recon_salt));
|
||||
}
|
||||
}
|
||||
|
||||
m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::VERACK));
|
||||
|
||||
// Potentially mark this peer as a preferred download peer.
|
||||
{
|
||||
LOCK(cs_main);
|
||||
|
|
66
src/node/txreconciliation.cpp
Normal file
66
src/node/txreconciliation.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) 2022 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <node/txreconciliation.h>
|
||||
|
||||
#include <util/check.h>
|
||||
#include <util/system.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Keeps track of txreconciliation-related per-peer state.
|
||||
*/
|
||||
class TxReconciliationState
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
/** Actual implementation for TxReconciliationTracker's data structure. */
|
||||
class TxReconciliationTracker::Impl
|
||||
{
|
||||
private:
|
||||
mutable Mutex m_txreconciliation_mutex;
|
||||
|
||||
/**
|
||||
* Keeps track of txreconciliation states of eligible peers.
|
||||
* For pre-registered peers, the locally generated salt is stored.
|
||||
* For registered peers, the locally generated salt is forgotten, and the state (including
|
||||
* "full" salt) is stored instead.
|
||||
*/
|
||||
std::unordered_map<NodeId, std::variant<uint64_t, TxReconciliationState>> m_states GUARDED_BY(m_txreconciliation_mutex);
|
||||
|
||||
public:
|
||||
explicit Impl() {}
|
||||
|
||||
uint64_t PreRegisterPeer(NodeId peer_id) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex)
|
||||
{
|
||||
AssertLockNotHeld(m_txreconciliation_mutex);
|
||||
LOCK(m_txreconciliation_mutex);
|
||||
// We do not support txreconciliation salt/version updates.
|
||||
assert(m_states.find(peer_id) == m_states.end());
|
||||
|
||||
LogPrintLevel(BCLog::TXRECONCILIATION, BCLog::Level::Debug, "Pre-register peer=%d\n", peer_id);
|
||||
const uint64_t local_salt{GetRand(UINT64_MAX)};
|
||||
|
||||
// We do this exactly once per peer (which are unique by NodeId, see GetNewNodeId) so it's
|
||||
// safe to assume we don't have this record yet.
|
||||
Assert(m_states.emplace(peer_id, local_salt).second);
|
||||
return local_salt;
|
||||
}
|
||||
};
|
||||
|
||||
TxReconciliationTracker::TxReconciliationTracker() : m_impl{std::make_unique<TxReconciliationTracker::Impl>()} {}
|
||||
|
||||
TxReconciliationTracker::~TxReconciliationTracker() = default;
|
||||
|
||||
uint64_t TxReconciliationTracker::PreRegisterPeer(NodeId peer_id)
|
||||
{
|
||||
return m_impl->PreRegisterPeer(peer_id);
|
||||
}
|
66
src/node/txreconciliation.h
Normal file
66
src/node/txreconciliation.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) 2022 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_NODE_TXRECONCILIATION_H
|
||||
#define BITCOIN_NODE_TXRECONCILIATION_H
|
||||
|
||||
#include <net.h>
|
||||
#include <sync.h>
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
/** Whether transaction reconciliation protocol should be enabled by default. */
|
||||
static constexpr bool DEFAULT_TXRECONCILIATION_ENABLE{false};
|
||||
/** Supported transaction reconciliation protocol version */
|
||||
static constexpr uint32_t TXRECONCILIATION_VERSION{1};
|
||||
|
||||
/**
|
||||
* Transaction reconciliation is a way for nodes to efficiently announce transactions.
|
||||
* This object keeps track of all txreconciliation-related communications with the peers.
|
||||
* The high-level protocol is:
|
||||
* 0. Txreconciliation protocol handshake.
|
||||
* 1. Once we receive a new transaction, add it to the set instead of announcing immediately.
|
||||
* 2. At regular intervals, a txreconciliation initiator requests a sketch from a peer, where a
|
||||
* sketch is a compressed representation of short form IDs of the transactions in their set.
|
||||
* 3. Once the initiator received a sketch from the peer, the initiator computes a local sketch,
|
||||
* and combines the two sketches to attempt finding the difference in *sets*.
|
||||
* 4a. If the difference was not larger than estimated, see SUCCESS below.
|
||||
* 4b. If the difference was larger than estimated, initial txreconciliation fails. The initiator
|
||||
* requests a larger sketch via an extension round (allowed only once).
|
||||
* - If extension succeeds (a larger sketch is sufficient), see SUCCESS below.
|
||||
* - If extension fails (a larger sketch is insufficient), see FAILURE below.
|
||||
*
|
||||
* SUCCESS. The initiator knows full symmetrical difference and can request what the initiator is
|
||||
* missing and announce to the peer what the peer is missing.
|
||||
*
|
||||
* FAILURE. The initiator notifies the peer about the failure and announces all transactions from
|
||||
* the corresponding set. Once the peer received the failure notification, the peer
|
||||
* announces all transactions from their set.
|
||||
|
||||
* This is a modification of the Erlay protocol (https://arxiv.org/abs/1905.10518) with two
|
||||
* changes (sketch extensions instead of bisections, and an extra INV exchange round), both
|
||||
* are motivated in BIP-330.
|
||||
*/
|
||||
class TxReconciliationTracker
|
||||
{
|
||||
private:
|
||||
class Impl;
|
||||
const std::unique_ptr<Impl> m_impl;
|
||||
|
||||
public:
|
||||
explicit TxReconciliationTracker();
|
||||
~TxReconciliationTracker();
|
||||
|
||||
/**
|
||||
* Step 0. Generates initial part of the state (salt) required to reconcile txs with the peer.
|
||||
* The salt is used for short ID computation required for txreconciliation.
|
||||
* The function returns the salt.
|
||||
* A peer can't participate in future txreconciliations without this call.
|
||||
* This function must be called only once per peer.
|
||||
*/
|
||||
uint64_t PreRegisterPeer(NodeId peer_id);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_NODE_TXRECONCILIATION_H
|
|
@ -44,6 +44,7 @@ const char *CFHEADERS="cfheaders";
|
|||
const char *GETCFCHECKPT="getcfcheckpt";
|
||||
const char *CFCHECKPT="cfcheckpt";
|
||||
const char *WTXIDRELAY="wtxidrelay";
|
||||
const char *SENDTXRCNCL="sendtxrcncl";
|
||||
} // namespace NetMsgType
|
||||
|
||||
/** All known message types. Keep this in the same order as the list of
|
||||
|
@ -84,6 +85,7 @@ const static std::string allNetMessageTypes[] = {
|
|||
NetMsgType::GETCFCHECKPT,
|
||||
NetMsgType::CFCHECKPT,
|
||||
NetMsgType::WTXIDRELAY,
|
||||
NetMsgType::SENDTXRCNCL,
|
||||
};
|
||||
const static std::vector<std::string> allNetMessageTypesVec(std::begin(allNetMessageTypes), std::end(allNetMessageTypes));
|
||||
|
||||
|
|
|
@ -258,6 +258,14 @@ extern const char* CFCHECKPT;
|
|||
* @since protocol version 70016 as described by BIP 339.
|
||||
*/
|
||||
extern const char* WTXIDRELAY;
|
||||
/**
|
||||
* Contains 2 1-byte bools, a 4-byte version number and an 8-byte salt.
|
||||
* The 2 booleans indicate that a node is willing to participate in transaction
|
||||
* reconciliation, respectively as an initiator or as a receiver.
|
||||
* The salt is used to compute short txids needed for efficient
|
||||
* txreconciliation, as described by BIP 330.
|
||||
*/
|
||||
extern const char* SENDTXRCNCL;
|
||||
}; // namespace NetMsgType
|
||||
|
||||
/* Get a vector of all valid message types (see above) */
|
||||
|
|
|
@ -130,6 +130,7 @@ FUZZ_TARGET_MSG(pong);
|
|||
FUZZ_TARGET_MSG(sendaddrv2);
|
||||
FUZZ_TARGET_MSG(sendcmpct);
|
||||
FUZZ_TARGET_MSG(sendheaders);
|
||||
FUZZ_TARGET_MSG(sendtxrcncl);
|
||||
FUZZ_TARGET_MSG(tx);
|
||||
FUZZ_TARGET_MSG(verack);
|
||||
FUZZ_TARGET_MSG(version);
|
||||
|
|
Loading…
Add table
Reference in a new issue