Skip to content

Commit 7a6d96d

Browse files
author
dbkeys
committed
Changes to ensure compatibility with new TLS / SSL Libraries
1 parent 2c236eb commit 7a6d96d

26 files changed

+1769
-631
lines changed

src/DoS_tests.cpp

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

0 commit comments

Comments
 (0)