mirror of
https://github.com/bitcoin/bips.git
synced 2026-02-09 15:23:09 +00:00
Merge pull request #2076 from ajtowns/202512-p2p-feature
BIP 434: Peer Feature Negotiation
This commit is contained in:
commit
3177af3bbf
@ -1367,6 +1367,13 @@ users (see also: [https://en.bitcoin.it/wiki/Economic_majority economic majority
|
||||
| Informational
|
||||
| Draft
|
||||
|-
|
||||
| [[bip-0434.md|434]]
|
||||
| Peer Services
|
||||
| Peer Feature Negotiation
|
||||
| Anthony Towns
|
||||
| Specification
|
||||
| Draft
|
||||
|-
|
||||
| [[bip-0443.mediawiki|443]]
|
||||
| Consensus (soft fork)
|
||||
| OP_CHECKCONTRACTVERIFY
|
||||
|
||||
320
bip-0434.md
Normal file
320
bip-0434.md
Normal file
@ -0,0 +1,320 @@
|
||||
```
|
||||
BIP: 434
|
||||
Layer: Peer Services
|
||||
Title: Peer Feature Negotiation
|
||||
Authors: Anthony Towns <aj@erisian.com.au>
|
||||
Status: Draft
|
||||
Type: Specification
|
||||
Assigned: 2026-01-14
|
||||
License: BSD-3-Clause
|
||||
Discussion: 2025-12-19: https://gnusha.org/pi/bitcoindev/aUUXLgEUCgGb122o@erisian.com.au/T/#u
|
||||
2020-08-21: https://gnusha.org/pi/bitcoindev/20200821023647.7eat4goqqrtaqnna@erisian.com.au/
|
||||
Version: 0.1.0
|
||||
```
|
||||
|
||||
## Abstract
|
||||
|
||||
This BIP defines a peer-to-peer (P2P) message that can be used for
|
||||
announcements and negotiation related to support of new peer-to-peer
|
||||
features.
|
||||
|
||||
## Motivation
|
||||
|
||||
Historically, new peer-to-peer protocol changes have been tied to
|
||||
bumping the protocol version, so that nodes know to only attempt
|
||||
feature negotiation with peers that support the feature. Coordinating
|
||||
the protocol version across implementations, when different clients may
|
||||
have different priorities for features to implement, is an unnecessary
|
||||
burden in the upgrade process for P2P features that do not require
|
||||
universal support. And at a more philosophical level, having the P2P
|
||||
protocol be [permissionlessly extensible][permless-extensible], with no
|
||||
coordination required between implementations or developers, seems ideal
|
||||
for a decentralized system.
|
||||
|
||||
Many earlier P2P protocol upgrades were implemented as new messages
|
||||
sent after a peer connection is set up (ie, after receipt of a `verack`
|
||||
message by both sides). See [BIP 130 (sendheaders)][BIP130], [BIP 133
|
||||
(feefilter)][BIP133], and [BIP 152 (compact blocks)][BIP152] for some
|
||||
examples. However, for some P2P upgrades, it is helpful to perform
|
||||
feature negotiation prior to a connection being fully established
|
||||
(ie, prior to the `verack` being received by both sides). [BIP 155
|
||||
(addrv2)][BIP155] and [BIP 339 (wtxid-relay)][BIP339] are examples of
|
||||
this approach, which involves sending and receiving a single new message
|
||||
(`sendaddrv2` and `wtxidrelay` respectively), in between `version` and
|
||||
`verack` to indicate support of the new feature.
|
||||
|
||||
In all these cases, sending new messages on the network raises the
|
||||
question of what non-implementing software will do with such messages. The
|
||||
common behavior observed on the network was for software to ignore
|
||||
unknown messages received from a peer, so these proposals posed minimal
|
||||
risk of potential network partitioning. In fact, supporting protocol
|
||||
extensibility in this manner was given as an explicit reason to ignore
|
||||
unknown messages in Bitcoin's [first release][0.1-extensibility].
|
||||
|
||||
However, if nodes respond to unknown messages by disconnecting, then
|
||||
the network might partition in the future as incompatible software is
|
||||
deployed. And in fact, some clients on the network have historically
|
||||
discouraged or disallowed unknown messages, both between `version`
|
||||
and `verack` (eg, Bitcoin Core discouraged such messages between
|
||||
[PR#9720][PR#9720] and [PR#19723][PR#19723], and btcd disallowed
|
||||
such messages until [PR#1812][btcd#1812], but see also discussion in
|
||||
[#1661][btcd#1661]), as well as after `verack`.
|
||||
|
||||
To maximise compatibility with such clients, most of these BIPs require
|
||||
that peers bump the protocol version:
|
||||
|
||||
* [BIP 130][BIP130] requires version 70012 or higher,
|
||||
* [BIP 133][BIP133] requires version 70013 or higher,
|
||||
* [BIP 152][BIP152] recommends version 70014/70015 or higher, and
|
||||
* [BIP 339][BIP339] requires version 70016 or higher.
|
||||
|
||||
And while [BIP 155][BIP155] does not specify a minimum protocol version,
|
||||
implementations have [added][PR#20564] a de facto requirement of version
|
||||
70016 or higher.
|
||||
|
||||
In this BIP, we propose codifying and generalising the mechanism used by
|
||||
[BIP 339][BIP339] for future P2P upgrades, by adding a single new feature
|
||||
negotiation message that can be reused for advertising arbitrary new
|
||||
features, and requiring that implementing software ignore unknown features
|
||||
that might be advertised. This allows future upgrades to negotiate new
|
||||
features by exchanging messages prior to exchanging `verack` messages,
|
||||
without concerns of being unnecessarily disconnected by a peer which
|
||||
doesn't understand the messages, and without needing to coordinate
|
||||
updating the protocol version.
|
||||
|
||||
## Specification
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",
|
||||
"RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
|
||||
interpreted as described in RFC 2119.
|
||||
|
||||
For the purposes of this section, `CompactSize` refers to the
|
||||
variable-length integer encoding used across the existing P2P protocol
|
||||
to encode array lengths, among other things, in 1, 3, 5 or 9 bytes. Only
|
||||
`CompactSize` encodings which are minimally-encoded (ie the shortest
|
||||
length possible) are used by this specification.
|
||||
|
||||
Nodes implementing this BIP:
|
||||
|
||||
* MUST advertise a protocol version number `>= 70017`,
|
||||
* MUST NOT send `feature` messages to peers that advertise a protocol
|
||||
version number `< 70017`,
|
||||
* MUST accept `feature` messages received after the `version` message
|
||||
and before the `verack` message, and
|
||||
* MUST NOT send `feature` messages after sending the `verack` message.
|
||||
|
||||
In addition, nodes implementing this BIP:
|
||||
|
||||
* SHOULD ignore unknown messages received after the `version` message
|
||||
and before the `verack` message,
|
||||
* MAY ignore `feature` messages sent after `verack`, and
|
||||
* MAY disconnect peers who send `feature` messages after `verack`.
|
||||
|
||||
Feature specifications based on this BIP:
|
||||
|
||||
* MUST forbid sending messages it introduces after `verack` to a peer
|
||||
that has not indicated support for the feature via a `feature`
|
||||
message.
|
||||
|
||||
### `feature` message
|
||||
|
||||
The payload of the `feature` message contains exactly the following data:
|
||||
|
||||
| Type | Name | Description |
|
||||
| ----------- | ------------- | ----------- |
|
||||
| string | `featureid` | Unique identifier for the feature |
|
||||
| byte-vector | `featuredata` | Feature-specific configuration data |
|
||||
|
||||
The `featureid` is encoded in the usual way, that is, as a `CompactSize`
|
||||
specifying the string length, followed by that many bytes. The string
|
||||
length MUST be between 4 and 80, inclusive. The string SHOULD include
|
||||
only printable ASCII characters (ie, each byte should have a value
|
||||
between 32 and 126, inclusive).
|
||||
|
||||
Likewise, `featuredata` is encoded as a `CompactSize` specifying the
|
||||
byte-vector size, followed by that many bytes. How these bytes are
|
||||
interpreted is part of the feature's specification. The byte-vector size
|
||||
MUST NOT be more than 512 bytes. Note that the `featuredata` field is not
|
||||
optional, so if no data is required, an empty vector should be provided,
|
||||
ie serialized as `CompactSize` of 0.
|
||||
|
||||
Nodes implementing this BIP MUST ignore `feature` messages specifying a
|
||||
`featureid` they do not support, so long as the payload conforms to the
|
||||
requirements above.
|
||||
|
||||
Nodes implementing this BIP MAY disconnect peers that send `feature`
|
||||
messages where the `feature` message's payload cannot be correctly
|
||||
parsed (including having missing or additional data), even if they do
|
||||
not recognise the `featureid`.
|
||||
|
||||
The `featureid` MUST be a globally unique identifier for the feature.
|
||||
For features published as a BIP, the `featureid` SHOULD be the assigned
|
||||
BIP number, eg "BIP434", or be based on the BIP number (eg, "BIP434v2"
|
||||
where the "v2" suffix covers versioning, or "BIP434.3" where the ".3"
|
||||
suffix covers part 3 of the BIP). For experimental features that do not
|
||||
(yet) have a BIP number assigned, some other unique identifier MUST be
|
||||
chosen, such as a URL to the repository where development is taking place,
|
||||
or the sha256 digest of some longer reference.
|
||||
|
||||
Nodes implementing both this BIP and [BIP 324 (v2 P2P encrypted
|
||||
transport)][BIP324] MUST treat a message with a 1-byte `message_type`
|
||||
equal to `XXX` that is received prior to `verack` as the `feature` message.
|
||||
|
||||
### Feature negotiation
|
||||
|
||||
It is RECOMMENDED that feature negotiation be designed and implemented
|
||||
as follows:
|
||||
|
||||
* all `feature` messages and the `verack` message should be sent
|
||||
immediately on receipt of the peer's `version` message
|
||||
* any negotiation calculations should be performed immediately on
|
||||
receipt of the peer's `verack` message
|
||||
|
||||
This structure is fairly easy to implement, and avoids introducing any
|
||||
significant latency that might result from more interactive negotiation
|
||||
methods.
|
||||
|
||||
Feature specifications defining a `featureid` MAY make use of the
|
||||
following approaches:
|
||||
|
||||
#### Feature advertisement:
|
||||
|
||||
1. Send a `feature` message advertising the `featureid` unconditionally
|
||||
2. Accept messages related to the feature unconditionally
|
||||
3. Only send messages defined by the feature if the peer sent
|
||||
a valid `feature` message for the `featureid`.
|
||||
|
||||
This approach is appropriate for many simple features that define
|
||||
new messages, particularly where an implementation might only
|
||||
implement sending or receiving a message, but not both, eg [BIP 35
|
||||
(mempool)][BIP35].
|
||||
|
||||
#### Feature coordination:
|
||||
|
||||
1. Send a `feature` message advertising the `featureid` unconditionally
|
||||
2. Check if the peer sends the same `feature` message (or a compatible
|
||||
one), and enable the feature for this peer if so.
|
||||
3. Only send/accept messages or encode data items according to the
|
||||
feature's specification if the feature is enabled for this peer.
|
||||
|
||||
This approach is appropriate for upgrades to data encoding in
|
||||
P2P messages, eg [BIP 339 (wtxidrelay)][BIP339] or [BIP 155
|
||||
(addrv2)][BIP155].
|
||||
|
||||
#### Feature versioning:
|
||||
|
||||
1. Send `feature` messages for multiple incompatible features, eg
|
||||
`BIP434v3`, `BIP434v2`, `BIP434v1`, ordered from most preferred
|
||||
to least.
|
||||
2. Track the corresponding `feature` messages from your peer.
|
||||
3. If you were the listening peer, enable your highest preference feature
|
||||
that your peer also supports.
|
||||
4. If you were the initiating peer, enable the first feature that your
|
||||
peer announced, that you also support.
|
||||
5. For example if the listening peer sends `BIP434v3`, `BIP434v2`,
|
||||
`BIP434v1`, and the initiating peer sends `BIP434v1`, `BIP434v2`,
|
||||
then the listening peer should select `BIP434v2` when `verack`
|
||||
is received, and the initiating peer should select `BIP434v2`
|
||||
as soon as `feature BIP434v2` is received.
|
||||
6. Conversely, if the initiating peer sends `BIP434v3`, `BIP434v2`,
|
||||
`BIP434v1`, and the listening peer sends `BIP434v1`, `BIP434v2`,
|
||||
then the listening peer should select `BIP434v1` when `verack`
|
||||
is received, and the initiating peer should select `BIP434v1`
|
||||
as soon as `feature BIP434v1` is received.
|
||||
7. In most cases, implementations should simply advertise incompatible
|
||||
features in order from most recent to oldest, on the basis that
|
||||
the only reason to make incompatible updates is because there are
|
||||
significant improvements. Exceptions to that may occur when two
|
||||
incompatible features are both receiving active development, or
|
||||
when an implementation has only partially implemented the latest
|
||||
spec, and the older spec is better supported (and thus should be
|
||||
listed first, as the preferred protocol to adopt).
|
||||
|
||||
This approach may be appropriate when making substantial changes to a
|
||||
deployed protocol and backwards compatibility is desirable on a short-term
|
||||
basis, or when there is disagreement amongst implementations or users
|
||||
as to which approach is most desirable.
|
||||
|
||||
## Considerations
|
||||
|
||||
The advantage this approach has over bumping the protocol version
|
||||
number when introducing new P2P messages or data structures, is that no
|
||||
coordination is required (that is, there is no longer a question whether
|
||||
version "n+1" belongs to Alice's new feature, or Bob's new feature),
|
||||
and there is no implication that supporting each new feature means all
|
||||
prior features are also supported.
|
||||
|
||||
The advantage this approach has over defining new messages for each
|
||||
feature is that the `featureid` can be much longer (at up to 80
|
||||
bytes) than a message type id (which are limited to 12 bytes). With a
|
||||
[BIP 324][BIP324] one-byte `message_type`, the overhead compared to that
|
||||
approach is also kept small.
|
||||
|
||||
This approach is largely equivalent to adding a [payload to the `verack`
|
||||
message][verack-payload] (eg, a vector of `featureid`, `featuredata`
|
||||
pairs). It was chosen because:
|
||||
|
||||
* it retains compatibility with any implementations that expect `verack`
|
||||
to have no payload;
|
||||
* it allows peers to process each feature request individually, rather than
|
||||
having to first load the configuration information for all features into
|
||||
memory at once (in order to validate the message's checksum), and then
|
||||
deal with each feature's configuration;
|
||||
* limiting the maximum message payload size you accept (eg to 4MB)
|
||||
does not limit the number of features you can accept; and
|
||||
* we have experience with negotiating features with individual messages,
|
||||
but no experience with doing so via `verack` payload.
|
||||
|
||||
A mild disadvantage compared to using a `verack` payload is that this
|
||||
approach allows the possibility of interactive feature negotiation prior
|
||||
to `verack`. However interactive feature negotiation is always possible
|
||||
simply by having the initiating peer disconnect and reconnect after
|
||||
discovering the listening peer's supported features.
|
||||
|
||||
This specification attempts to maximise compatibility with implementations
|
||||
that prefer to fully validate each message received:
|
||||
|
||||
* `feature` messages, even for unknown features, must always be fully
|
||||
parseable into a `featureid` and `featuredata`
|
||||
* Ignoring unknown messages prior to `verack` is only a recommendation,
|
||||
not a requirement, so compliant implementations may disconnect on an
|
||||
unknown message that cannot be validated.
|
||||
* Sending unknown messages after `verack` is explicitly forbidden,
|
||||
in so far as that is possible.
|
||||
|
||||
## Backward compatibility
|
||||
|
||||
Clients specifying a version number prior to `70017` remain fully
|
||||
compatible with this change.
|
||||
|
||||
Clients specifying a version number of `70017` or higher that do not
|
||||
implement this BIP remain fully compatible provided they do not disconnect
|
||||
peers upon receiving unexpected messages received between `version` and
|
||||
`verack`.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Much of the logic here, and much of the text in the motivation section,
|
||||
is based on Suhas Daftuar's 2020 post on [Generalizing feature
|
||||
negotiation][suhas-draft].
|
||||
|
||||
## Copyright
|
||||
|
||||
This BIP is licensed under the 2-clause BSD license.
|
||||
|
||||
[BIP130]: https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki
|
||||
[BIP133]: https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki
|
||||
[BIP152]: https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
|
||||
[BIP155]: https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki
|
||||
[BIP339]: https://github.com/bitcoin/bips/blob/master/bip-0339.mediawiki
|
||||
[BIP35]: https://github.com/bitcoin/bips/blob/master/bip-0035.mediawiki
|
||||
[BIP324]: https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki
|
||||
[verack-payload]: https://gnusha.org/pi/bitcoindev/B514142F-382B-4D49-B68D-0115ECBD1D79@voskuil.org/
|
||||
[PR#20564]: https://github.com/bitcoin/bitcoin/pull/20564
|
||||
[PR#9720]: https://github.com/bitcoin/bitcoin/pull/9720
|
||||
[PR#19723]: https://github.com/bitcoin/bitcoin/pull/19723
|
||||
[btcd#1812]: https://github.com/btcsuite/btcd/pull/1812
|
||||
[btcd#1661]: https://github.com/btcsuite/btcd/issues/1661
|
||||
[permless-extensible]: https://github.com/bitcoin/bitcoin/pull/20564#issuecomment-738456560
|
||||
[0.1-extensibility]: https://github.com/benjiqq/bitcoinArchive/blob/master/bitcoin0.1/src/main.cpp#L2035-L2039
|
||||
[suhas-draft]: https://gnusha.org/pi/bitcoindev/CAFp6fsE=HPFUMFhyuZkroBO_QJ-dUWNJqCPg9=fMJ3Jqnu1hnw@mail.gmail.com/
|
||||
Loading…
x
Reference in New Issue
Block a user