Hi Suhas,
Thank you for this proposal. I agree with your aims, but I think a new
P2P message isn't necessary to achieve them.
# Motivation
There are two distinct (but interacting) motivations:
1. Allow a node to accept more incoming connections which will only be
used for block propagation (no transaction relay or addr gossip),
while minimizing resource requirements.
2. Prevent `addr` gossip messages from being sent to peers which will
'black hole' those addrs (i.e. not relay them further).
These motivations interact because if we simply increase the number of
block-relay-only connections that nodes make without making any
allowance for the fact those connections won't gossip addr records, then
we'll increase the number of addr black holes and worsen addr gossip.
# Using fRelay=false to signal no transaction relay.
`fRelay` is an optional field in the `version` message. There are three
BIPs concerned with `fRelay`:
- BIP 37[1] introduced the `fRelay` field to indicate to the recipient
that they must not relay transactions over the connection until a
`filteradd` message has been received.
- BIP 60[2] aimed to make the `fRelay` field mandatory. It is not clear
how widely this BIP has been adopted by implementations.
- BIP 111[3] introduced a `NODE_BLOOM` service bit to indicate that
bloom filters are served by this node. According to this BIP, "If a
node does not support bloom filters but receives a "filterload",
"filteradd", or "filterclear" message from a peer the node should
disconnect that peer immediately."
Within Bitcoin Core:
- PR 1795[4] (merged in January 2013) added support for BIP 37 Bloom
filters.
- Since PR 2763[5] (merged in June 2013), Bitcoin Core will _always_
include the `fRelay` flag in `version` messages that it sends. Bitcoin
Core will tolerate the `fRelay` field being present or absent in any
`version` message that it receives[6].
- PR 6579[7] (merged in August 2015) implemented BIP 111. From that
point on, a Bitcoin Core node would disconnect peers that sent it
`filter*` messages if it hadn't enabled `NODE_BLOOM`, provided the
peer's version was >= 70011. In PR 7708[8] (merged in March 2016) this
was extended to disconnect any peer that sends a `filter*` message,
regardless of its version (in general, a 'polite disconnect' for any
peer that requests an unsupported service is probably the best
behaviour). In PR 16152[9] (merged in July 2019), serving Bloom
filters was disabled by default, due to potential denial-of-service
attacks being possible against nodes which serve bloom filters on
public connections.
- PR 6993[10] (merged in November 2015) started reusing the `fRelay`
field for the new `-blocksonly` mode. If Bitcoin Core is started with
`-blocksonly` configured, then it includes `fRelay=false` in all of
the `version` messages it sends. In PR 15759[11] (merged in September
2019), this usage of `fRelay` to permanently disable tx relay was
extended for use by the new block-relay only connection type.
The net effect is that `fRelay` is already being used to indicate that
transactions should not be relayed over a connection. In the motivation
for your BIP, you write:
> The low-bandwidth / minimal-resource nature of these connections is
> currently known only by the initiator of the connection; this is
> because the transaction relay field in the version message is not a
> permanent setting for the lifetime of the connection. Consequently, a
> node receiving an inbound connection with transaction relay disabled
> cannot distinguish between a peer that will never enable transaction
> relay (as described in BIP 37) and one that will...
However, as AJ points out in his response [12], the Bitcoin Core node
_does_ know whether transaction relay can be supported as soon as the
`version` message is received:
> [...] you either set m_tx_relay->fRelayTxes to true via the VERSION
> message (either explicitly or by not setting fRelay), or you enable it
> later with FILTERLOAD or FILTERCLEAR, both of which will cause a
> disconnect if bloom filters aren't supported. Bloom filter support is
> (optionally?) indicated via a service bit (BIP 111), so you could
> assume you know whether they're supported as soon as you receive the
> VERSION line.
i.e. if Bitcoin Core node is running under normal configuration with
bloom filters disabled for public connections (which is both the default
setting and highly recommended due to DoS concerns), then as soon as it
receives a `version` message with `fRelay=false`, it can be sure that
there will never be any transaction relay with that peer. If the peer
later tries to enable transaction relay by sending a `filterload`
message, then the node will disconnect that peer immediately.
In summary, we can continue using the `fRelay` field to indicate that
no transaction relay can happen for the entire lifetime of the
connection. Bitcoin Core can postpone allocating resources for
transaction relay data structures until after the version message has
been received to minimize resource usage for incoming block-relay-only
connections. A rough implementation is here[13]. Obviously, a node that
has been configured to serve bloom filters on public connections would
not be able to take advantage of this and accept additional incoming
block-relay-only peers, but I think that's fine - we already discourage
that configuration.
I think a good counter-argument against simply using `fRelay` for this
purpose is that we shouldn't reuse a protocol feature designed for one
function to achieve a totally different aim. However, we know that nodes
on the network have been using `fRelay` to disable transaction relay
since Bitcoin Core version 0.12 (when `-blocksonly` was added), and that
usage was expanded to _all_ nodes running Bitcoin Core version 0.19 or
later (when block-relay-only connections were introduced), so using
`fRelay` to disable transaction relay is now de facto part of the p2p
protocol.
# Preventing addr black holes
Addresses of potential peers are gossiped around the p2p network using
`addr` messages. When a Bitcoin Core node learns of a new `addr` record,
it will relay that record to one or two of its peers, chosen at
random[14]. The idea is that eventually the `addr` record will reach
most of the nodes on the network.
If there are too many nodes on the network that receive `addr` records
and do not relay those records on to their peers (termed _addr black
hole_ nodes), then propagation of those `addr` records suffers -- any
individual `addr` record is unlikely to reach a large proportion of
nodes on the network.
Since a motivation for block-relay-only connections is to protect
against eclipse attacks and thwart network topology analysis, Bitcoin
Core will not relay `addr` records on those connections, and will ignore
any `addr` record received over those connections. Therefore, increasing
the number of block-relay-only connections without changing the `addr`
gossip logic is likely to increase the prevalence of addr black holes,
and negatively impact addr propagation. This is why BIP 338 includes:
> It is RECOMMENDED that a node that has sent or received a disabletx
> message to/from a peer not send any of these messages to the peer:
>
> - addr/getaddr
> - addrv2 (BIP 155)
I think a better approach would be for Bitcoin Core to only relay addr
records to an inbound peer if it has previously received an `addr` or
`addrv2` message from that peer, since that indicates definitively that
the peer actively gossips `addr` records. This approach was first
suggested by AJ in the original block-relay-only PR[15].
An advantage of this approach is that it will improve addr propagation
immediately and without any change to the P2P protocol, and will prevent
sending `addr` records to all addr black holes (such as light clients),
not just incoming block-relay-only connections.
# Conclusion
We can increase the permitted number of inbound block-relay-only peers
while minimizing resource requirement _and_ improving addr record
propagation, without any changes to the p2p protocol required.
I propose that for Bitcoin Core version 22.0:
- only initialize the transaction relay data structures after the
`version` message is received, and only if fRelay=true and
`NODE_BLOOM` is not offered on this connection.
- only initialize the addr data structures for inbound connections when
an `addr`, `addrv2` or `getaddr` message is received on the
connection, and only consider a connection for addr relay if its addr
data structures are initialized.
- update the inbound eviction logic to protect more inbound peers which
do not have transaction relay data structures.
Then, in version 23.0:
- modestly increase the number of outbound block-relay-only connections.
John
[1]
https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki[2]
https://github.com/bitcoin/bips/blob/master/bip-0060.mediawiki[3]
https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki[4]
https://github.com/bitcoin/bitcoin/pull/1795[5]
https://github.com/bitcoin/bitcoin/pull/2763[6]
https://github.com/bitcoin/bitcoin/blob/e49117470b77fb7d53be122c6490ba163c6e304d/src/net_processing.cpp#L2582-L2583[7]
https://github.com/bitcoin/bitcoin/pull/6579[8]
https://github.com/bitcoin/bitcoin/pull/7708[9]
https://github.com/bitcoin/bitcoin/pull/16152[10]
https://github.com/bitcoin/bitcoin/pull/6993[11]
https://github.com/bitcoin/bitcoin/pull/15759[12]
https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-January/018347.html[13]
https://github.com/jnewbery/bitcoin/tree/2021-02-lazy-init-peer[14]
https://github.com/bitcoin/bitcoin/blob/e52ce9f2b312b3cf3b0837918e07d7603e241d63/src/net_processing.cpp#L1696-L1700[15]
https://github.com/bitcoin/bitcoin/pull/15759#issuecomment-527012757> Hi,
>
> I'm proposing the addition of a new, optional p2p message to allow peers to communicate that they do not want to send or receive (loose) transactions for the lifetime of a connection.
>
> The goal of this message is to help facilitate connections on the network over which only block-related data (blocks/headers/compact blocks/etc) are relayed, to create low-resource connections that help protect against partition attacks on the network. In particular, by adding a network message that communicates that transactions will not be relayed for the life of the connection, we ease the implementation of software that could have increased inbound connection limits for such peers, which in turn will make it easier to add additional persistent block-relay-only connections on the network -- strengthening network security for little additional bandwidth.
>
> Software has been deployed for over a year now which makes such connections, using the BIP37/BIP60 "fRelay" field in the version message to signal that transactions should not be sent initially. However, BIP37 allows for transaction relay to be enabled later in the connection's lifetime, complicating software that would try to distinguish inbound peers that will never relay transactions from those that might.
>
> This proposal would add a single new p2p message, "disabletx", which (if used at all) must be sent between version and verack. I propose that this message is valid for peers advertising protocol version 70017 or higher. Software is free to implement this BIP or ignore this message and remain compatible with software that does implement it.
>
> Full text of the proposed BIP is below.
>
> Thanks,
> Suhas
>
> ---------------------------------------------------
>
> <pre>
> BIP: XXX
> Layer: Peer Services
> Title: Disable transaction relay message
> Author: Suhas Daftuar <
sdaftuar@chaincode.com>
> Comments-Summary: No comments yet.
> Comments-URI:
> Status: Draft
> Type: Standards Track
> Created: 2020-09-03
> License: BSD-2-Clause
> </pre>
>
> ==Abstract==
>
> This BIP describes a change to the p2p protocol to allow a node to tell a peer
> that a connection will not be used for transaction relay, to support
> block-relay-only connections that are currently in use on the network.
>
> ==Motivation==
>
> For nearly the past year, software has been deployed[1] which initiates
> connections on the Bitcoin network and sets the transaction relay field
> (introduced by BIP 37 and also defined in BIP 60) to false, to prevent
> transaction relay from occurring on the connection. Additionally, addr messages
> received from the peer are ignored by this software.
>
> The purpose of these connections is two-fold: by making additional
> low-bandwidth connections on which blocks can propagate, the robustness of a
> node to network partitioning attacks is strengthened. Additionally, by not
> relaying transactions and ignoring received addresses, the ability of an
> adversary to learn the complete network graph (or a subgraph) is reduced[2],
> which in turn increases the cost or difficulty to an attacker seeking to carry
> out a network partitioning attack (when compared with having such knowledge).
>
> The low-bandwidth / minimal-resource nature of these connections is currently
> known only by the initiator of the connection; this is because the transaction
> relay field in the version message is not a permanent setting for the lifetime
> of the connection. Consequently, a node receiving an inbound connection with
> transaction relay disabled cannot distinguish between a peer that will never
> enable transaction relay (as described in BIP 37) and one that will. Moreover,
> the node also cannot determine that the incoming connection will ignore relayed
> addresses; with that knowledge a node would likely choose other peers to
> receive announced addresses instead.
>
> This proposal adds a new, optional message that a node can send a peer when
> initiating a connection to that peer, to indicate that connection should not be
> used for transaction-relay for the connection's lifetime. In addition, without
> a current mechanism to negotiate whether addresses should be relayed on a
> connection, this BIP suggests that address messages not be sent on links where
> tx-relay has been disabled.
>
> ==Specification==
>
> # A new disabletx message is added, which is defined as an empty message where pchCommand == "disabletx".
> # The protocol version of nodes implementing this BIP must be set to 70017 or higher.
> # If a node sets the transaction relay field in the version message to a peer to false, then the disabletx message MAY also be sent in response to a version message from that peer if the peer's protocol version is >= 70017. If sent, the disabletx message MUST be sent prior to sending a verack.
> # A node that has sent or received a disabletx message to/from a peer MUST NOT send any of these messages to the peer:
> ## inv messages for transactions
> ## getdata messages for transactions
> ## getdata messages for merkleblock (BIP 37)
> ## filteradd/filterload/filterclear (BIP 37)
> ## mempool (BIP 35)
> # It is RECOMMENDED that a node that has sent or received a disabletx message to/from a peer not send any of these messages to the peer:
> ## addr/getaddr
> ## addrv2 (BIP 155)
> # The behavior regarding sending or processing other message types is not specified by this BIP.
> # Nodes MAY decide to not remain connected to peers that send this message (for example, if trying to find a peer that will relay transactions).
>
> ==Compatibility==
>
> Nodes with protocol version >= 70017 that do not implement this BIP, and nodes
> with protocol version < 70017, will continue to remain compatible with
> implementing software: transactions would not be relayed to peers sending the
> disabletx message (provided that BIP 37 or BIP 60 has been implemented), and while
> periodic address relay may still take place, software implementing this BIP
> should not be disconnecting such peers solely for that reason.
>
> Disabling address relay is suggested but not required by this BIP, to allow for
> future protocol extensions that might specify more carefully how address relay
> is to be negotiated. This BIP's recommendations for software to not relay
> addresses is intended to be interpreted as guidance in the absence of any such
> future protocol extension, to accommodate existing software behavior.
>
> Note that all messages specified in BIP 152, including blocktxn and
> getblocktxn, are permitted between peers that have sent/received a disabletx
> message, subject to the feature negotiation of BIP 152.
>
> ==Implementation==
>
> TBD
>
> ==References==
>
> # Bitcoin Core has [
https://github.com/bitcoin/bitcoin/pull/15759 implemented this functionality] since version 0.19.0.1, released in November 2019.
> # For example, see
https://www.cs.umd.edu/projects/coinscope/coinscope.pdf and
https://arxiv.org/pdf/1812.00942.pdf.
>
> ==Copyright==
>
> This BIP is licensed under the 2-clause BSD license.