Skip to content

Commit 6262915

Browse files
committed
Add unit test for stale tip checking
1 parent 83df257 commit 6262915

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

src/net_processing.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,15 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con
550550

551551
} // namespace
552552

553+
// This function is used for testing the stale tip eviction logic, see
554+
// DoS_tests.cpp
555+
void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds)
556+
{
557+
LOCK(cs_main);
558+
CNodeState *state = State(node);
559+
if (state) state->m_last_block_announcement = time_in_seconds;
560+
}
561+
553562
// Returns true for outbound peers, excluding manual connections, feelers, and
554563
// one-shots
555564
bool IsOutboundDisconnectionCandidate(const CNode *node)

src/test/DoS_tests.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ CService ip(uint32_t i)
4040

4141
static NodeId id = 0;
4242

43+
void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds);
44+
4345
BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup)
4446

4547
// Test eviction of an outbound peer whose chain never advances
@@ -87,6 +89,89 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
8789
peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
8890
}
8991

92+
void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic)
93+
{
94+
CAddress addr(ip(GetRandInt(0xffffffff)), NODE_NONE);
95+
vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr, 0, 0, CAddress(), "", /*fInboundIn=*/ false));
96+
CNode &node = *vNodes.back();
97+
node.SetSendVersion(PROTOCOL_VERSION);
98+
99+
peerLogic.InitializeNode(&node);
100+
node.nVersion = 1;
101+
node.fSuccessfullyConnected = true;
102+
103+
CConnmanTest::AddNode(node);
104+
}
105+
106+
BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
107+
{
108+
const Consensus::Params& consensusParams = Params().GetConsensus();
109+
constexpr int nMaxOutbound = 8;
110+
CConnman::Options options;
111+
options.nMaxConnections = 125;
112+
options.nMaxOutbound = nMaxOutbound;
113+
options.nMaxFeeler = 1;
114+
115+
connman->Init(options);
116+
std::vector<CNode *> vNodes;
117+
118+
// Mock some outbound peers
119+
for (int i=0; i<nMaxOutbound; ++i) {
120+
AddRandomOutboundPeer(vNodes, *peerLogic);
121+
}
122+
123+
peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
124+
125+
// No nodes should be marked for disconnection while we have no extra peers
126+
for (const CNode *node : vNodes) {
127+
BOOST_CHECK(node->fDisconnect == false);
128+
}
129+
130+
SetMockTime(GetTime() + 3*consensusParams.nPowTargetSpacing + 1);
131+
132+
// Now tip should definitely be stale, and we should look for an extra
133+
// outbound peer
134+
peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
135+
BOOST_CHECK(connman->GetTryNewOutboundPeer());
136+
137+
// Still no peers should be marked for disconnection
138+
for (const CNode *node : vNodes) {
139+
BOOST_CHECK(node->fDisconnect == false);
140+
}
141+
142+
// If we add one more peer, something should get marked for eviction
143+
// on the next check (since we're mocking the time to be in the future, the
144+
// required time connected check should be satisfied).
145+
AddRandomOutboundPeer(vNodes, *peerLogic);
146+
147+
peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
148+
for (int i=0; i<nMaxOutbound; ++i) {
149+
BOOST_CHECK(vNodes[i]->fDisconnect == false);
150+
}
151+
// Last added node should get marked for eviction
152+
BOOST_CHECK(vNodes.back()->fDisconnect == true);
153+
154+
vNodes.back()->fDisconnect = false;
155+
156+
// Update the last announced block time for the last
157+
// peer, and check that the next newest node gets evicted.
158+
UpdateLastBlockAnnounceTime(vNodes.back()->GetId(), GetTime());
159+
160+
peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
161+
for (int i=0; i<nMaxOutbound-1; ++i) {
162+
BOOST_CHECK(vNodes[i]->fDisconnect == false);
163+
}
164+
BOOST_CHECK(vNodes[nMaxOutbound-1]->fDisconnect == true);
165+
BOOST_CHECK(vNodes.back()->fDisconnect == false);
166+
167+
bool dummy;
168+
for (const CNode *node : vNodes) {
169+
peerLogic->FinalizeNode(node->GetId(), dummy);
170+
}
171+
172+
CConnmanTest::ClearNodes();
173+
}
174+
90175
BOOST_AUTO_TEST_CASE(DoS_banning)
91176
{
92177
std::atomic<bool> interruptDummy(false);

0 commit comments

Comments
 (0)