How do nodes tell each other which features they support?How do nodes tell each other which features they support?
Looking at Clark Moody's Dashboard, there are nodes running 15 different versions of Bitcoin Core and 4 different versions of Knots. While all these nodes can sync to the same most recent block, some of them may have slightly different features than the others.
For instance, the new short-lived tor/I2P connections for broadcasting transactions feature (#1412523) is really cool, but if someone else is running a Bitcoin Core version earlier than 22, their node won't understand what I2P is. Their node might disconnect from you if you try to open an I2P connection with it. There needs to be some way for my node to talk to other nodes and discover what features they support so that nodes don't send messages other nodes don't understand.
The way this has been handled so far is via nodes telling each other their protocolversion number. A protocolversion is not the same as the version number of the software. For instance, Core v28 returns the protocolversion number 70016.
The problem with this system is that all the different people working on node software have to coordinate what each protocolversion number means. Additionally, there is an expectation that for any given protocolversion number, the node will support all previous features. Perhaps the node implementation doesn't want to implement a particular older feature. Things can get clunky pretty quickly.
Also, many versions of node software have set up requirements for minimum a protocolversion to avoid connecting to old nodes that don't support the same features and that will later disconnect from them when they receive messages they don't understand.
In a worst case scenario this could lead to the network splitting into separate networks when a new feature is released and older nodes that don't support the feature don't make connections with the new nodes. Network partitions are bad.
Enter BIP 434: Peer Feature NegotiationEnter BIP 434: Peer Feature Negotiation
With BIP 434, @ajtowns is proposing a new way of doing p2p feature announcements and negotiations. This new way would no longer rely on a protocolversion number, instead allowing nodes to send "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...without concerns of being unnecessarily disconnected by a peer which doesn't understand the messages, and without needing to coordinate updating the protocol version.
This seems like a pretty efficient way to get nodes to understand what kinds of messages they can send to each other without getting disconnected.
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 one-byte message_type, the overhead compared to that approach is also kept small.
If you're interested in learning more:If you're interested in learning more:
- BIP draft: BIP 434: Peer Feature Negotiation
- Bitcoin development mailing list post: https://groups.google.com/g/bitcoindev/c/DFXtbUdCNZE
There hasn't been a whole lot of discussion about this idea yet (no responses on the mailing list), but there are a few comments on the PR.
wondering: what happens to
servicesin theversionmessage long-term.The services flags indicate which optional peer services a node offers which is different from whether nodes understand a protocol feature. I would expect that they continue to get used.
OTOH, if BIP 434 is adopted, the protocol version might not need to be bumped further after the bump for BIP 434.
So signalling if your node is a pruned node is something that is a service flag, while the things covered by BIP 434 might be more like does your node know how to support encrypted transport?
I think that's a bad example because of how that protocol initializes from the first byte, but I guess that
feefilterandaddrv2would be good examples.Ah, I was worried that my short lived I2P example was also bad. Thanks for sharing the other examples!
Because you mention it, yes, I'm quite sure that it is, because you either have a listening i2p interface or you don't, but I didn't feel like dwelling on it, haha.
Yeah, that I2P example felt a bit off-base. Nodes self-announce their (network-respective) address for each network they support to each peer after establishing a connection, i.e., on clearnet, a node will announce its clearnet address to peers. Such peers may then forward the address when they get asked for a batch of addresses by another node. I don’t remember whether nodes only gossip addresses of the respective network on each network, or whether they generally gossip addresses from all addresses (probably the latter?), but a node that doesn’t use I2P wouldn’t announce an I2P address, so we’d never try to connect to it with I2P.
Good write up on a real P2P pain point explicit feature negotiation feels like a much cleaner, safer path than constant protocol version bumps.