Bitcoin Core 31.99.0
P2P Digital Currency
denialofservice_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5// Unit tests for denial-of-service detection/prevention code
6
7#include <banman.h>
8#include <chainparams.h>
9#include <common/args.h>
10#include <net.h>
11#include <net_processing.h>
12#include <pubkey.h>
13#include <script/sign.h>
15#include <serialize.h>
16#include <test/util/net.h>
17#include <test/util/random.h>
19#include <test/util/time.h>
20#include <util/string.h>
21#include <util/time.h>
22#include <validation.h>
23
24#include <array>
25#include <cstdint>
26
27#include <boost/test/unit_test.hpp>
28
29static CService ip(uint32_t i)
30{
31 struct in_addr s;
32 s.s_addr = i;
33 return CService(CNetAddr(s), Params().GetDefaultPort());
34}
35
36BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
37
38// Test eviction of an outbound peer whose chain never advances
39// Mock a node connection, and use mocktime to simulate a peer
40// which never sends any headers messages. PeerLogic should
41// decide to evict that outbound peer, after the appropriate timeouts.
42// Note that we protect 4 outbound nodes from being subject to
43// this logic; this test takes advantage of that protection only
44// being applied to nodes which send headers with sufficient
45// work.
46BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
47{
49
50 ConnmanTestMsg& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
51 // Disable inactivity checks for this test to avoid interference
52 connman.SetPeerConnectTimeout(99999s);
53 PeerManager& peerman = *m_node.peerman;
54
55 // Mock an outbound peer
56 CAddress addr1(ip(0xa0b0c001), NODE_NONE);
57 NodeId id{0};
58 CNode dummyNode1{id++,
59 /*sock=*/nullptr,
60 addr1,
61 /*nKeyedNetGroupIn=*/0,
62 /*nLocalHostNonceIn=*/0,
63 CAddress(),
64 /*addrNameIn=*/"",
66 /*inbound_onion=*/false,
67 /*network_key=*/0};
68
69 connman.Handshake(
70 /*node=*/dummyNode1,
71 /*successfully_connected=*/true,
72 /*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
73 /*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
74 /*version=*/PROTOCOL_VERSION,
75 /*relay_txs=*/true);
76
77 // This test requires that we have a chain with non-zero work.
78 {
80 BOOST_CHECK(m_node.chainman->ActiveChain().Tip() != nullptr);
81 BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->nChainWork > 0);
82 }
83
84 // Test starts here
85 BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in getheaders
86
87 {
88 LOCK(dummyNode1.cs_vSend);
89 const auto& [to_send, _more, _msg_type] = dummyNode1.m_transport->GetBytesToSend(false);
90 BOOST_CHECK(!to_send.empty());
91 }
92 connman.FlushSendBuffer(dummyNode1);
93
94 NodeClockContext clock_ctx{};
95 clock_ctx += 21min;
96
97 BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in getheaders
98 {
99 LOCK(dummyNode1.cs_vSend);
100 const auto& [to_send, _more, _msg_type] = dummyNode1.m_transport->GetBytesToSend(false);
101 BOOST_CHECK(!to_send.empty());
102 }
103
104 clock_ctx += 3min;
105 BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in disconnect
106 BOOST_CHECK(dummyNode1.fDisconnect == true);
107
108 peerman.FinalizeNode(dummyNode1);
109}
110
112void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman, ConnectionType connType, bool onion_peer = false)
113{
114 CAddress addr;
115
116 if (onion_peer) {
117 auto tor_addr{m_rng.randbytes(ADDR_TORV3_SIZE)};
118 BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr)));
119 }
120
121 while (!addr.IsRoutable()) {
122 addr = CAddress(ip(m_rng.randbits(32)), NODE_NONE);
123 }
124
125 vNodes.emplace_back(new CNode{id++,
126 /*sock=*/nullptr,
127 addr,
128 /*nKeyedNetGroupIn=*/0,
129 /*nLocalHostNonceIn=*/0,
130 CAddress(),
131 /*addrNameIn=*/"",
132 connType,
133 /*inbound_onion=*/false,
134 /*network_key=*/0});
135 CNode &node = *vNodes.back();
136 node.SetCommonVersion(PROTOCOL_VERSION);
137
139 node.fSuccessfullyConnected = true;
140
141 connman.AddTestNode(node);
142}
143}; // struct OutboundTest
144
145BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest)
146{
147 NodeId id{0};
148 auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
149 auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
150
151 constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS;
152 CConnman::Options options;
154
155 const auto time_init{Now<NodeSeconds>()};
156 NodeClockContext clock_ctx{time_init};
157 const auto delta{3 * std::chrono::seconds{m_node.chainman->GetConsensus().nPowTargetSpacing} + 1s};
158 connman->Init(options);
159 std::vector<CNode *> vNodes;
160
161 // Mock some outbound peers
162 for (int i = 0; i < max_outbound_full_relay; ++i) {
163 AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
164 }
165
166 peerLogic->CheckForStaleTipAndEvictPeers();
167
168 // No nodes should be marked for disconnection while we have no extra peers
169 for (const CNode *node : vNodes) {
170 BOOST_CHECK(node->fDisconnect == false);
171 }
172
173 clock_ctx += delta;
174
175 // Now tip should definitely be stale, and we should look for an extra
176 // outbound peer
177 peerLogic->CheckForStaleTipAndEvictPeers();
178 BOOST_CHECK(connman->GetTryNewOutboundPeer());
179
180 // Still no peers should be marked for disconnection
181 for (const CNode *node : vNodes) {
182 BOOST_CHECK(node->fDisconnect == false);
183 }
184
185 // If we add one more peer, something should get marked for eviction
186 // on the next check (since we're mocking the time to be in the future, the
187 // required time connected check should be satisfied).
188 clock_ctx.set(time_init);
189 AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
190 clock_ctx += delta;
191
192 peerLogic->CheckForStaleTipAndEvictPeers();
193 for (int i = 0; i < max_outbound_full_relay; ++i) {
194 BOOST_CHECK(vNodes[i]->fDisconnect == false);
195 }
196 // Last added node should get marked for eviction
197 BOOST_CHECK(vNodes.back()->fDisconnect == true);
198
199 vNodes.back()->fDisconnect = false;
200
201 // Update the last announced block time for the last
202 // peer, and check that the next newest node gets evicted.
203 peerLogic->UpdateLastBlockAnnounceTime(vNodes.back()->GetId(), GetTime());
204
205 peerLogic->CheckForStaleTipAndEvictPeers();
206 for (int i = 0; i < max_outbound_full_relay - 1; ++i) {
207 BOOST_CHECK(vNodes[i]->fDisconnect == false);
208 }
209 BOOST_CHECK(vNodes[max_outbound_full_relay-1]->fDisconnect == true);
210 BOOST_CHECK(vNodes.back()->fDisconnect == false);
211
212 vNodes[max_outbound_full_relay - 1]->fDisconnect = false;
213
214 // Add an onion peer, that will be protected because it is the only one for
215 // its network, so another peer gets disconnected instead.
216 clock_ctx.set(time_init);
217 AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY, /*onion_peer=*/true);
218 clock_ctx += delta;
219 peerLogic->CheckForStaleTipAndEvictPeers();
220
221 for (int i = 0; i < max_outbound_full_relay - 2; ++i) {
222 BOOST_CHECK(vNodes[i]->fDisconnect == false);
223 }
224 BOOST_CHECK(vNodes[max_outbound_full_relay - 2]->fDisconnect == false);
225 BOOST_CHECK(vNodes[max_outbound_full_relay - 1]->fDisconnect == true);
226 BOOST_CHECK(vNodes[max_outbound_full_relay]->fDisconnect == false);
227
228 // Add a second onion peer which won't be protected
229 clock_ctx.set(time_init);
230 AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY, /*onion_peer=*/true);
231 clock_ctx += delta;
232 peerLogic->CheckForStaleTipAndEvictPeers();
233
234 BOOST_CHECK(vNodes.back()->fDisconnect == true);
235
236 for (const CNode *node : vNodes) {
237 peerLogic->FinalizeNode(*node);
238 }
239
240 connman->ClearTestNodes();
241}
242
243BOOST_FIXTURE_TEST_CASE(block_relay_only_eviction, OutboundTest)
244{
245 NodeId id{0};
246 auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
247 auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
248
249 constexpr int max_outbound_block_relay{MAX_BLOCK_RELAY_ONLY_CONNECTIONS};
250 constexpr auto MINIMUM_CONNECT_TIME{30s};
251 CConnman::Options options;
253
254 connman->Init(options);
255 std::vector<CNode*> vNodes;
256
257 // Add block-relay-only peers up to the limit
258 for (int i = 0; i < max_outbound_block_relay; ++i) {
259 AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::BLOCK_RELAY);
260 }
261 peerLogic->CheckForStaleTipAndEvictPeers();
262
263 for (int i = 0; i < max_outbound_block_relay; ++i) {
264 BOOST_CHECK(vNodes[i]->fDisconnect == false);
265 }
266
267 // Add an extra block-relay-only peer breaking the limit (mocks logic in ThreadOpenConnections)
268 AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::BLOCK_RELAY);
269 peerLogic->CheckForStaleTipAndEvictPeers();
270
271 // The extra peer should only get marked for eviction after MINIMUM_CONNECT_TIME
272 for (int i = 0; i < max_outbound_block_relay; ++i) {
273 BOOST_CHECK(vNodes[i]->fDisconnect == false);
274 }
275 BOOST_CHECK(vNodes.back()->fDisconnect == false);
276
277 NodeClockContext clock_ctx{};
278 clock_ctx += MINIMUM_CONNECT_TIME;
279 peerLogic->CheckForStaleTipAndEvictPeers();
280 for (int i = 0; i < max_outbound_block_relay; ++i) {
281 BOOST_CHECK(vNodes[i]->fDisconnect == false);
282 }
283 BOOST_CHECK(vNodes.back()->fDisconnect == true);
284
285 // Update the last block time for the extra peer,
286 // and check that the next youngest peer gets evicted.
287 vNodes.back()->fDisconnect = false;
288 vNodes.back()->m_last_block_time = GetTime<std::chrono::seconds>();
289
290 peerLogic->CheckForStaleTipAndEvictPeers();
291 for (int i = 0; i < max_outbound_block_relay - 1; ++i) {
292 BOOST_CHECK(vNodes[i]->fDisconnect == false);
293 }
294 BOOST_CHECK(vNodes[max_outbound_block_relay - 1]->fDisconnect == true);
295 BOOST_CHECK(vNodes.back()->fDisconnect == false);
296
297 for (const CNode* node : vNodes) {
298 peerLogic->FinalizeNode(*node);
299 }
300 connman->ClearTestNodes();
301}
302
303BOOST_AUTO_TEST_CASE(peer_discouragement)
304{
306
307 auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
308 auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
309 auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
310
311 CNetAddr tor_netaddr;
312 BOOST_REQUIRE(
313 tor_netaddr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"));
314 const CService tor_service{tor_netaddr, Params().GetDefaultPort()};
315
316 const std::array<CAddress, 3> addr{CAddress{ip(0xa0b0c001), NODE_NONE},
317 CAddress{ip(0xa0b0c002), NODE_NONE},
318 CAddress{tor_service, NODE_NONE}};
319
320 const CNetAddr other_addr{ip(0xa0b0ff01)}; // Not any of addr[].
321
322 std::array<CNode*, 3> nodes;
323
324 banman->ClearBanned();
325 NodeId id{0};
326 nodes[0] = new CNode{id++,
327 /*sock=*/nullptr,
328 addr[0],
329 /*nKeyedNetGroupIn=*/0,
330 /*nLocalHostNonceIn=*/0,
331 CAddress(),
332 /*addrNameIn=*/"",
334 /*inbound_onion=*/false,
335 /*network_key=*/1};
336 nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
337 peerLogic->InitializeNode(*nodes[0], NODE_NETWORK);
338 nodes[0]->fSuccessfullyConnected = true;
339 connman->AddTestNode(*nodes[0]);
340 peerLogic->UnitTestMisbehaving(nodes[0]->GetId()); // Should be discouraged
341 BOOST_CHECK(peerLogic->SendMessages(*nodes[0]));
342
343 BOOST_CHECK(banman->IsDiscouraged(addr[0]));
344 BOOST_CHECK(nodes[0]->fDisconnect);
345 BOOST_CHECK(!banman->IsDiscouraged(other_addr)); // Different address, not discouraged
346
347 nodes[1] = new CNode{id++,
348 /*sock=*/nullptr,
349 addr[1],
350 /*nKeyedNetGroupIn=*/1,
351 /*nLocalHostNonceIn=*/1,
352 CAddress(),
353 /*addrNameIn=*/"",
355 /*inbound_onion=*/false,
356 /*network_key=*/1};
357 nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
358 peerLogic->InitializeNode(*nodes[1], NODE_NETWORK);
359 nodes[1]->fSuccessfullyConnected = true;
360 connman->AddTestNode(*nodes[1]);
361 BOOST_CHECK(peerLogic->SendMessages(*nodes[1]));
362 // [0] is still discouraged/disconnected.
363 BOOST_CHECK(banman->IsDiscouraged(addr[0]));
364 BOOST_CHECK(nodes[0]->fDisconnect);
365 // [1] is not discouraged/disconnected yet.
366 BOOST_CHECK(!banman->IsDiscouraged(addr[1]));
367 BOOST_CHECK(!nodes[1]->fDisconnect);
368 peerLogic->UnitTestMisbehaving(nodes[1]->GetId());
369 BOOST_CHECK(peerLogic->SendMessages(*nodes[1]));
370 // Expect both [0] and [1] to be discouraged/disconnected now.
371 BOOST_CHECK(banman->IsDiscouraged(addr[0]));
372 BOOST_CHECK(nodes[0]->fDisconnect);
373 BOOST_CHECK(banman->IsDiscouraged(addr[1]));
374 BOOST_CHECK(nodes[1]->fDisconnect);
375
376 // Make sure non-IP peers are discouraged and disconnected properly.
377
378 nodes[2] = new CNode{id++,
379 /*sock=*/nullptr,
380 addr[2],
381 /*nKeyedNetGroupIn=*/1,
382 /*nLocalHostNonceIn=*/1,
383 CAddress(),
384 /*addrNameIn=*/"",
386 /*inbound_onion=*/false,
387 /*network_key=*/2};
388 nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
389 peerLogic->InitializeNode(*nodes[2], NODE_NETWORK);
390 nodes[2]->fSuccessfullyConnected = true;
391 connman->AddTestNode(*nodes[2]);
392 peerLogic->UnitTestMisbehaving(nodes[2]->GetId());
393 BOOST_CHECK(peerLogic->SendMessages(*nodes[2]));
394 BOOST_CHECK(banman->IsDiscouraged(addr[0]));
395 BOOST_CHECK(banman->IsDiscouraged(addr[1]));
396 BOOST_CHECK(banman->IsDiscouraged(addr[2]));
397 BOOST_CHECK(nodes[0]->fDisconnect);
398 BOOST_CHECK(nodes[1]->fDisconnect);
399 BOOST_CHECK(nodes[2]->fDisconnect);
400
401 for (CNode* node : nodes) {
402 peerLogic->FinalizeNode(*node);
403 }
404 connman->ClearTestNodes();
405}
406
408{
410
411 auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
412 auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
413 auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
414
415 banman->ClearBanned();
416 const NodeClockContext clock_ctx{}; // keep mocktime constant
417
418 CAddress addr(ip(0xa0b0c001), NODE_NONE);
419 NodeId id{0};
420 CNode dummyNode{id++,
421 /*sock=*/nullptr,
422 addr,
423 /*nKeyedNetGroupIn=*/4,
424 /*nLocalHostNonceIn=*/4,
425 CAddress(),
426 /*addrNameIn=*/"",
428 /*inbound_onion=*/false,
429 /*network_key=*/1};
430 dummyNode.SetCommonVersion(PROTOCOL_VERSION);
431 peerLogic->InitializeNode(dummyNode, NODE_NETWORK);
432 dummyNode.fSuccessfullyConnected = true;
433
434 peerLogic->UnitTestMisbehaving(dummyNode.GetId());
435 BOOST_CHECK(peerLogic->SendMessages(dummyNode));
436 BOOST_CHECK(banman->IsDiscouraged(addr));
437
438 peerLogic->FinalizeNode(dummyNode);
439}
440
static constexpr unsigned int DEFAULT_MISBEHAVING_BANTIME
Definition: banman.h:19
node::NodeContext m_node
Definition: bitcoin-gui.cpp:47
const CChainParams & Params()
Return the currently selected parameters.
A CService with information about it as peer.
Definition: protocol.h:367
uint16_t GetDefaultPort() const
Definition: chainparams.h:91
Network address.
Definition: netaddress.h:113
bool IsRoutable() const
Definition: netaddress.cpp:462
bool SetSpecial(std::string_view addr)
Parse a Tor or I2P address and set this object to it.
Definition: netaddress.cpp:212
Information about a peer.
Definition: net.h:680
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:530
static Mutex g_msgproc_mutex
Mutex for anything that is only accessed via the msg processing thread.
Definition: net.h:1030
virtual void FinalizeNode(const CNode &node)=0
Handle removal of a peer (clear state)
virtual bool SendMessages(CNode &node) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex)=0
Send queued protocol messages to a given node.
virtual void InitializeNode(const CNode &node, ServiceFlags our_services)=0
Initialize a peer (setup state)
Helper to initialize the global NodeClock, let a duration elapse, and reset it after use in a test.
Definition: time.h:40
static std::unique_ptr< PeerManager > make(CConnman &connman, AddrMan &addrman, BanMan *banman, ChainstateManager &chainman, CTxMemPool &pool, node::Warnings &warnings, Options opts)
std::vector< B > randbytes(size_t len) noexcept
Generate random bytes.
Definition: random.h:297
uint64_t randbits(int bits) noexcept
Generate a random (bits)-bit integer.
Definition: random.h:204
ConnectionType
Different types of connections to a peer.
@ BLOCK_RELAY
We use block-relay-only connections to help prevent against partition attacks.
@ OUTBOUND_FULL_RELAY
These are the default connections that we use to connect with the network.
@ INBOUND
Inbound connections are those initiated by a peer.
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest)
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
static CService ip(uint32_t i)
static const std::string addr1
Definition: key_tests.cpp:31
Definition: messages.h:21
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS
The maximum number of peer connections to maintain.
Definition: net.h:81
int64_t NodeId
Definition: net.h:103
static const int MAX_OUTBOUND_FULL_RELAY_CONNECTIONS
Maximum number of automatic outgoing nodes over which we'll relay everything (blocks,...
Definition: net.h:69
static const int MAX_BLOCK_RELAY_ONLY_CONNECTIONS
Maximum number of block-relay-only outgoing connections.
Definition: net.h:73
static constexpr auto MINIMUM_CONNECT_TIME
Minimum time an outbound-peer-eviction candidate must be connected for, in order to evict.
std::string OnionToString(std::span< const uint8_t > addr)
Definition: netaddress.cpp:569
static constexpr size_t ADDR_TORV3_SIZE
Size of TORv3 address (in bytes).
Definition: netaddress.h:93
#define BOOST_CHECK(expr)
Definition: object.cpp:16
ServiceFlags
nServices flags
Definition: protocol.h:309
@ NODE_NONE
Definition: protocol.h:312
@ NODE_WITNESS
Definition: protocol.h:320
@ NODE_NETWORK
Definition: protocol.h:315
static const int PROTOCOL_VERSION
network protocol versioning
FastRandomContext m_rng
Definition: setup_common.h:65
int m_max_automatic_connections
Definition: net.h:1077
void AddTestNode(CNode &node)
Definition: net.h:62
void FlushSendBuffer(CNode &node) const
Definition: net.cpp:99
void SetPeerConnectTimeout(std::chrono::seconds timeout)
Definition: net.h:46
void AddRandomOutboundPeer(NodeId &id, std::vector< CNode * > &vNodes, PeerManager &peerLogic, ConnmanTestMsg &connman, ConnectionType connType, bool onion_peer=false)
Testing setup that configures a complete environment.
Definition: setup_common.h:118
std::unique_ptr< CConnman > connman
Definition: context.h:68
std::unique_ptr< CTxMemPool > mempool
Definition: context.h:69
std::unique_ptr< AddrMan > addrman
Definition: context.h:67
std::unique_ptr< ChainstateManager > chainman
Definition: context.h:74
std::unique_ptr< node::Warnings > warnings
Manages all the node warnings.
Definition: context.h:93
std::unique_ptr< PeerManager > peerman
Definition: context.h:72
std::unique_ptr< const NetGroupManager > netgroupman
Definition: context.h:70
#define LOCK(cs)
Definition: sync.h:268
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition: time.cpp:89