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.
6 // Unit tests for denial-of-service detection/prevention code
16 #include "serialize.h"
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>
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;
31 CService ip(uint32_t i)
35 return CService(CNetAddr(s), Params().GetDefaultPort());
38 BOOST_AUTO_TEST_SUITE(DoS_tests)
40 BOOST_AUTO_TEST_CASE(DoS_banning)
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
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));
63 BOOST_AUTO_TEST_CASE(DoS_banscore)
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");
82 BOOST_AUTO_TEST_CASE(DoS_bantime)
85 int64_t nStartTime = GetTime();
86 SetMockTime(nStartTime); // Overrides future calls to GetTime()
88 CAddress addr(ip(0xa0b0c001));
89 CNode dummyNode(INVALID_SOCKET, addr, "", true);
90 dummyNode.nVersion = 1;
92 Misbehaving(dummyNode.GetId(), 100);
93 SendMessages(&dummyNode, false);
94 BOOST_CHECK(CNode::IsBanned(addr));
96 SetMockTime(nStartTime+60*60);
97 BOOST_CHECK(CNode::IsBanned(addr));
99 SetMockTime(nStartTime+60*60*24+1);
100 BOOST_CHECK(!CNode::IsBanned(addr));
103 static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2, int64_t time2)\
106 return CheckNBits(nbits2, time2, nbits1, time1);
107 int64_t deltaTime = time2-time1;
110 required.SetCompact(ComputeMinWork(nbits1, deltaTime));
112 have.SetCompact(nbits2);
113 return (have <= required);
116 BOOST_AUTO_TEST_CASE(DoS_checknbits)
118 using namespace boost::assign; // for 'map_list_of()'
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);
129 // Make sure CheckNBits considers every combination of block-chain-lock-in-points
131 BOOST_FOREACH(const BlockData::value_type& i, chainData)
133 BOOST_FOREACH(const BlockData::value_type& j, chainData)
135 BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first));
139 // Test a couple of insane combinations:
140 BlockData::value_type firstcheck = *(chainData.begin());
141 BlockData::value_type lastcheck = *(chainData.rbegin());
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));
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));
152 CTransaction RandomOrphan()
154 std::map<uint256, CTransaction>::iterator it;
155 it = mapOrphanTransactions.lower_bound(GetRandHash());
156 if (it == mapOrphanTransactions.end())
157 it = mapOrphanTransactions.begin();
161 BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
164 key.MakeNewKey(true);
165 CBasicKeyStore keystore;
166 keystore.AddKey(key);
168 // 50 orphan transactions:
169 for (int i = 0; i < 50; i++)
173 tx.vin[0].prevout.n = 0;
174 tx.vin[0].prevout.hash = GetRandHash();
175 tx.vin[0].scriptSig << OP_1;
177 tx.vout[0].nValue = 1*CENT;
178 tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
183 // ... and 50 that depend on other orphans:
184 for (int i = 0; i < 50; i++)
186 CTransaction txPrev = RandomOrphan();
190 tx.vin[0].prevout.n = 0;
191 tx.vin[0].prevout.hash = txPrev.GetHash();
193 tx.vout[0].nValue = 1*CENT;
194 tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
195 SignSignature(keystore, txPrev, tx, 0);
200 // This really-big orphan should be ignored:
201 for (int i = 0; i < 10; i++)
203 CTransaction txPrev = RandomOrphan();
207 tx.vout[0].nValue = 1*CENT;
208 tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
210 for (unsigned int j = 0; j < tx.vin.size(); j++)
212 tx.vin[j].prevout.n = j;
213 tx.vin[j].prevout.hash = txPrev.GetHash();
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;
221 BOOST_CHECK(!AddOrphanTx(tx));
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());
234 BOOST_AUTO_TEST_CASE(DoS_checkSig)
236 // Test signature caching code (see key.cpp Verify() methods)
239 key.MakeNewKey(true);
240 CBasicKeyStore keystore;
241 keystore.AddKey(key);
242 unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
244 // 100 orphan transactions:
245 static const int NPREV=100;
246 CTransaction orphans[NPREV];
247 for (int i = 0; i < NPREV; i++)
249 CTransaction& tx = orphans[i];
251 tx.vin[0].prevout.n = 0;
252 tx.vin[0].prevout.hash = GetRandHash();
253 tx.vin[0].scriptSig << OP_1;
255 tx.vout[0].nValue = 1*CENT;
256 tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
261 // Create a transaction that depends on orphans:
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++)
269 tx.vin[j].prevout.n = 0;
270 tx.vin[j].prevout.hash = orphans[j].GetHash();
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);
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);
294 BOOST_CHECK_MESSAGE(nManyValidate < nOneValidate, "Signature cache timing failed");
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;
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);
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");
318 LimitOrphanTxSize(0);
321 BOOST_AUTO_TEST_SUITE_END()