PIVX Core  5.6.99
P2P Digital Currency
DoS_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2014 The Bitcoin Core developers
2 // Copyright (c) 2019-2022 The PIVX Core developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 //
7 // Unit tests for denial-of-service detection/prevention code
8 //
9 
10 #include "test/test_pivx.h"
11 
12 #include "arith_uint256.h"
13 #include "keystore.h"
14 #include "net_processing.h"
15 #include "net.h"
16 #include "pubkey.h"
17 #include "pow.h"
18 #include "script/sign.h"
19 #include "serialize.h"
20 #include "util/system.h"
21 #include "validation.h"
22 
23 #include <stdint.h>
24 
25 #include <boost/test/unit_test.hpp>
26 
27 // Tests this internal-to-validation.cpp method:
28 extern bool AddOrphanTx(const CTransactionRef& tx, NodeId peer);
29 extern void EraseOrphansFor(NodeId peer);
30 extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
31 struct COrphanTx {
34  int64_t nTimeExpire;
35 };
37 extern std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(g_cs_orphans);
38 
39 CService ip(uint32_t i)
40 {
41  struct in_addr s;
42  s.s_addr = i;
43  return CService(CNetAddr(s), Params().GetDefaultPort());
44 }
45 
46 static NodeId id = 0;
47 
49 
50 void misbehave(NodeId id, int value) {
51  LOCK(cs_main);
52  Misbehaving(id, value); // Should get banned
53 }
54 
56 {
57  std::atomic<bool> interruptDummy(false);
58 
59  connman->ClearBanned();
60  CAddress addr1(ip(0xa0b0c001), NODE_NONE);
61  CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, "", true);
62  dummyNode1.SetSendVersion(PROTOCOL_VERSION);
63  peerLogic->InitializeNode(&dummyNode1);
64  dummyNode1.nVersion = 1;
65  dummyNode1.fSuccessfullyConnected = true;
66  misbehave(dummyNode1.GetId(), 100); // Should get banned
67  {
68  LOCK2(cs_main, dummyNode1.cs_sendProcessing);
69  peerLogic->SendMessages(&dummyNode1, interruptDummy);
70  }
71  BOOST_CHECK(connman->IsBanned(addr1));
72  BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
73 
74  CAddress addr2(ip(0xa0b0c002), NODE_NONE);
75  CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, "", true);
76  dummyNode2.SetSendVersion(PROTOCOL_VERSION);
77  peerLogic->InitializeNode(&dummyNode2);
78  dummyNode2.nVersion = 1;
79  dummyNode2.fSuccessfullyConnected = true;
80  misbehave(dummyNode2.GetId(), 50);
81  {
82  LOCK2(cs_main, dummyNode2.cs_sendProcessing);
83  peerLogic->SendMessages(&dummyNode2, interruptDummy);
84  }
85  BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet...
86  BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be
87  misbehave(dummyNode2.GetId(), 50);
88  {
89  LOCK2(cs_main, dummyNode2.cs_sendProcessing);
90  peerLogic->SendMessages(&dummyNode2, interruptDummy);
91  }
92  BOOST_CHECK(connman->IsBanned(addr2));
93 }
94 
95 BOOST_AUTO_TEST_CASE(DoS_banscore)
96 {
97  std::atomic<bool> interruptDummy(false);
98 
99  connman->ClearBanned();
100  gArgs.ForceSetArg("-banscore", "111"); // because 11 is my favorite number
101  CAddress addr1(ip(0xa0b0c001), NODE_NONE);
102  CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, "", true);
103  dummyNode1.SetSendVersion(PROTOCOL_VERSION);
104  peerLogic->InitializeNode(&dummyNode1);
105  dummyNode1.nVersion = 1;
106  dummyNode1.fSuccessfullyConnected = true;
107  misbehave(dummyNode1.GetId(), 100);
108  {
109  LOCK2(cs_main, dummyNode1.cs_sendProcessing);
110  peerLogic->SendMessages(&dummyNode1, interruptDummy);
111  }
112  BOOST_CHECK(!connman->IsBanned(addr1));
113  misbehave(dummyNode1.GetId(), 10);
114  {
115  LOCK2(cs_main, dummyNode1.cs_sendProcessing);
116  peerLogic->SendMessages(&dummyNode1, interruptDummy);
117  }
118  BOOST_CHECK(!connman->IsBanned(addr1));
119  misbehave(dummyNode1.GetId(), 1);
120  {
121  LOCK2(cs_main, dummyNode1.cs_sendProcessing);
122  peerLogic->SendMessages(&dummyNode1, interruptDummy);
123  }
124  BOOST_CHECK(connman->IsBanned(addr1));
125  gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD));
126 }
127 
129 {
130  std::atomic<bool> interruptDummy(false);
131 
132  connman->ClearBanned();
133  int64_t nStartTime = GetTime();
134  SetMockTime(nStartTime); // Overrides future calls to GetTime()
135 
136  CAddress addr(ip(0xa0b0c001), NODE_NONE);
137  CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, "", true);
138  dummyNode.SetSendVersion(PROTOCOL_VERSION);
139  peerLogic->InitializeNode(&dummyNode);
140  dummyNode.nVersion = 1;
141  dummyNode.fSuccessfullyConnected = true;
142 
143  misbehave(dummyNode.GetId(), 100);
144  {
145  LOCK2(cs_main, dummyNode.cs_sendProcessing);
146  peerLogic->SendMessages(&dummyNode, interruptDummy);
147  }
148  BOOST_CHECK(connman->IsBanned(addr));
149 
150  SetMockTime(nStartTime+60*60);
151  BOOST_CHECK(connman->IsBanned(addr));
152 
153  SetMockTime(nStartTime+60*60*24+1);
154  BOOST_CHECK(!connman->IsBanned(addr));
155 }
156 
158 {
159  std::map<uint256, COrphanTx>::iterator it;
161  it = mapOrphanTransactions.lower_bound(InsecureRand256());
162  if (it == mapOrphanTransactions.end())
163  it = mapOrphanTransactions.begin();
164  return it->second.tx;
165 }
166 
167 static void MakeNewKeyWithFastRandomContext(CKey& key)
168 {
169  std::vector<unsigned char> keydata;
170  keydata = g_insecure_rand_ctx.randbytes(32);
171  key.Set(keydata.data(), keydata.data() + keydata.size(), /*fCompressedIn*/ true);
172  assert(key.IsValid());
173 }
174 
175 BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
176 {
177  // This test had non-deterministic coverage due to
178  // randomly selected seeds.
179  // This seed is chosen so that all branches of the function
180  // ecdsa_signature_parse_der_lax are executed during this test.
181  // Specifically branches that run only when an ECDSA
182  // signature's R and S values have leading zeros.
184 
185  CKey key;
186  MakeNewKeyWithFastRandomContext(key);
187  CBasicKeyStore keystore;
188  keystore.AddKey(key);
189 
190  // 50 orphan transactions:
191  for (int i = 0; i < 50; i++)
192  {
194  tx.vin.resize(1);
195  tx.vin[0].prevout.n = 0;
196  tx.vin[0].prevout.hash = InsecureRand256();
197  tx.vin[0].scriptSig << OP_1;
198  tx.vout.resize(1);
199  tx.vout[0].nValue = 1*CENT;
200  tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
201 
202  AddOrphanTx(MakeTransactionRef(tx), i);
203  }
204 
205  // ... and 50 that depend on other orphans:
206  for (int i = 0; i < 50; i++)
207  {
208  CTransactionRef txPrev = RandomOrphan();
209 
211  tx.vin.resize(1);
212  tx.vin[0].prevout.n = 0;
213  tx.vin[0].prevout.hash = txPrev->GetHash();
214  tx.vout.resize(1);
215  tx.vout[0].nValue = 1*CENT;
216  tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
217  SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL);
218 
219  AddOrphanTx(MakeTransactionRef(tx), i);
220  }
221 
222  // This really-big orphan should be ignored:
223  for (int i = 0; i < 10; i++)
224  {
225  CTransactionRef txPrev = RandomOrphan();
226 
228  tx.vout.resize(1);
229  tx.vout[0].nValue = 1*CENT;
230  tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
231  tx.vin.resize(2777);
232  for (unsigned int j = 0; j < tx.vin.size(); j++)
233  {
234  tx.vin[j].prevout.n = j;
235  tx.vin[j].prevout.hash = txPrev->GetHash();
236  }
237  SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL);
238  // Re-use same signature for other inputs
239  // (they don't have to be valid for this test)
240  for (unsigned int j = 1; j < tx.vin.size(); j++)
241  tx.vin[j].scriptSig = tx.vin[0].scriptSig;
242 
243  BOOST_CHECK(!AddOrphanTx(MakeTransactionRef(tx), i));
244  }
245 
247  // Test EraseOrphansFor:
248  for (NodeId i = 0; i < 3; i++)
249  {
250  size_t sizeBefore = mapOrphanTransactions.size();
251  EraseOrphansFor(i);
252  BOOST_CHECK(mapOrphanTransactions.size() < sizeBefore);
253  }
254 
255  // Test LimitOrphanTxSize() function:
256  LimitOrphanTxSize(40);
257  BOOST_CHECK(mapOrphanTransactions.size() <= 40);
258  LimitOrphanTxSize(10);
259  BOOST_CHECK(mapOrphanTransactions.size() <= 10);
261  BOOST_CHECK(mapOrphanTransactions.empty());
262 }
263 
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
RecursiveMutex g_cs_orphans
bool AddOrphanTx(const CTransactionRef &tx, NodeId peer)
void EraseOrphansFor(NodeId peer)
For random eviction.
BOOST_AUTO_TEST_CASE(DoS_banning)
Definition: DoS_tests.cpp:55
CTransactionRef RandomOrphan()
Definition: DoS_tests.cpp:157
void misbehave(NodeId id, int value)
Definition: DoS_tests.cpp:50
std::map< uint256, COrphanTx > mapOrphanTransactions GUARDED_BY(g_cs_orphans)
CService ip(uint32_t i)
Definition: DoS_tests.cpp:39
uint256 ArithToUint256(const arith_uint256 &a)
const CChainParams & Params()
Return the currently selected parameters.
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: system.cpp:489
A CService with information about it as peer.
Definition: protocol.h:338
Basic key store, that keeps keys in an address->secret map.
Definition: keystore.h:99
An encapsulated private key.
Definition: key.h:30
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:95
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:186
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:76
virtual bool AddKey(const CKey &key)
Definition: keystore.cpp:14
Network address.
Definition: netaddress.h:120
Information about a peer.
Definition: net.h:669
std::atomic< int > nVersion
Definition: net.h:699
void SetSendVersion(int nVersionIn)
Definition: net.cpp:775
NodeId GetId() const
Definition: net.h:825
RecursiveMutex cs_sendProcessing
Definition: net.h:688
std::atomic_bool fSuccessfullyConnected
Definition: net.h:721
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:167
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:484
Fast randomness source.
Definition: random.h:107
std::vector< unsigned char > randbytes(size_t len)
Generate random bytes.
Definition: random.cpp:632
256-bit unsigned big integer.
#define INVALID_SOCKET
Definition: compat.h:64
BOOST_AUTO_TEST_SUITE_END()
std::unique_ptr< PeerLogicValidation > peerLogic
Definition: init.cpp:91
@ SIGHASH_ALL
Definition: interpreter.h:24
@ LOCK
Definition: lockunlock.h:16
int NodeId
Definition: net.h:109
void Misbehaving(NodeId pnode, int howmuch, const std::string &message) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Increase a node's misbehavior score.
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:80
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
#define BOOST_CHECK(expr)
Definition: object.cpp:17
@ NODE_NONE
Definition: protocol.h:314
@ NODE_NETWORK
Definition: protocol.h:318
@ OP_1
Definition: script.h:59
bool SignSignature(const CKeyStore &keystore, const CScript &fromPubKey, CMutableTransaction &txTo, unsigned int nIn, const CAmount &amount, int nHashType, bool fColdStake)
Produce a script signature for a transaction.
Definition: sign.cpp:192
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a PIVX scriptPubKey for the given CTxDestination.
Definition: standard.cpp:278
A mutable version of CTransaction.
Definition: transaction.h:409
std::vector< CTxOut > vout
Definition: transaction.h:411
std::vector< CTxIn > vin
Definition: transaction.h:410
NodeId fromPeer
int64_t nTimeExpire
CTransactionRef tx
#define LOCK2(cs1, cs2)
Definition: sync.h:221
ArgsManager gArgs
Definition: system.cpp:89
FastRandomContext g_insecure_rand_ctx
Definition: test_pivx.cpp:35
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:456
void SetMockTime(int64_t nMockTimeIn)
For testing.
Definition: utiltime.cpp:51
int64_t GetTime()
DEPRECATED Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable)
Definition: utiltime.cpp:27