Skip to content

Commit

Permalink
merge bitcoin#26359: Erlay support signaling follow-ups
Browse files Browse the repository at this point in the history
  • Loading branch information
kwvg committed Oct 27, 2024
1 parent b55a6f7 commit 38a16a2
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 163 deletions.
2 changes: 1 addition & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-v2transport", strprintf("Support v2 transport (default: %u)", DEFAULT_V2_TRANSPORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), 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, OptionsCategory::CONNECTION);
argsman.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port>. Nodes not using the default ports (default: %u, testnet: %u, regtest: %u) are unlikely to get incoming connections. Not relevant for I2P (see doc/i2p.md).", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
Expand All @@ -588,7 +589,6 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-socketevents=<mode>", "Socket events mode, which must be one of 'select', 'poll', 'epoll' or 'kqueue', depending on your system (default: Linux - 'epoll', FreeBSD/Apple - 'kqueue', Windows - 'select')", 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_BOOL, 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("-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);
#ifdef USE_UPNP
Expand Down
54 changes: 27 additions & 27 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3544,17 +3544,14 @@ void PeerManagerImpl::ProcessMessage(

if (greatest_common_version >= INCREASE_MAX_HEADERS2_VERSION && m_txreconciliation) {
// Per BIP-330, we announce txreconciliation support if:
// - protocol version per the VERSION message supports INCREASE_MAX_HEADERS2_VERSION;
// - we intended to exchange transactions over this connection while establishing it
// and the peer indicated support for transaction relay in the VERSION message;
// - protocol version per the peer's VERSION message supports INCREASE_MAX_HEADERS2_VERSION;
// - transaction relay is supported per the peer's VERSION message (see m_relays_txs);
// - this is not a block-relay-only connection and not a feeler (see m_relays_txs);
// - this is not an addr fetch connection;
// - we are not in -blocksonly mode.
if (pfrom.m_relays_txs && !m_ignore_incoming_txs) {
if (pfrom.m_relays_txs && !pfrom.IsAddrFetchConn() && !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));
}
}
Expand Down Expand Up @@ -3771,41 +3768,44 @@ void PeerManagerImpl::ProcessMessage(
}

if (pfrom.fSuccessfullyConnected) {
// Disconnect peers that send a SENDTXRCNCL message after VERACK.
LogPrint(BCLog::NET, "sendtxrcncl received after verack from peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
}

if (!peer->GetTxRelay()) {
// Disconnect peers that send a SENDTXRCNCL message even though we indicated we don't
// support transaction relay.
// Peer must not offer us reconciliations if we specified no tx relay support in VERSION.
if (RejectIncomingTxs(pfrom)) {
LogPrint(BCLog::NET, "sendtxrcncl received from peer=%d to which we indicated no tx relay; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
}

bool is_peer_initiator, is_peer_responder;
// Peer must not offer us reconciliations if they specified no tx relay support in VERSION.
// This flag might also be false in other cases, but the RejectIncomingTxs check above
// eliminates them, so that this flag fully represents what we are looking for.
if (!pfrom.m_relays_txs) {
LogPrint(BCLog::NET, "sendtxrcncl received from peer=%d which indicated no tx relay to us; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
}

uint32_t peer_txreconcl_version;
uint64_t remote_salt;
vRecv >> is_peer_initiator >> is_peer_responder >> peer_txreconcl_version >> remote_salt;
vRecv >> peer_txreconcl_version >> remote_salt;

if (m_txreconciliation->IsPeerRegistered(pfrom.GetId())) {
// A peer is already registered, meaning we already received SENDTXRCNCL from them.
const ReconciliationRegisterResult result = m_txreconciliation->RegisterPeer(pfrom.GetId(), pfrom.IsInboundConn(),
peer_txreconcl_version, remote_salt);
switch (result) {
case ReconciliationRegisterResult::NOT_FOUND:
LogPrint(BCLog::NET, "Ignore unexpected txreconciliation signal from peer=%d\n", pfrom.GetId());
break;
case ReconciliationRegisterResult::SUCCESS:
break;
case ReconciliationRegisterResult::ALREADY_REGISTERED:
LogPrint(BCLog::NET, "txreconciliation protocol violation from peer=%d (sendtxrcncl received from already registered peer); disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
}

const ReconciliationRegisterResult result = m_txreconciliation->RegisterPeer(pfrom.GetId(), pfrom.IsInboundConn(),
is_peer_initiator, is_peer_responder,
peer_txreconcl_version,
remote_salt);

// If it's a protocol violation, disconnect.
// If the peer was not found (but something unexpected happened) or it was registered,
// nothing to be done.
if (result == ReconciliationRegisterResult::PROTOCOL_VIOLATION) {
case ReconciliationRegisterResult::PROTOCOL_VIOLATION:
LogPrint(BCLog::NET, "txreconciliation protocol violation from peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
Expand Down
52 changes: 18 additions & 34 deletions src/node/txreconciliation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class TxReconciliationState
* the following commits.
*
* Reconciliation protocol assumes using one role consistently: either a reconciliation
* initiator (requesting sketches), or responder (sending sketches). This defines our role.
* initiator (requesting sketches), or responder (sending sketches). This defines our role,
* based on the direction of the p2p connection.
*
*/
bool m_we_initiate;
Expand Down Expand Up @@ -81,31 +82,30 @@ class TxReconciliationTracker::Impl
{
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());

LogPrint(BCLog::TXRECONCILIATION, "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);
Assume(m_states.emplace(peer_id, local_salt).second);
return local_salt;
}

ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound, bool is_peer_recon_initiator,
bool is_peer_recon_responder, uint32_t peer_recon_version,
uint64_t remote_salt) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex)
ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound, uint32_t peer_recon_version,
uint64_t remote_salt) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex)
{
AssertLockNotHeld(m_txreconciliation_mutex);
LOCK(m_txreconciliation_mutex);
auto recon_state = m_states.find(peer_id);

// A peer should be in the pre-registered state to proceed here.
if (recon_state == m_states.end()) return NOT_FOUND;
uint64_t* local_salt = std::get_if<uint64_t>(&recon_state->second);
// A peer is already registered. This should be checked by the caller.
Assume(local_salt);
if (recon_state == m_states.end()) return ReconciliationRegisterResult::NOT_FOUND;

if (std::holds_alternative<TxReconciliationState>(recon_state->second)) {
return ReconciliationRegisterResult::ALREADY_REGISTERED;
}

uint64_t local_salt = *std::get_if<uint64_t>(&recon_state->second);

// If the peer supports the version which is lower than ours, we downgrade to the version
// it supports. For now, this only guarantees that nodes with future reconciliation
Expand All @@ -114,27 +114,13 @@ class TxReconciliationTracker::Impl
// satisfactory (e.g. too low).
const uint32_t recon_version{std::min(peer_recon_version, m_recon_version)};
// v1 is the lowest version, so suggesting something below must be a protocol violation.
if (recon_version < 1) return PROTOCOL_VIOLATION;

// Must match SENDTXRCNCL logic.
const bool they_initiate = is_peer_recon_initiator && is_peer_inbound;
const bool we_initiate = !is_peer_inbound && is_peer_recon_responder;

// If we ever announce support for both requesting and responding, this will need
// tie-breaking. For now, this is mutually exclusive because both are based on the
// inbound flag.
assert(!(they_initiate && we_initiate));

// The peer set both flags to false, we treat it as a protocol violation.
if (!(they_initiate || we_initiate)) return PROTOCOL_VIOLATION;
if (recon_version < 1) return ReconciliationRegisterResult::PROTOCOL_VIOLATION;

LogPrint(BCLog::TXRECONCILIATION, "Register peer=%d with the following params: " /* Continued */
"we_initiate=%i, they_initiate=%i.\n",
peer_id, we_initiate, they_initiate);
LogPrint(BCLog::TXRECONCILIATION, "Register peer=%d (inbound=%i)\n", peer_id, is_peer_inbound);

const uint256 full_salt{ComputeSalt(*local_salt, remote_salt)};
recon_state->second = TxReconciliationState(we_initiate, full_salt.GetUint64(0), full_salt.GetUint64(1));
return SUCCESS;
const uint256 full_salt{ComputeSalt(local_salt, remote_salt)};
recon_state->second = TxReconciliationState(!is_peer_inbound, full_salt.GetUint64(0), full_salt.GetUint64(1));
return ReconciliationRegisterResult::SUCCESS;
}

void ForgetPeer(NodeId peer_id) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex)
Expand Down Expand Up @@ -166,11 +152,9 @@ uint64_t TxReconciliationTracker::PreRegisterPeer(NodeId peer_id)
}

ReconciliationRegisterResult TxReconciliationTracker::RegisterPeer(NodeId peer_id, bool is_peer_inbound,
bool is_peer_recon_initiator, bool is_peer_recon_responder,
uint32_t peer_recon_version, uint64_t remote_salt)
{
return m_impl->RegisterPeer(peer_id, is_peer_inbound, is_peer_recon_initiator, is_peer_recon_responder,
peer_recon_version, remote_salt);
return m_impl->RegisterPeer(peer_id, is_peer_inbound, peer_recon_version, remote_salt);
}

void TxReconciliationTracker::ForgetPeer(NodeId peer_id)
Expand Down
13 changes: 7 additions & 6 deletions src/node/txreconciliation.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ static constexpr bool DEFAULT_TXRECONCILIATION_ENABLE{false};
/** Supported transaction reconciliation protocol version */
static constexpr uint32_t TXRECONCILIATION_VERSION{1};

enum ReconciliationRegisterResult {
NOT_FOUND = 0,
SUCCESS = 1,
PROTOCOL_VIOLATION = 2,
enum class ReconciliationRegisterResult {
NOT_FOUND,
SUCCESS,
ALREADY_REGISTERED,
PROTOCOL_VIOLATION,
};

/**
Expand Down Expand Up @@ -72,8 +73,8 @@ class TxReconciliationTracker
* Step 0. Once the peer agreed to reconcile txs with us, generate the state required to track
* ongoing reconciliations. Must be called only after pre-registering the peer and only once.
*/
ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound, bool is_peer_recon_initiator,
bool is_peer_recon_responder, uint32_t peer_recon_version, uint64_t remote_salt);
ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound,
uint32_t peer_recon_version, uint64_t remote_salt);

/**
* Attempts to forget txreconciliation-related state of the peer (if we previously stored any).
Expand Down
4 changes: 1 addition & 3 deletions src/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,7 @@ extern const char* GETCFCHECKPT;
*/
extern const char* CFCHECKPT;
/**
* 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.
* Contains a 4-byte version number and an 8-byte salt.
* The salt is used to compute short txids needed for efficient
* txreconciliation, as described by BIP 330.
*/
Expand Down
Loading

0 comments on commit 38a16a2

Please sign in to comment.