2 // Unit tests for denial-of-service detection/prevention code
6 #include <boost/assign/list_of.hpp> // for 'map_list_of()'
7 #include <boost/date_time/posix_time/posix_time_types.hpp>
8 #include <boost/test/unit_test.hpp>
9 #include <boost/foreach.hpp>
18 // Tests this internal-to-main.cpp method:
19 extern bool AddOrphanTx(const CDataStream& vMsg);
20 extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
21 extern std::map<uint256, CDataStream*> mapOrphanTransactions;
22 extern std::map<uint256, std::map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
24 CService ip(uint32_t i)
28 return CService(CNetAddr(s), GetDefaultPort());
31 BOOST_AUTO_TEST_SUITE(DoS_tests)
33 BOOST_AUTO_TEST_CASE(DoS_banning)
36 CAddress addr1(ip(0xa0b0c001));
37 CNode dummyNode1(INVALID_SOCKET, addr1, true);
38 dummyNode1.Misbehaving(100); // Should get banned
39 BOOST_CHECK(CNode::IsBanned(addr1));
40 BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different ip, not banned
42 CAddress addr2(ip(0xa0b0c002));
43 CNode dummyNode2(INVALID_SOCKET, addr2, true);
44 dummyNode2.Misbehaving(50);
45 BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
46 BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
47 dummyNode2.Misbehaving(50);
48 BOOST_CHECK(CNode::IsBanned(addr2));
51 BOOST_AUTO_TEST_CASE(DoS_banscore)
54 mapArgs["-banscore"] = "111"; // because 11 is my favorite number
55 CAddress addr1(ip(0xa0b0c001));
56 CNode dummyNode1(INVALID_SOCKET, addr1, true);
57 dummyNode1.Misbehaving(100);
58 BOOST_CHECK(!CNode::IsBanned(addr1));
59 dummyNode1.Misbehaving(10);
60 BOOST_CHECK(!CNode::IsBanned(addr1));
61 dummyNode1.Misbehaving(1);
62 BOOST_CHECK(CNode::IsBanned(addr1));
63 mapArgs.erase("-banscore");
66 BOOST_AUTO_TEST_CASE(DoS_bantime)
69 int64 nStartTime = GetTime();
70 SetMockTime(nStartTime); // Overrides future calls to GetTime()
72 CAddress addr(ip(0xa0b0c001));
73 CNode dummyNode(INVALID_SOCKET, addr, true);
75 dummyNode.Misbehaving(100);
76 BOOST_CHECK(CNode::IsBanned(addr));
78 SetMockTime(nStartTime+60*60);
79 BOOST_CHECK(CNode::IsBanned(addr));
81 SetMockTime(nStartTime+60*60*24+1);
82 BOOST_CHECK(!CNode::IsBanned(addr));
85 static bool CheckNBits(unsigned int nbits1, int64 time1, unsigned int nbits2, int64 time2)\
88 return CheckNBits(nbits2, time2, nbits1, time1);
89 int64 deltaTime = time2-time1;
92 required.SetCompact(ComputeMinWork(nbits1, deltaTime));
94 have.SetCompact(nbits2);
95 return (have <= required);
98 BOOST_AUTO_TEST_CASE(DoS_checknbits)
100 using namespace boost::assign; // for 'map_list_of()'
102 // Timestamps,nBits from the bitcoin blockchain.
103 // These are the block-chain checkpoint blocks
104 typedef std::map<int64, unsigned int> BlockData;
105 BlockData chainData =
106 map_list_of(1239852051,486604799)(1262749024,486594666)
107 (1279305360,469854461)(1280200847,469830746)(1281678674,469809688)
108 (1296207707,453179945)(1302624061,453036989)(1309640330,437004818)
109 (1313172719,436789733);
111 // Make sure CheckNBits considers every combination of block-chain-lock-in-points
113 BOOST_FOREACH(const BlockData::value_type& i, chainData)
115 BOOST_FOREACH(const BlockData::value_type& j, chainData)
117 BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first));
121 // Test a couple of insane combinations:
122 BlockData::value_type firstcheck = *(chainData.begin());
123 BlockData::value_type lastcheck = *(chainData.rbegin());
125 // First checkpoint difficulty at or a while after the last checkpoint time should fail when
126 // compared to last checkpoint
127 BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*10, lastcheck.second, lastcheck.first));
128 BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*60*24*14, lastcheck.second, lastcheck.first));
130 // ... but OK if enough time passed for difficulty to adjust downward:
131 BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first));
135 static uint256 RandomHash()
137 std::vector<unsigned char> randbytes(32);
138 RAND_bytes(&randbytes[0], 32);
139 uint256 randomhash(randbytes);
143 CTransaction RandomOrphan()
145 std::map<uint256, CDataStream*>::iterator it;
146 it = mapOrphanTransactions.lower_bound(RandomHash());
147 if (it == mapOrphanTransactions.end())
148 it = mapOrphanTransactions.begin();
149 const CDataStream* pvMsg = it->second;
151 CDataStream(*pvMsg) >> tx;
155 BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
158 key.MakeNewKey(true);
159 CBasicKeyStore keystore;
160 keystore.AddKey(key);
162 // 50 orphan transactions:
163 for (int i = 0; i < 50; i++)
167 tx.vin[0].prevout.n = 0;
168 tx.vin[0].prevout.hash = RandomHash();
169 tx.vin[0].scriptSig << OP_1;
171 tx.vout[0].nValue = 1*CENT;
172 tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());
174 CDataStream ds(SER_DISK, CLIENT_VERSION);
179 // ... and 50 that depend on other orphans:
180 for (int i = 0; i < 50; i++)
182 CTransaction txPrev = RandomOrphan();
186 tx.vin[0].prevout.n = 0;
187 tx.vin[0].prevout.hash = txPrev.GetHash();
189 tx.vout[0].nValue = 1*CENT;
190 tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());
191 SignSignature(keystore, txPrev, tx, 0);
193 CDataStream ds(SER_DISK, CLIENT_VERSION);
198 // This really-big orphan should be ignored:
199 for (int i = 0; i < 10; i++)
201 CTransaction txPrev = RandomOrphan();
205 tx.vout[0].nValue = 1*CENT;
206 tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());
208 for (int j = 0; j < tx.vin.size(); j++)
210 tx.vin[j].prevout.n = j;
211 tx.vin[j].prevout.hash = txPrev.GetHash();
213 SignSignature(keystore, txPrev, tx, 0);
214 // Re-use same signature for other inputs
215 // (they don't have to be valid for this test)
216 for (int j = 1; j < tx.vin.size(); j++)
217 tx.vin[j].scriptSig = tx.vin[0].scriptSig;
219 CDataStream ds(SER_DISK, CLIENT_VERSION);
221 BOOST_CHECK(!AddOrphanTx(ds));
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);
243 // 100 orphan transactions:
244 static const int NPREV=100;
245 CTransaction orphans[NPREV];
246 for (int i = 0; i < NPREV; i++)
248 CTransaction& tx = orphans[i];
250 tx.vin[0].prevout.n = 0;
251 tx.vin[0].prevout.hash = GetRandHash();
252 tx.vin[0].scriptSig << OP_1;
254 tx.vout[0].nValue = 1*CENT;
255 tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());
257 CDataStream ds(SER_DISK, CLIENT_VERSION);
262 // Create a transaction that depends on orphans:
265 tx.vout[0].nValue = 1*CENT;
266 tx.vout[0].scriptPubKey.SetBitcoinAddress(key.GetPubKey());
267 tx.vin.resize(NPREV);
268 for (int j = 0; j < tx.vin.size(); j++)
270 tx.vin[j].prevout.n = 0;
271 tx.vin[j].prevout.hash = orphans[j].GetHash();
273 // Creating signatures primes the cache:
274 boost::posix_time::ptime mst1 = boost::posix_time::microsec_clock::local_time();
275 for (int j = 0; j < tx.vin.size(); j++)
276 BOOST_CHECK(SignSignature(keystore, orphans[j], tx, j));
277 boost::posix_time::ptime mst2 = boost::posix_time::microsec_clock::local_time();
278 boost::posix_time::time_duration msdiff = mst2 - mst1;
279 long nOneValidate = msdiff.total_milliseconds();
280 if (fDebug) printf("DoS_Checksig sign: %ld\n", nOneValidate);
282 // ... now validating repeatedly should be quick:
283 // 2.8GHz machine, -g build: Sign takes ~760ms,
284 // uncached Verify takes ~250ms, cached Verify takes ~50ms
285 // (for 100 single-signature inputs)
286 mst1 = boost::posix_time::microsec_clock::local_time();
287 for (int i = 0; i < 5; i++)
288 for (int j = 0; j < tx.vin.size(); j++)
289 BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));
290 mst2 = boost::posix_time::microsec_clock::local_time();
291 msdiff = mst2 - mst1;
292 long nManyValidate = msdiff.total_milliseconds();
293 if (fDebug) printf("DoS_Checksig five: %ld\n", nManyValidate);
295 BOOST_CHECK_MESSAGE(nManyValidate < nOneValidate, "Signature cache timing failed");
297 // Empty a signature, validation should fail:
298 CScript save = tx.vin[0].scriptSig;
299 tx.vin[0].scriptSig = CScript();
300 BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));
301 tx.vin[0].scriptSig = save;
303 // Swap signatures, validation should fail:
304 std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
305 BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL));
306 BOOST_CHECK(!VerifySignature(orphans[1], tx, 1, true, SIGHASH_ALL));
307 std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
309 // Exercise -maxsigcachesize code:
310 mapArgs["-maxsigcachesize"] = "10";
311 // Generate a new, different signature for vin[0] to trigger cache clear:
312 CScript oldSig = tx.vin[0].scriptSig;
313 BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0));
314 BOOST_CHECK(tx.vin[0].scriptSig != oldSig);
315 for (int j = 0; j < tx.vin.size(); j++)
316 BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL));
317 mapArgs.erase("-maxsigcachesize");
319 LimitOrphanTxSize(0);
322 BOOST_AUTO_TEST_SUITE_END()