zips/drafts/bitcartel-nu0-network-hands.../draft.rst

221 lines
8.8 KiB
ReStructuredText
Raw Normal View History

2018-01-22 21:27:45 -08:00
::
ZIP: ???
Title: Network Upgrade Zero ("OverWinter") Network Handshake
Author: Simon Liu <simon@z.cash>
Comments-Summary: No comments yet.
Category: Process
Created: 2018-01-15
License: MIT
Terminology
===========
The key words "MUST", "MUST NOT", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119.
"Legacy" - pre-NU0
"NU0" - Network upgade zero
"Overwinter" - Code-name for NU0
Abstract
========
This proposal defines an upgrade to network handshake format required for Network Upgrade Activation Mechanism [#zip-0???]_.
Related to [#zip-0143]_
Motivation
==========
2018-02-06 16:09:01 -08:00
With scheduled network upgrades, at the activation height, nodes on each branch should disconnect from nodes on other branches and only accept new incoming connections from nodes on the same branch.
2018-01-22 21:27:45 -08:00
Specification
=============
2018-02-06 16:09:01 -08:00
When a new inbound connection is received or an outbound connection created, a CNode object is instantiated with the version field set to INIT_PROTO_VERSION which has a value of 209. This value is not transmitted across the network, but for legacy reasons and technical debt beyond the scope of this ZIP, this value will not be changed.
2018-01-22 21:27:45 -08:00
2018-02-06 16:09:01 -08:00
Once the two nodes have connected and started the handshake to negotiate the protocol version, the version field of CNode will be updated. The handshake involves "version" and "verack" messages being exchanged.::
2018-01-22 21:27:45 -08:00
L -> R: Send version message with the local peer's version
R -> L: Send version message back
R -> L: Send verack message
R: Sets version to the minimum of the 2 versions
L -> R: Send verack message after receiving version message from R
L: Sets version to the minimum of the 2 versions
2018-02-06 16:09:01 -08:00
Source: https://en.bitcoin.it/wiki/Version_Handshake
2018-01-22 21:27:45 -08:00
To send a version message, the node will invoke PushVersion()::
2018-02-06 16:09:01 -08:00
void CNode::PushVersion() {
...
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
...
}
2018-01-22 21:27:45 -08:00
Where:
2018-02-06 16:09:01 -08:00
- Pre-Overwinter PROTOCOL_VERSION is 170002
- OVERWINTER_PROTO_VERSION is 170003
2018-01-22 21:27:45 -08:00
2018-02-06 16:09:01 -08:00
Rejecting Pre-Overwinter Connections
------------------------------------
2018-01-22 21:27:45 -08:00
2018-02-06 16:09:01 -08:00
Currently, nodes will reject connections from nodes with a protocol version lower than the other node's minimum supported protocol version.
This value is defined as::
2018-01-22 21:27:45 -08:00
//! disconnect from peers older than this proto version
static const int MIN_PEER_PROTO_VERSION = 170002;
2018-02-08 00:42:51 -08:00
With rejection implemented as::
2018-01-22 21:27:45 -08:00
if (pfrom->nVersion < MIN_PEER_PROTO_VERSION)
{
// disconnect from old peers running protocol version we don't support.
Prior to activation, Overwinter nodes will contain the following constants::
static const int PROTOCOL_VERSION = 170003;
static const int MIN_PEER_PROTO_VERSION = 170002;
2018-02-06 16:09:01 -08:00
This allows pre-Overwinter nodes (which only supports protocol version 170002) and Overwinter nodes (which support both 170002 and 170003) to remain connected prior to activation.
2018-01-22 21:27:45 -08:00
2018-02-08 00:42:51 -08:00
These values cannot be changed at run-time, so when Overwinter activates, Overwinter nodes should take steps to:
2018-01-22 21:27:45 -08:00
2018-02-06 16:09:01 -08:00
- reject new connections from pre-Overwinter nodes
- disconnect any existing conncetions to pre-Overwinter nodes
2018-01-22 21:27:45 -08:00
Network Coalescence
-------------------
Prior to the activation of Overwinter, nodes running pre-Overwinter protocol version 170002 and the Overwinter protocol version 170003 remain connected with the same consensus rules, but it would be preferable for nodes supporting Overwinter to connect to other nodes supporting Overwinter.
2018-02-08 00:42:51 -08:00
This would help the network partition smoothly, since nodes should already be connected to (a majority of) peers running the same protocol version. Otherwise an Overwinter node may find their connections to legacy nodes droppedsuddenly at the activation height, potentiallyleaving them isolated and susceptible to eclipse attacks. [link]
2018-01-22 21:27:45 -08:00
To assist network coalescence before the activation height, we update the eviction process to place a higher priority on evicting legacy nodes.
2018-02-08 00:42:51 -08:00
Currently, an eviction process takes place when new inbound connections arrive, but the node has already connected to the maximum number of inbound peers::
2018-01-22 21:27:45 -08:00
2018-02-08 00:42:51 -08:00
if (nInbound >= nMaxInbound)
{
if (!AttemptToEvictConnection(whitelisted)) {
// No connection to evict, disconnect the new connection
LogPrint("net", "failed to find an eviction candidate - connection dropped (full)\n");
CloseSocket(hSocket);
return;
}
}
We update this process by adding behaviour so that the set of eviction candidates will prefer pre-Overwinter node, when the chain tip is in a period N blocks before the activation block height, where N is defined as::
static const int NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD = 1000.
2018-01-22 21:27:45 -08:00
2018-02-08 00:42:51 -08:00
The eviction candidates can be modified as so::
2018-01-22 21:27:45 -08:00
static bool AttemptToEvictConnection(bool fPreferNewConnection) {
...
// Protect connections with certain characteristics
...
2018-02-08 00:42:51 -08:00
// Check version of eviction candidates...
// If we are connected to any pre-Overwinter nodes, keep them in the eviction set and remove any Overwinter nodes
// If we are only connected to Overwinter nodes, continue with existing behaviour.
if ((height < nActivationHeight) &&
(height >= (nActivationHeight - NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD)))
{
// Find any nodes which don't support Overwinter protocol version
BOOST_FOREACH(const CNodeRef &node, vEvictionCandidates) {
if (node->nVersion < OVERWINTER_PROTO_VERSION) {
vTmpEvictionCandidates.push_back(node);
}
}
2018-01-22 21:27:45 -08:00
2018-02-08 00:42:51 -08:00
// Prioritize these nodes by replacing eviction set with them
if (vTmpEvictionCandidates.size() > 0) {
vEvictionCandidates = vTmpEvictionCandidates;
}
}
2018-01-22 21:27:45 -08:00
2018-02-08 00:42:51 -08:00
The existing method of disconnecting a candidate remains:
vEvictionCandidates[0]->fDisconnect = true;
The existing eviction process also classifies and divides eviction candidates into groups. If a group only has one peer, it will not be evicted. This means at least one pre-Overwinter node should remain connected upto the activation block height, barring any network issues or a high ban score.
2018-01-22 21:27:45 -08:00
2018-02-08 00:42:51 -08:00
Disconnecting Existing Connections
----------------------------------
2018-01-22 21:27:45 -08:00
2018-02-08 00:42:51 -08:00
At the activation block height, an Overwinter node may still remain connected to pre-Overwinter nodes. Currently, when connecting, a node can only perform the networking handshake once, where it sends the version message before any other messages are processed. To disconnect existing pre-Overwinter connections, ProcessMessage is modified so that once Overwinter activates, the protocol version of a peer is always checked when processing inbound messages.
2018-01-22 21:27:45 -08:00
Example code::
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived)
...
else if (pfrom->nVersion == 0)
{
// Must have a version message before anything else
Misbehaving(pfrom->GetId(), 1);
return false;
}
else if (strCommand == "verack")
{
...
}
// Disconnect existing connection if:
// 1. The version message has been received
// 2. Overwinter is active
// 3. Version is legacy
else if (
pfrom->nVersion != 0 &&
isOverwinterActivated() &&
pfrom->nVersion < OVERWINTER_PROTO_VERSION )
{
LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion);
pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE,
strprintf("Version must be %d or greater", OVERWINTER_PROTO_VERSION));
pfrom->fDisconnect = true;
return false;
}
Deployment
==========
This proposal will be deployed with the Overwinter network upgrade.
Testnet:
Mainnet:
Backward compatibility
======================
2018-02-08 00:42:51 -08:00
This proposal intentionally creates what is known as a hard fork where Overwinter nodes disconnect from pre-Overwinter nodes.
Prior to the network upgrade activating, Overwinter and pre-Overwinter nodes are compatible and can connect to each other. However, Overwinter nodes will have a preference for connecting to other Overwinter nodes, so pre-Overwinter nodes will gradually be disconnected in the run up to activation.
Once the network upgrades, even though pre-Overwinter nodes can still accept the numerically larger protocol version used by Overwinter as being valid, Overwinter nodes will always disconnect peers using lower protocol versions.
2018-01-22 21:27:45 -08:00
Reference Implementation
========================
TBC
References
==========
Partition nodes with old protocol version from network in advance of hard fork https://github.com/zcash/zcash/issues/2775
https://en.bitcoin.it/wiki/Protocol_documentation#version
.. [#zip-0???] Network Upgrade Activation Mechanism