mirror of https://github.com/zcash/zips.git
271 lines
19 KiB
HTML
271 lines
19 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<title>ZIP 201: Network Peer Management for Overwinter</title>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="css/style.css"></head>
|
||
<body>
|
||
<section>
|
||
<pre>ZIP: 201
|
||
Title: Network Peer Management for Overwinter
|
||
Owners: Daira Hopwood <daira@electriccoin.co>
|
||
Original-Authors: Simon Liu
|
||
Status: Final
|
||
Category: Network
|
||
Created: 2018-01-15
|
||
License: MIT</pre>
|
||
<section id="terminology"><h2><span class="section-heading">Terminology</span><span class="section-anchor"> <a rel="bookmark" href="#terminology"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h2>
|
||
<p>The key words "MUST", "MUST NOT", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119. <a id="id1" class="footnote_reference" href="#rfc2119">1</a></p>
|
||
<p>The terms "consensus branch" and "network upgrade" in this document are to be interpreted as described in IP 200. <a id="id2" class="footnote_reference" href="#zip-0200">3</a></p>
|
||
<p>The terms below are to be interpreted as follows:</p>
|
||
<dl>
|
||
<dt>Overwinter</dt>
|
||
<dd>Code-name for the first Zcash network upgrade, also known as Network Upgrade Zero.</dd>
|
||
</dl>
|
||
</section>
|
||
<section id="abstract"><h2><span class="section-heading">Abstract</span><span class="section-anchor"> <a rel="bookmark" href="#abstract"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h2>
|
||
<p>This proposal defines an upgrade to the network handshake and peer management required for network upgrades following the Network Upgrade Mechanism <a id="id3" class="footnote_reference" href="#zip-0200">3</a>.</p>
|
||
<p>Related to:</p>
|
||
<ul>
|
||
<li>Transaction Signature Validation for Overwinter <a id="id4" class="footnote_reference" href="#zip-0143">2</a>.</li>
|
||
<li>Version 3 Transaction Format for Overwinter <a id="id5" class="footnote_reference" href="#zip-0202">4</a>.</li>
|
||
<li>Transaction Expiry <a id="id6" class="footnote_reference" href="#zip-0203">5</a>.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="motivation"><h2><span class="section-heading">Motivation</span><span class="section-anchor"> <a rel="bookmark" href="#motivation"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h2>
|
||
<p>With scheduled network upgrades, at the activation height, nodes on each consensus branch should disconnect from nodes on other consensus branches and only accept new incoming connections from nodes on the same consensus branch.</p>
|
||
</section>
|
||
<section id="specification"><h2><span class="section-heading">Specification</span><span class="section-anchor"> <a rel="bookmark" href="#specification"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h2>
|
||
<p>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.</p>
|
||
<p>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 <a id="id7" class="footnote_reference" href="#bitcoin-version-handshake">8</a> involves "version" and "verack" messages being exchanged.:</p>
|
||
<pre>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</pre>
|
||
<p>To send a version message, the node will invoke <code>PushVersion()</code>:</p>
|
||
<pre>void CNode::PushVersion() {
|
||
...
|
||
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, ...);
|
||
...
|
||
}</pre>
|
||
<p>where <code>PROTOCOL_VERSION</code> is the highest protocol version supported by the node.</p>
|
||
<section id="rejecting-pre-overwinter-connections"><h3><span class="section-heading">Rejecting Pre-Overwinter Connections</span><span class="section-anchor"> <a rel="bookmark" href="#rejecting-pre-overwinter-connections"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h3>
|
||
<p>Currently, nodes will reject connections from peers with an advertised protocol version lower than the other node's minimum supported protocol version.</p>
|
||
<p>This value is defined as:</p>
|
||
<pre>//! disconnect from peers older than this proto version
|
||
static const int MIN_PEER_PROTO_VERSION = 170002;</pre>
|
||
<p>With rejection implemented as:</p>
|
||
<pre>if (pfrom->nVersion < MIN_PEER_PROTO_VERSION)
|
||
{
|
||
// disconnect from old peers running protocol version we don't support.</pre>
|
||
<p>Activation of Overwinter will take place first on testnet, and if successful, followed by mainnet.</p>
|
||
<p>To prepare for testnet activation, Overwinter nodes will contain the following constants:</p>
|
||
<pre>static const int PROTOCOL_VERSION = 170003;
|
||
static const int MIN_PEER_PROTO_VERSION = 170002;</pre>
|
||
<p>Nodes running protocol version 170003 have a testnet activation height set, but do not have a mainnet activation height set.</p>
|
||
<p>On testnet, a pre-Overwinter node is defined to be a node for which the highest supported protocol version is <= 170002.</p>
|
||
<p>These constants allow pre-Overwinter nodes that support protocol version 170002, and Overwinter nodes (which support both protocol versions 170002 and 170003 before Overwinter activation) to remain connected until the activation.</p>
|
||
<p>To prepare for mainnet activation, Overwinter nodes will contain the following constants:</p>
|
||
<pre>static const int PROTOCOL_VERSION = 170005;
|
||
static const int MIN_PEER_PROTO_VERSION = 170002;</pre>
|
||
<p>On mainnet, a pre-Overwinter node is defined to be a node for which the highest supported protocol version is <= 170004. (Nodes running protocol version 170003 or 170004 do not have a mainnet activation height set. The intermediate protocol version 170004 is used to indicate support for the <code>NODE_BLOOM</code> service bit defined in <a id="id8" class="footnote_reference" href="#bip-0111">6</a>.)</p>
|
||
<p>These constants allow pre-Overwinter nodes that support protocol versions 170002 to 170004 inclusive, and Overwinter nodes (which support protocol versions 170002 to 170005 inclusive before Overwinter activation) to remain connected until the activation.</p>
|
||
<p>As these constants cannot be changed at run-time, once Overwinter activates on testnet or mainnet, Overwinter nodes should take steps to:</p>
|
||
<ul>
|
||
<li>reject new connections from pre-Overwinter nodes;</li>
|
||
<li>disconnect any existing connections to pre-Overwinter nodes.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="network-coalescence"><h3><span class="section-heading">Network Coalescence</span><span class="section-anchor"> <a rel="bookmark" href="#network-coalescence"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h3>
|
||
<p>Prior to the activation of Overwinter, nodes running a pre-Overwinter protocol version (e.g. 170002) and the Overwinter protocol version (170003 for testnet; 170005 for mainnet) remain connected with the same consensus rules, but it is desirable for nodes supporting Overwinter to connect preferentially to other nodes supporting Overwinter.</p>
|
||
<p>This is intended to 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 Sprout nodes dropped suddenly at the activation height, potentially leaving them isolated and susceptible to eclipse attacks. <a id="id9" class="footnote_reference" href="#eclipse-attack">9</a></p>
|
||
<p>To assist network coalescence before the activation height, we update the eviction process to place a higher priority on evicting Sprout nodes.</p>
|
||
<p>Currently, an eviction process takes place when new inbound connections arrive, but the node has already connected to the maximum number of inbound peers:</p>
|
||
<pre>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;
|
||
}
|
||
}</pre>
|
||
<p>We update this process by adding behaviour so that the set of eviction candidates will prefer pre-Overwinter nodes, when the chain tip is in a period N blocks before the activation block height, where N is defined as:</p>
|
||
<pre>/** The period before a network upgrade activates, where connections to upgrading peers are preferred (in blocks). */
|
||
static const int NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD = 24 * 24 * 3;</pre>
|
||
<p>The eviction candidates can be modified as so:</p>
|
||
<pre>static bool AttemptToEvictConnection(bool fPreferNewConnection) {
|
||
...
|
||
// Protect connections with certain characteristics
|
||
...
|
||
// 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 (nActivationHeight > 0 &&
|
||
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 < params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion) {
|
||
vTmpEvictionCandidates.push_back(node);
|
||
}
|
||
}
|
||
|
||
// Prioritize these nodes by replacing eviction set with them
|
||
if (vTmpEvictionCandidates.size() > 0) {
|
||
vEvictionCandidates = vTmpEvictionCandidates;
|
||
}
|
||
}</pre>
|
||
<p>The existing method of disconnecting a candidate remains:</p>
|
||
<blockquote>
|
||
<p>vEvictionCandidates[0]->fDisconnect = true;</p>
|
||
</blockquote>
|
||
<p>The existing eviction process will classify and divide eviction candidates into buckets called netgroups. If a netgroup only has one peer, it will not be evicted. This means at least one pre-Overwinter node will remain connected upto the activation block height, barring any network issues or a high ban score.</p>
|
||
</section>
|
||
<section id="disconnecting-existing-connections"><h3><span class="section-heading">Disconnecting Existing Connections</span><span class="section-anchor"> <a rel="bookmark" href="#disconnecting-existing-connections"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h3>
|
||
<p>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, <code>ProcessMessage</code> is modified so that once Overwinter activates, if necessary, the protocol version of an existing peer is validated when inbound messages arrive.</p>
|
||
<p>Example code:</p>
|
||
<pre>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 peer connection when:
|
||
// 1. The version message has been received
|
||
// 2. Overwinter is active
|
||
// 3. Peer version is pre-Overwinter
|
||
else if (NetworkUpgradeActive(GetHeight(), chainparams.GetConsensus(), Consensus::UPGRADE_OVERWINTER)
|
||
&& (pfrom->nVersion < chainparams.GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion))
|
||
{
|
||
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",
|
||
chainparams.GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion));
|
||
pfrom->fDisconnect = true;
|
||
return false;
|
||
}</pre>
|
||
</section>
|
||
</section>
|
||
<section id="deployment-of-overwinter"><h2><span class="section-heading">Deployment of Overwinter</span><span class="section-anchor"> <a rel="bookmark" href="#deployment-of-overwinter"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h2>
|
||
<p>The Overwinter network upgrade defines the following network upgrade constants <a id="id10" class="footnote_reference" href="#zip-0200">3</a>:</p>
|
||
<dl>
|
||
<dt>CONSENSUS_BRANCH_ID</dt>
|
||
<dd><code>0x5ba81b19</code></dd>
|
||
<dt>ACTIVATION_HEIGHT</dt>
|
||
<dd>
|
||
<p>Testnet: 207500</p>
|
||
<p>Mainnet: 347500</p>
|
||
</dd>
|
||
</dl>
|
||
<p>The following ZIPs are deployed by Overwinter:</p>
|
||
<ul>
|
||
<li>ZIP 200 <a id="id11" class="footnote_reference" href="#zip-0200">3</a></li>
|
||
<li>ZIP 201 (this ZIP)</li>
|
||
<li>ZIP 202 <a id="id12" class="footnote_reference" href="#zip-0202">4</a></li>
|
||
<li>ZIP 203 <a id="id13" class="footnote_reference" href="#zip-0203">5</a></li>
|
||
<li>ZIP 143 <a id="id14" class="footnote_reference" href="#zip-0143">2</a></li>
|
||
</ul>
|
||
</section>
|
||
<section id="backward-compatibility"><h2><span class="section-heading">Backward compatibility</span><span class="section-anchor"> <a rel="bookmark" href="#backward-compatibility"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h2>
|
||
<p>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.</p>
|
||
<p>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.</p>
|
||
</section>
|
||
<section id="reference-implementation"><h2><span class="section-heading">Reference Implementation</span><span class="section-anchor"> <a rel="bookmark" href="#reference-implementation"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h2>
|
||
<p><a href="https://github.com/zcash/zcash/pull/2919">https://github.com/zcash/zcash/pull/2919</a></p>
|
||
</section>
|
||
<section id="references"><h2><span class="section-heading">References</span><span class="section-anchor"> <a rel="bookmark" href="#references"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h2>
|
||
<table id="rfc2119" class="footnote">
|
||
<tbody>
|
||
<tr>
|
||
<th>1</th>
|
||
<td><a href="https://www.rfc-editor.org/rfc/rfc2119.html">RFC 2119: Key words for use in RFCs to Indicate Requirement Levels</a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<table id="zip-0143" class="footnote">
|
||
<tbody>
|
||
<tr>
|
||
<th>2</th>
|
||
<td><a href="zip-0143">ZIP 143: Transaction Signature Validation for Overwinter</a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<table id="zip-0200" class="footnote">
|
||
<tbody>
|
||
<tr>
|
||
<th>3</th>
|
||
<td><a href="zip-0200">ZIP 200: Network Upgrade Mechanism</a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<table id="zip-0202" class="footnote">
|
||
<tbody>
|
||
<tr>
|
||
<th>4</th>
|
||
<td><a href="zip-0202">ZIP 202: Version 3 Transaction Format for Overwinter</a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<table id="zip-0203" class="footnote">
|
||
<tbody>
|
||
<tr>
|
||
<th>5</th>
|
||
<td><a href="zip-0203">ZIP 203: Transaction Expiry</a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<table id="bip-0111" class="footnote">
|
||
<tbody>
|
||
<tr>
|
||
<th>6</th>
|
||
<td><a href="https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki">BIP 111: NODE_BLOOM service bit</a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<table id="bitcoin-verson" class="footnote">
|
||
<tbody>
|
||
<tr>
|
||
<th>7</th>
|
||
<td><a href="https://en.bitcoin.it/wiki/Protocol_documentation#version">https://en.bitcoin.it/wiki/Protocol_documentation#version</a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<table id="bitcoin-version-handshake" class="footnote">
|
||
<tbody>
|
||
<tr>
|
||
<th>8</th>
|
||
<td><a href="https://en.bitcoin.it/wiki/Version_Handshake">https://en.bitcoin.it/wiki/Version_Handshake</a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<table id="eclipse-attack" class="footnote">
|
||
<tbody>
|
||
<tr>
|
||
<th>9</th>
|
||
<td><a href="https://eprint.iacr.org/2015/263">Eclipse Attacks on Bitcoin’s Peer-to-Peer Network</a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<table id="partition-discussion" class="footnote">
|
||
<tbody>
|
||
<tr>
|
||
<th>10</th>
|
||
<td><a href="https://github.com/zcash/zcash/issues/2775">Partition nodes with old protocol version from network in advance of hard fork</a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</section>
|
||
</section>
|
||
</body>
|
||
</html> |