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
15 #include "script/sign.h"
16 #include "serialize.h"
21 #include <boost/assign/list_of.hpp> // for 'map_list_of()'
22 #include <boost/date_time/posix_time/posix_time_types.hpp>
23 #include <boost/foreach.hpp>
24 #include <boost/test/unit_test.hpp>
26 // Tests this internal-to-main.cpp method:
27 extern bool AddOrphanTx(const CTransaction& tx);
28 extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
29 extern std::map<uint256, CTransaction> mapOrphanTransactions;
30 extern std::map<uint256, std::set<uint256> > mapOrphanTransactionsByPrev;
32 CService ip(uint32_t i)
36 return CService(CNetAddr(s), Params().GetDefaultPort());
39 BOOST_AUTO_TEST_SUITE(DoS_tests)
41 BOOST_AUTO_TEST_CASE(DoS_banning)
44 CAddress addr1(ip(0xa0b0c001));
45 CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
46 dummyNode1.nVersion = 1;
47 Misbehaving(dummyNode1.GetId(), 100); // Should get banned
48 SendMessages(&dummyNode1, false);
49 BOOST_CHECK(CNode::IsBanned(addr1));
50 BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
52 CAddress addr2(ip(0xa0b0c002));
53 CNode dummyNode2(INVALID_SOCKET, addr2, "", true);
54 dummyNode2.nVersion = 1;
55 Misbehaving(dummyNode2.GetId(), 50);
56 SendMessages(&dummyNode2, false);
57 BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
58 BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
59 Misbehaving(dummyNode2.GetId(), 50);
60 SendMessages(&dummyNode2, false);
61 BOOST_CHECK(CNode::IsBanned(addr2));
64 BOOST_AUTO_TEST_CASE(DoS_banscore)
67 mapArgs["-banscore"] = "111"; // because 11 is my favorite number
68 CAddress addr1(ip(0xa0b0c001));
69 CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
70 dummyNode1.nVersion = 1;
71 Misbehaving(dummyNode1.GetId(), 100);
72 SendMessages(&dummyNode1, false);
73 BOOST_CHECK(!CNode::IsBanned(addr1));
74 Misbehaving(dummyNode1.GetId(), 10);
75 SendMessages(&dummyNode1, false);
76 BOOST_CHECK(!CNode::IsBanned(addr1));
77 Misbehaving(dummyNode1.GetId(), 1);
78 SendMessages(&dummyNode1, false);
79 BOOST_CHECK(CNode::IsBanned(addr1));
80 mapArgs.erase("-banscore");
83 BOOST_AUTO_TEST_CASE(DoS_bantime)
86 int64_t nStartTime = GetTime();
87 SetMockTime(nStartTime); // Overrides future calls to GetTime()
89 CAddress addr(ip(0xa0b0c001));
90 CNode dummyNode(INVALID_SOCKET, addr, "", true);
91 dummyNode.nVersion = 1;
93 Misbehaving(dummyNode.GetId(), 100);
94 SendMessages(&dummyNode, false);
95 BOOST_CHECK(CNode::IsBanned(addr));
97 SetMockTime(nStartTime+60*60);
98 BOOST_CHECK(CNode::IsBanned(addr));
100 SetMockTime(nStartTime+60*60*24+1);
101 BOOST_CHECK(!CNode::IsBanned(addr));
104 static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2, int64_t time2)\
107 return CheckNBits(nbits2, time2, nbits1, time1);
108 int64_t deltaTime = time2-time1;
110 return CheckMinWork(nbits2, nbits1, deltaTime);
113 BOOST_AUTO_TEST_CASE(DoS_checknbits)
115 using namespace boost::assign; // for 'map_list_of()'
117 // Timestamps,nBits from the bitcoin block chain.
118 // These are the block-chain checkpoint blocks
119 typedef std::map<int64_t, unsigned int> BlockData;
120 BlockData chainData =
121 map_list_of(1239852051,486604799)(1262749024,486594666)
122 (1279305360,469854461)(1280200847,469830746)(1281678674,469809688)
123 (1296207707,453179945)(1302624061,453036989)(1309640330,437004818)
124 (1313172719,436789733);
126 // Make sure CheckNBits considers every combination of block-chain-lock-in-points
128 BOOST_FOREACH(const BlockData::value_type& i, chainData)
130 BOOST_FOREACH(const BlockData::value_type& j, chainData)
132 BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first));
136 // Test a couple of insane combinations:
137 BlockData::value_type firstcheck = *(chainData.begin());
138 BlockData::value_type lastcheck = *(chainData.rbegin());
140 // First checkpoint difficulty at or a while after the last checkpoint time should fail when
141 // compared to last checkpoint
142 BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*10, lastcheck.second, lastcheck.first));
143 BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*60*24*14, lastcheck.second, lastcheck.first));
145 // ... but OK if enough time passed for difficulty to adjust downward:
146 BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first));
149 CTransaction RandomOrphan()
151 std::map<uint256, CTransaction>::iterator it;
152 it = mapOrphanTransactions.lower_bound(GetRandHash());
153 if (it == mapOrphanTransactions.end())
154 it = mapOrphanTransactions.begin();
158 BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
161 key.MakeNewKey(true);
162 CBasicKeyStore keystore;
163 keystore.AddKey(key);
165 // 50 orphan transactions:
166 for (int i = 0; i < 50; i++)
168 CMutableTransaction tx;
170 tx.vin[0].prevout.n = 0;
171 tx.vin[0].prevout.hash = GetRandHash();
172 tx.vin[0].scriptSig << OP_1;
174 tx.vout[0].nValue = 1*CENT;
175 tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
180 // ... and 50 that depend on other orphans:
181 for (int i = 0; i < 50; i++)
183 CTransaction txPrev = RandomOrphan();
185 CMutableTransaction tx;
187 tx.vin[0].prevout.n = 0;
188 tx.vin[0].prevout.hash = txPrev.GetHash();
190 tx.vout[0].nValue = 1*CENT;
191 tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
192 SignSignature(keystore, txPrev, tx, 0);
197 // This really-big orphan should be ignored:
198 for (int i = 0; i < 10; i++)
200 CTransaction txPrev = RandomOrphan();
202 CMutableTransaction tx;
204 tx.vout[0].nValue = 1*CENT;
205 tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
207 for (unsigned int j = 0; j < tx.vin.size(); j++)
209 tx.vin[j].prevout.n = j;
210 tx.vin[j].prevout.hash = txPrev.GetHash();
212 SignSignature(keystore, txPrev, tx, 0);
213 // Re-use same signature for other inputs
214 // (they don't have to be valid for this test)
215 for (unsigned int j = 1; j < tx.vin.size(); j++)
216 tx.vin[j].scriptSig = tx.vin[0].scriptSig;
218 BOOST_CHECK(!AddOrphanTx(tx));
221 // Test LimitOrphanTxSize() function:
222 LimitOrphanTxSize(40);
223 BOOST_CHECK(mapOrphanTransactions.size() <= 40);
224 LimitOrphanTxSize(10);
225 BOOST_CHECK(mapOrphanTransactions.size() <= 10);
226 LimitOrphanTxSize(0);
227 BOOST_CHECK(mapOrphanTransactions.empty());
228 BOOST_CHECK(mapOrphanTransactionsByPrev.empty());
231 BOOST_AUTO_TEST_SUITE_END()