Auto merge of #3512 - str4d:3487-nu-peer-management, r=ebfull

Make NU peer management logic upgrade-agnostic

Closes #3487.
This commit is contained in:
Homu
2018-09-18 04:25:54 -07:00
9 changed files with 270 additions and 148 deletions

View File

@@ -114,20 +114,28 @@ bool IsActivationHeightForAnyUpgrade(
return false;
}
boost::optional<int> NextActivationHeight(
int nHeight,
const Consensus::Params& params)
{
boost::optional<int> NextEpoch(int nHeight, const Consensus::Params& params) {
if (nHeight < 0) {
return boost::none;
}
// Don't count Sprout as an activation height
// Sprout is never pending
for (auto idx = Consensus::BASE_SPROUT + 1; idx < Consensus::MAX_NETWORK_UPGRADES; idx++) {
if (NetworkUpgradeState(nHeight, params, Consensus::UpgradeIndex(idx)) == UPGRADE_PENDING) {
return params.vUpgrades[idx].nActivationHeight;
return idx;
}
}
return boost::none;
}
boost::optional<int> NextActivationHeight(
int nHeight,
const Consensus::Params& params)
{
auto idx = NextEpoch(nHeight, params);
if (idx) {
return params.vUpgrades[idx.get()].nActivationHeight;
}
return boost::none;
}

View File

@@ -79,6 +79,12 @@ bool IsActivationHeightForAnyUpgrade(
int nHeight,
const Consensus::Params& params);
/**
* Returns the index of the next upgrade after the given block height, or
* boost::none if there are no more known upgrades.
*/
boost::optional<int> NextEpoch(int nHeight, const Consensus::Params& params);
/**
* Returns the activation height for the next upgrade after the given block height,
* or boost::none if there are no more known upgrades.

View File

@@ -143,6 +143,35 @@ TEST_F(UpgradesTest, IsActivationHeightForAnyUpgrade) {
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params));
}
TEST_F(UpgradesTest, NextEpoch) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& params = Params().GetConsensus();
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
EXPECT_EQ(NextEpoch(-1, params), boost::none);
EXPECT_EQ(NextEpoch(0, params), boost::none);
EXPECT_EQ(NextEpoch(1, params), boost::none);
EXPECT_EQ(NextEpoch(1000000, params), boost::none);
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
EXPECT_EQ(NextEpoch(-1, params), boost::none);
EXPECT_EQ(NextEpoch(0, params), boost::none);
EXPECT_EQ(NextEpoch(1, params), boost::none);
EXPECT_EQ(NextEpoch(1000000, params), boost::none);
int nActivationHeight = 100;
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight);
EXPECT_EQ(NextEpoch(-1, params), boost::none);
EXPECT_EQ(NextEpoch(0, params), static_cast<int>(Consensus::UPGRADE_TESTDUMMY));
EXPECT_EQ(NextEpoch(1, params), static_cast<int>(Consensus::UPGRADE_TESTDUMMY));
EXPECT_EQ(NextEpoch(nActivationHeight - 1, params), static_cast<int>(Consensus::UPGRADE_TESTDUMMY));
EXPECT_EQ(NextEpoch(nActivationHeight, params), boost::none);
EXPECT_EQ(NextEpoch(nActivationHeight + 1, params), boost::none);
EXPECT_EQ(NextEpoch(1000000, params), boost::none);
}
TEST_F(UpgradesTest, NextActivationHeight) {
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& params = Params().GetConsensus();

View File

@@ -5016,15 +5016,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return false;
}
// When Overwinter is active, reject incoming connections from non-Overwinter nodes
// Reject incoming connections from nodes that don't know about the current epoch
const Consensus::Params& params = Params().GetConsensus();
if (NetworkUpgradeActive(GetHeight(), params, Consensus::UPGRADE_OVERWINTER)
&& pfrom->nVersion < params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)
auto currentEpoch = CurrentEpoch(GetHeight(), params);
if (pfrom->nVersion < params.vUpgrades[currentEpoch].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",
params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion));
params.vUpgrades[currentEpoch].nProtocolVersion));
pfrom->fDisconnect = true;
return false;
}
@@ -5149,15 +5149,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// 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))
// 2. Peer version is below the minimum version for the current epoch
else if (pfrom->nVersion < chainparams.GetConsensus().vUpgrades[
CurrentEpoch(GetHeight(), chainparams.GetConsensus())].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));
chainparams.GetConsensus().vUpgrades[
CurrentEpoch(GetHeight(), chainparams.GetConsensus())].nProtocolVersion));
pfrom->fDisconnect = true;
return false;
}

View File

@@ -820,22 +820,26 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
}
const Consensus::Params& params = Params().GetConsensus();
int nActivationHeight = params.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight;
auto nextEpoch = NextEpoch(height, params);
if (nextEpoch) {
auto idx = nextEpoch.get();
int nActivationHeight = params.vUpgrades[idx].nActivationHeight;
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_SAPLING].nProtocolVersion) {
vTmpEvictionCandidates.push_back(node);
if (nActivationHeight > 0 &&
height < nActivationHeight &&
height >= nActivationHeight - NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD)
{
// Find any nodes which don't support the protocol version for the next upgrade
for (const CNodeRef &node : vEvictionCandidates) {
if (node->nVersion < params.vUpgrades[idx].nProtocolVersion) {
vTmpEvictionCandidates.push_back(node);
}
}
}
// Prioritize these nodes by replacing eviction set with them
if (vTmpEvictionCandidates.size() > 0) {
vEvictionCandidates = vTmpEvictionCandidates;
// Prioritize these nodes by replacing eviction set with them
if (vTmpEvictionCandidates.size() > 0) {
vEvictionCandidates = vTmpEvictionCandidates;
}
}
}