]> Git Repo - VerusCoin.git/blob - src/test/DoS_tests.cpp
d86cc7a290eb6dc81e6860ed010af0719a58a1a7
[VerusCoin.git] / src / test / DoS_tests.cpp
1 // Copyright (c) 2011-2014 The Bitcoin Core developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 //
6 // Unit tests for denial-of-service detection/prevention code
7 //
8
9
10
11 #include "bignum.h"
12 #include "keystore.h"
13 #include "main.h"
14 #include "net.h"
15 #include "script.h"
16 #include "serialize.h"
17
18 #include <stdint.h>
19
20 #include <boost/assign/list_of.hpp> // for 'map_list_of()'
21 #include <boost/date_time/posix_time/posix_time_types.hpp>
22 #include <boost/foreach.hpp>
23 #include <boost/test/unit_test.hpp>
24
25 // Tests this internal-to-main.cpp method:
26 extern bool AddOrphanTx(const CTransaction& tx);
27 extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
28 extern std::map<uint256, CTransaction> mapOrphanTransactions;
29 extern std::map<uint256, std::set<uint256> > mapOrphanTransactionsByPrev;
30
31 CService ip(uint32_t i)
32 {
33     struct in_addr s;
34     s.s_addr = i;
35     return CService(CNetAddr(s), Params().GetDefaultPort());
36 }
37
38 BOOST_AUTO_TEST_SUITE(DoS_tests)
39
40 BOOST_AUTO_TEST_CASE(DoS_banning)
41 {
42     CNode::ClearBanned();
43     CAddress addr1(ip(0xa0b0c001));
44     CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
45     dummyNode1.nVersion = 1;
46     Misbehaving(dummyNode1.GetId(), 100); // Should get banned
47     SendMessages(&dummyNode1, false);
48     BOOST_CHECK(CNode::IsBanned(addr1));
49     BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
50
51     CAddress addr2(ip(0xa0b0c002));
52     CNode dummyNode2(INVALID_SOCKET, addr2, "", true);
53     dummyNode2.nVersion = 1;
54     Misbehaving(dummyNode2.GetId(), 50);
55     SendMessages(&dummyNode2, false);
56     BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
57     BOOST_CHECK(CNode::IsBanned(addr1));  // ... but 1 still should be
58     Misbehaving(dummyNode2.GetId(), 50);
59     SendMessages(&dummyNode2, false);
60     BOOST_CHECK(CNode::IsBanned(addr2));
61 }
62
63 BOOST_AUTO_TEST_CASE(DoS_banscore)
64 {
65     CNode::ClearBanned();
66     mapArgs["-banscore"] = "111"; // because 11 is my favorite number
67     CAddress addr1(ip(0xa0b0c001));
68     CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
69     dummyNode1.nVersion = 1;
70     Misbehaving(dummyNode1.GetId(), 100);
71     SendMessages(&dummyNode1, false);
72     BOOST_CHECK(!CNode::IsBanned(addr1));
73     Misbehaving(dummyNode1.GetId(), 10);
74     SendMessages(&dummyNode1, false);
75     BOOST_CHECK(!CNode::IsBanned(addr1));
76     Misbehaving(dummyNode1.GetId(), 1);
77     SendMessages(&dummyNode1, false);
78     BOOST_CHECK(CNode::IsBanned(addr1));
79     mapArgs.erase("-banscore");
80 }
81
82 BOOST_AUTO_TEST_CASE(DoS_bantime)
83 {
84     CNode::ClearBanned();
85     int64_t nStartTime = GetTime();
86     SetMockTime(nStartTime); // Overrides future calls to GetTime()
87
88     CAddress addr(ip(0xa0b0c001));
89     CNode dummyNode(INVALID_SOCKET, addr, "", true);
90     dummyNode.nVersion = 1;
91
92     Misbehaving(dummyNode.GetId(), 100);
93     SendMessages(&dummyNode, false);
94     BOOST_CHECK(CNode::IsBanned(addr));
95
96     SetMockTime(nStartTime+60*60);
97     BOOST_CHECK(CNode::IsBanned(addr));
98
99     SetMockTime(nStartTime+60*60*24+1);
100     BOOST_CHECK(!CNode::IsBanned(addr));
101 }
102
103 static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2, int64_t time2)\
104 {
105     if (time1 > time2)
106         return CheckNBits(nbits2, time2, nbits1, time1);
107     int64_t deltaTime = time2-time1;
108
109     CBigNum required;
110     required.SetCompact(ComputeMinWork(nbits1, deltaTime));
111     CBigNum have;
112     have.SetCompact(nbits2);
113     return (have <= required);
114 }
115
116 BOOST_AUTO_TEST_CASE(DoS_checknbits)
117 {
118     using namespace boost::assign; // for 'map_list_of()'
119
120     // Timestamps,nBits from the bitcoin block chain.
121     // These are the block-chain checkpoint blocks
122     typedef std::map<int64_t, unsigned int> BlockData;
123     BlockData chainData =
124         map_list_of(1239852051,486604799)(1262749024,486594666)
125         (1279305360,469854461)(1280200847,469830746)(1281678674,469809688)
126         (1296207707,453179945)(1302624061,453036989)(1309640330,437004818)
127         (1313172719,436789733);
128
129     // Make sure CheckNBits considers every combination of block-chain-lock-in-points
130     // "sane":
131     BOOST_FOREACH(const BlockData::value_type& i, chainData)
132     {
133         BOOST_FOREACH(const BlockData::value_type& j, chainData)
134         {
135             BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first));
136         }
137     }
138
139     // Test a couple of insane combinations:
140     BlockData::value_type firstcheck = *(chainData.begin());
141     BlockData::value_type lastcheck = *(chainData.rbegin());
142
143     // First checkpoint difficulty at or a while after the last checkpoint time should fail when
144     // compared to last checkpoint
145     BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*10, lastcheck.second, lastcheck.first));
146     BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*60*24*14, lastcheck.second, lastcheck.first));
147
148     // ... but OK if enough time passed for difficulty to adjust downward:
149     BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first));
150 }
151
152 CTransaction RandomOrphan()
153 {
154     std::map<uint256, CTransaction>::iterator it;
155     it = mapOrphanTransactions.lower_bound(GetRandHash());
156     if (it == mapOrphanTransactions.end())
157         it = mapOrphanTransactions.begin();
158     return it->second;
159 }
160
161 BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
162 {
163     CKey key;
164     key.MakeNewKey(true);
165     CBasicKeyStore keystore;
166     keystore.AddKey(key);
167
168     // 50 orphan transactions:
169     for (int i = 0; i < 50; i++)
170     {
171         CTransaction tx;
172         tx.vin.resize(1);
173         tx.vin[0].prevout.n = 0;
174         tx.vin[0].prevout.hash = GetRandHash();
175         tx.vin[0].scriptSig << OP_1;
176         tx.vout.resize(1);
177         tx.vout[0].nValue = 1*CENT;
178         tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
179
180         AddOrphanTx(tx);
181     }
182
183     // ... and 50 that depend on other orphans:
184     for (int i = 0; i < 50; i++)
185     {
186         CTransaction txPrev = RandomOrphan();
187
188         CTransaction tx;
189         tx.vin.resize(1);
190         tx.vin[0].prevout.n = 0;
191         tx.vin[0].prevout.hash = txPrev.GetHash();
192         tx.vout.resize(1);
193         tx.vout[0].nValue = 1*CENT;
194         tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
195         SignSignature(keystore, txPrev, tx, 0);
196
197         AddOrphanTx(tx);
198     }
199
200     // This really-big orphan should be ignored:
201     for (int i = 0; i < 10; i++)
202     {
203         CTransaction txPrev = RandomOrphan();
204
205         CTransaction tx;
206         tx.vout.resize(1);
207         tx.vout[0].nValue = 1*CENT;
208         tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
209         tx.vin.resize(500);
210         for (unsigned int j = 0; j < tx.vin.size(); j++)
211         {
212             tx.vin[j].prevout.n = j;
213             tx.vin[j].prevout.hash = txPrev.GetHash();
214         }
215         SignSignature(keystore, txPrev, tx, 0);
216         // Re-use same signature for other inputs
217         // (they don't have to be valid for this test)
218         for (unsigned int j = 1; j < tx.vin.size(); j++)
219             tx.vin[j].scriptSig = tx.vin[0].scriptSig;
220
221         BOOST_CHECK(!AddOrphanTx(tx));
222     }
223
224     // Test LimitOrphanTxSize() function:
225     LimitOrphanTxSize(40);
226     BOOST_CHECK(mapOrphanTransactions.size() <= 40);
227     LimitOrphanTxSize(10);
228     BOOST_CHECK(mapOrphanTransactions.size() <= 10);
229     LimitOrphanTxSize(0);
230     BOOST_CHECK(mapOrphanTransactions.empty());
231     BOOST_CHECK(mapOrphanTransactionsByPrev.empty());
232 }
233
234 BOOST_AUTO_TEST_CASE(DoS_checkSig)
235 {
236     // Test signature caching code (see key.cpp Verify() methods)
237
238     CKey key;
239     key.MakeNewKey(true);
240     CBasicKeyStore keystore;
241     keystore.AddKey(key);
242     unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
243
244     // 100 orphan transactions:
245     static const int NPREV=100;
246     CTransaction orphans[NPREV];
247     for (int i = 0; i < NPREV; i++)
248     {
249         CTransaction& tx = orphans[i];
250         tx.vin.resize(1);
251         tx.vin[0].prevout.n = 0;
252         tx.vin[0].prevout.hash = GetRandHash();
253         tx.vin[0].scriptSig << OP_1;
254         tx.vout.resize(1);
255         tx.vout[0].nValue = 1*CENT;
256         tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
257
258         AddOrphanTx(tx);
259     }
260
261     // Create a transaction that depends on orphans:
262     CTransaction tx;
263     tx.vout.resize(1);
264     tx.vout[0].nValue = 1*CENT;
265     tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
266     tx.vin.resize(NPREV);
267     for (unsigned int j = 0; j < tx.vin.size(); j++)
268     {
269         tx.vin[j].prevout.n = 0;
270         tx.vin[j].prevout.hash = orphans[j].GetHash();
271     }
272     // Creating signatures primes the cache:
273     boost::posix_time::ptime mst1 = boost::posix_time::microsec_clock::local_time();
274     for (unsigned int j = 0; j < tx.vin.size(); j++)
275         BOOST_CHECK(SignSignature(keystore, orphans[j], tx, j));
276     boost::posix_time::ptime mst2 = boost::posix_time::microsec_clock::local_time();
277     boost::posix_time::time_duration msdiff = mst2 - mst1;
278     long nOneValidate = msdiff.total_milliseconds();
279     if (fDebug) printf("DoS_Checksig sign: %ld\n", nOneValidate);
280
281     // ... now validating repeatedly should be quick:
282     // 2.8GHz machine, -g build: Sign takes ~760ms,
283     // uncached Verify takes ~250ms, cached Verify takes ~50ms
284     // (for 100 single-signature inputs)
285     mst1 = boost::posix_time::microsec_clock::local_time();
286     for (unsigned int i = 0; i < 5; i++)
287         for (unsigned int j = 0; j < tx.vin.size(); j++)
288             BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL));
289     mst2 = boost::posix_time::microsec_clock::local_time();
290     msdiff = mst2 - mst1;
291     long nManyValidate = msdiff.total_milliseconds();
292     if (fDebug) printf("DoS_Checksig five: %ld\n", nManyValidate);
293
294     BOOST_CHECK_MESSAGE(nManyValidate < nOneValidate, "Signature cache timing failed");
295
296     // Empty a signature, validation should fail:
297     CScript save = tx.vin[0].scriptSig;
298     tx.vin[0].scriptSig = CScript();
299     BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL));
300     tx.vin[0].scriptSig = save;
301
302     // Swap signatures, validation should fail:
303     std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
304     BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL));
305     BOOST_CHECK(!VerifySignature(CCoins(orphans[1], MEMPOOL_HEIGHT), tx, 1, flags, SIGHASH_ALL));
306     std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
307
308     // Exercise -maxsigcachesize code:
309     mapArgs["-maxsigcachesize"] = "10";
310     // Generate a new, different signature for vin[0] to trigger cache clear:
311     CScript oldSig = tx.vin[0].scriptSig;
312     BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0));
313     BOOST_CHECK(tx.vin[0].scriptSig != oldSig);
314     for (unsigned int j = 0; j < tx.vin.size(); j++)
315         BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL));
316     mapArgs.erase("-maxsigcachesize");
317
318     LimitOrphanTxSize(0);
319 }
320
321 BOOST_AUTO_TEST_SUITE_END()
This page took 0.033663 seconds and 2 git commands to generate.