Changeset View
Changeset View
Standalone View
Standalone View
src/test/denialofservice_tests.cpp
Show All 16 Lines | |||||
#include <validation.h> | #include <validation.h> | ||||
#include <test/test_bitcoin.h> | #include <test/test_bitcoin.h> | ||||
#include <boost/test/unit_test.hpp> | #include <boost/test/unit_test.hpp> | ||||
#include <cstdint> | #include <cstdint> | ||||
struct CConnmanTest : public CConnman { | |||||
using CConnman::CConnman; | |||||
void AddNode(CNode &node) { | |||||
LOCK(cs_vNodes); | |||||
vNodes.push_back(&node); | |||||
} | |||||
void ClearNodes() { | |||||
LOCK(cs_vNodes); | |||||
for (CNode *node : vNodes) { | |||||
delete node; | |||||
} | |||||
vNodes.clear(); | |||||
} | |||||
}; | |||||
// Tests these internal-to-net_processing.cpp methods: | // Tests these internal-to-net_processing.cpp methods: | ||||
extern bool AddOrphanTx(const CTransactionRef &tx, NodeId peer); | extern bool AddOrphanTx(const CTransactionRef &tx, NodeId peer); | ||||
extern void EraseOrphansFor(NodeId peer); | extern void EraseOrphansFor(NodeId peer); | ||||
extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); | extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); | ||||
struct COrphanTx { | struct COrphanTx { | ||||
CTransactionRef tx; | CTransactionRef tx; | ||||
NodeId fromPeer; | NodeId fromPeer; | ||||
Show All 19 Lines | |||||
// after the appropriate timeouts. | // after the appropriate timeouts. | ||||
// Note that we protect 4 outbound nodes from being subject to this logic; this | // Note that we protect 4 outbound nodes from being subject to this logic; this | ||||
// test takes advantage of that protection only being applied to nodes which | // test takes advantage of that protection only being applied to nodes which | ||||
// send headers with sufficient work. | // send headers with sufficient work. | ||||
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) { | BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) { | ||||
const Config &config = GetConfig(); | const Config &config = GetConfig(); | ||||
std::atomic<bool> interruptDummy(false); | std::atomic<bool> interruptDummy(false); | ||||
auto connman = std::make_unique<CConnman>(config, 0x1337, 0x1337); | |||||
auto peerLogic = | |||||
std::make_unique<PeerLogicValidation>(connman.get(), scheduler, false); | |||||
// Mock an outbound peer | // Mock an outbound peer | ||||
CAddress addr1(ip(0xa0b0c001), NODE_NONE); | CAddress addr1(ip(0xa0b0c001), NODE_NONE); | ||||
CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK), 0, INVALID_SOCKET, addr1, | CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK), 0, INVALID_SOCKET, addr1, | ||||
0, 0, CAddress(), "", | 0, 0, CAddress(), "", | ||||
/*fInboundIn=*/false); | /*fInboundIn=*/false); | ||||
dummyNode1.SetSendVersion(PROTOCOL_VERSION); | dummyNode1.SetSendVersion(PROTOCOL_VERSION); | ||||
peerLogic->InitializeNode(config, &dummyNode1); | peerLogic->InitializeNode(config, &dummyNode1); | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) { | ||||
BOOST_CHECK(dummyNode1.fDisconnect == true); | BOOST_CHECK(dummyNode1.fDisconnect == true); | ||||
SetMockTime(0); | SetMockTime(0); | ||||
bool dummy; | bool dummy; | ||||
peerLogic->FinalizeNode(config, dummyNode1.GetId(), dummy); | peerLogic->FinalizeNode(config, dummyNode1.GetId(), dummy); | ||||
} | } | ||||
static void AddRandomOutboundPeer(const Config &config, | static void AddRandomOutboundPeer(const Config &config, | ||||
std::vector<std::unique_ptr<CNode>> &vNodes, | std::vector<CNode *> &vNodes, | ||||
PeerLogicValidation &peerLogic) { | PeerLogicValidation &peerLogic, | ||||
CConnmanTest *connman) { | |||||
CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE); | CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE); | ||||
vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK), 0, | vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK), 0, | ||||
INVALID_SOCKET, addr, 0, 0, CAddress(), "", | INVALID_SOCKET, addr, 0, 0, CAddress(), "", | ||||
/*fInboundIn=*/false)); | /*fInboundIn=*/false)); | ||||
CNode &node = *vNodes.back(); | CNode &node = *vNodes.back(); | ||||
node.SetSendVersion(PROTOCOL_VERSION); | node.SetSendVersion(PROTOCOL_VERSION); | ||||
peerLogic.InitializeNode(config, &node); | peerLogic.InitializeNode(config, &node); | ||||
node.nVersion = 1; | node.nVersion = 1; | ||||
node.fSuccessfullyConnected = true; | node.fSuccessfullyConnected = true; | ||||
CConnmanTest::AddNode(node); | connman->AddNode(node); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(stale_tip_peer_management) { | BOOST_AUTO_TEST_CASE(stale_tip_peer_management) { | ||||
const Config &config = GetConfig(); | const Config &config = GetConfig(); | ||||
auto connman = std::make_unique<CConnmanTest>(config, 0x1337, 0x1337); | |||||
auto peerLogic = | |||||
std::make_unique<PeerLogicValidation>(connman.get(), scheduler, false); | |||||
const Consensus::Params &consensusParams = | const Consensus::Params &consensusParams = | ||||
config.GetChainParams().GetConsensus(); | config.GetChainParams().GetConsensus(); | ||||
constexpr int nMaxOutbound = 8; | constexpr int nMaxOutbound = 8; | ||||
CConnman::Options options; | CConnman::Options options; | ||||
options.nMaxConnections = 125; | options.nMaxConnections = 125; | ||||
options.nMaxOutbound = nMaxOutbound; | options.nMaxOutbound = nMaxOutbound; | ||||
options.nMaxFeeler = 1; | options.nMaxFeeler = 1; | ||||
connman->Init(options); | connman->Init(options); | ||||
std::vector<std::unique_ptr<CNode>> vNodes; | std::vector<CNode *> vNodes; | ||||
// Mock some outbound peers | // Mock some outbound peers | ||||
for (int i = 0; i < nMaxOutbound; ++i) { | for (int i = 0; i < nMaxOutbound; ++i) { | ||||
AddRandomOutboundPeer(config, vNodes, *peerLogic); | AddRandomOutboundPeer(config, vNodes, *peerLogic, connman.get()); | ||||
} | } | ||||
peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); | peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); | ||||
// No nodes should be marked for disconnection while we have no extra peers | // No nodes should be marked for disconnection while we have no extra peers | ||||
for (auto const &node : vNodes) { | for (const CNode *node : vNodes) { | ||||
BOOST_CHECK(node->fDisconnect == false); | BOOST_CHECK(node->fDisconnect == false); | ||||
} | } | ||||
SetMockTime(GetTime() + 3 * consensusParams.nPowTargetSpacing + 1); | SetMockTime(GetTime() + 3 * consensusParams.nPowTargetSpacing + 1); | ||||
// Now tip should definitely be stale, and we should look for an extra | // Now tip should definitely be stale, and we should look for an extra | ||||
// outbound peer | // outbound peer | ||||
peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); | peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); | ||||
BOOST_CHECK(connman->GetTryNewOutboundPeer()); | BOOST_CHECK(connman->GetTryNewOutboundPeer()); | ||||
// Still no peers should be marked for disconnection | // Still no peers should be marked for disconnection | ||||
for (auto const &node : vNodes) { | for (const CNode *node : vNodes) { | ||||
BOOST_CHECK(node->fDisconnect == false); | BOOST_CHECK(node->fDisconnect == false); | ||||
} | } | ||||
// If we add one more peer, something should get marked for eviction | // If we add one more peer, something should get marked for eviction | ||||
// on the next check (since we're mocking the time to be in the future, the | // on the next check (since we're mocking the time to be in the future, the | ||||
// required time connected check should be satisfied). | // required time connected check should be satisfied). | ||||
AddRandomOutboundPeer(config, vNodes, *peerLogic); | AddRandomOutboundPeer(config, vNodes, *peerLogic, connman.get()); | ||||
peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); | peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); | ||||
for (int i = 0; i < nMaxOutbound; ++i) { | for (int i = 0; i < nMaxOutbound; ++i) { | ||||
BOOST_CHECK(vNodes[i]->fDisconnect == false); | BOOST_CHECK(vNodes[i]->fDisconnect == false); | ||||
} | } | ||||
// Last added node should get marked for eviction | // Last added node should get marked for eviction | ||||
BOOST_CHECK(vNodes.back()->fDisconnect == true); | BOOST_CHECK(vNodes.back()->fDisconnect == true); | ||||
vNodes.back()->fDisconnect = false; | vNodes.back()->fDisconnect = false; | ||||
// Update the last announced block time for the last | // Update the last announced block time for the last | ||||
// peer, and check that the next newest node gets evicted. | // peer, and check that the next newest node gets evicted. | ||||
UpdateLastBlockAnnounceTime(vNodes.back()->GetId(), GetTime()); | UpdateLastBlockAnnounceTime(vNodes.back()->GetId(), GetTime()); | ||||
peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); | peerLogic->CheckForStaleTipAndEvictPeers(consensusParams); | ||||
for (int i = 0; i < nMaxOutbound - 1; ++i) { | for (int i = 0; i < nMaxOutbound - 1; ++i) { | ||||
BOOST_CHECK(vNodes[i]->fDisconnect == false); | BOOST_CHECK(vNodes[i]->fDisconnect == false); | ||||
} | } | ||||
BOOST_CHECK(vNodes[nMaxOutbound - 1]->fDisconnect == true); | BOOST_CHECK(vNodes[nMaxOutbound - 1]->fDisconnect == true); | ||||
BOOST_CHECK(vNodes.back()->fDisconnect == false); | BOOST_CHECK(vNodes.back()->fDisconnect == false); | ||||
bool dummy; | bool dummy; | ||||
for (auto const &node : vNodes) { | for (const CNode *node : vNodes) { | ||||
peerLogic->FinalizeNode(config, node->GetId(), dummy); | peerLogic->FinalizeNode(config, node->GetId(), dummy); | ||||
} | } | ||||
CConnmanTest::ClearNodes(); | connman->ClearNodes(); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(DoS_banning) { | BOOST_AUTO_TEST_CASE(DoS_banning) { | ||||
const Config &config = GetConfig(); | const Config &config = GetConfig(); | ||||
std::atomic<bool> interruptDummy(false); | std::atomic<bool> interruptDummy(false); | ||||
auto connman = std::make_unique<CConnman>(config, 0x1337, 0x1337); | |||||
auto peerLogic = | |||||
std::make_unique<PeerLogicValidation>(connman.get(), scheduler, false); | |||||
connman->ClearBanned(); | connman->ClearBanned(); | ||||
CAddress addr1(ip(0xa0b0c001), NODE_NONE); | CAddress addr1(ip(0xa0b0c001), NODE_NONE); | ||||
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, | CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, | ||||
CAddress(), "", true); | CAddress(), "", true); | ||||
dummyNode1.SetSendVersion(PROTOCOL_VERSION); | dummyNode1.SetSendVersion(PROTOCOL_VERSION); | ||||
peerLogic->InitializeNode(config, &dummyNode1); | peerLogic->InitializeNode(config, &dummyNode1); | ||||
dummyNode1.nVersion = 1; | dummyNode1.nVersion = 1; | ||||
dummyNode1.fSuccessfullyConnected = true; | dummyNode1.fSuccessfullyConnected = true; | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(DoS_banning) { | ||||
peerLogic->FinalizeNode(config, dummyNode1.GetId(), dummy); | peerLogic->FinalizeNode(config, dummyNode1.GetId(), dummy); | ||||
peerLogic->FinalizeNode(config, dummyNode2.GetId(), dummy); | peerLogic->FinalizeNode(config, dummyNode2.GetId(), dummy); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(DoS_banscore) { | BOOST_AUTO_TEST_CASE(DoS_banscore) { | ||||
const Config &config = GetConfig(); | const Config &config = GetConfig(); | ||||
std::atomic<bool> interruptDummy(false); | std::atomic<bool> interruptDummy(false); | ||||
auto connman = std::make_unique<CConnman>(config, 0x1337, 0x1337); | |||||
auto peerLogic = | |||||
std::make_unique<PeerLogicValidation>(connman.get(), scheduler, false); | |||||
connman->ClearBanned(); | connman->ClearBanned(); | ||||
// because 11 is my favorite number. | // because 11 is my favorite number. | ||||
gArgs.ForceSetArg("-banscore", "111"); | gArgs.ForceSetArg("-banscore", "111"); | ||||
CAddress addr1(ip(0xa0b0c001), NODE_NONE); | CAddress addr1(ip(0xa0b0c001), NODE_NONE); | ||||
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, | CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, | ||||
CAddress(), "", true); | CAddress(), "", true); | ||||
dummyNode1.SetSendVersion(PROTOCOL_VERSION); | dummyNode1.SetSendVersion(PROTOCOL_VERSION); | ||||
peerLogic->InitializeNode(config, &dummyNode1); | peerLogic->InitializeNode(config, &dummyNode1); | ||||
Show All 31 Lines | BOOST_AUTO_TEST_CASE(DoS_banscore) { | ||||
bool dummy; | bool dummy; | ||||
peerLogic->FinalizeNode(config, dummyNode1.GetId(), dummy); | peerLogic->FinalizeNode(config, dummyNode1.GetId(), dummy); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(DoS_bantime) { | BOOST_AUTO_TEST_CASE(DoS_bantime) { | ||||
const Config &config = GetConfig(); | const Config &config = GetConfig(); | ||||
std::atomic<bool> interruptDummy(false); | std::atomic<bool> interruptDummy(false); | ||||
auto connman = std::make_unique<CConnman>(config, 0x1337, 0x1337); | |||||
auto peerLogic = | |||||
std::make_unique<PeerLogicValidation>(connman.get(), scheduler, false); | |||||
connman->ClearBanned(); | connman->ClearBanned(); | ||||
int64_t nStartTime = GetTime(); | int64_t nStartTime = GetTime(); | ||||
// Overrides future calls to GetTime() | // Overrides future calls to GetTime() | ||||
SetMockTime(nStartTime); | SetMockTime(nStartTime); | ||||
CAddress addr(ip(0xa0b0c001), NODE_NONE); | CAddress addr(ip(0xa0b0c001), NODE_NONE); | ||||
CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, | CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, | ||||
CAddress(), "", true); | CAddress(), "", true); | ||||
▲ Show 20 Lines • Show All 111 Lines • Show Last 20 Lines |