@ -1,7 +1,10 @@
//
//
// Unit tests for denial-of-service detection/prevention code
// Unit tests for denial-of-service detection/prevention code
//
//
# include <algorithm>
# include <boost/assign/list_of.hpp> // for 'map_list_of()'
# include <boost/assign/list_of.hpp> // for 'map_list_of()'
# include <boost/date_time/posix_time/posix_time_types.hpp>
# include <boost/test/unit_test.hpp>
# include <boost/test/unit_test.hpp>
# include <boost/foreach.hpp>
# include <boost/foreach.hpp>
@ -57,7 +60,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
BOOST_CHECK ( ! CNode : : IsBanned ( addr1 ) ) ;
BOOST_CHECK ( ! CNode : : IsBanned ( addr1 ) ) ;
dummyNode1 . Misbehaving ( 1 ) ;
dummyNode1 . Misbehaving ( 1 ) ;
BOOST_CHECK ( CNode : : IsBanned ( addr1 ) ) ;
BOOST_CHECK ( CNode : : IsBanned ( addr1 ) ) ;
mapArgs [ " -banscore " ] = " 100 " ;
mapArgs . erase ( " -banscore " ) ;
}
}
BOOST_AUTO_TEST_CASE ( DoS_bantime )
BOOST_AUTO_TEST_CASE ( DoS_bantime )
@ -220,4 +223,92 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
BOOST_CHECK ( mapOrphanTransactionsByPrev . empty ( ) ) ;
BOOST_CHECK ( mapOrphanTransactionsByPrev . empty ( ) ) ;
}
}
BOOST_AUTO_TEST_CASE ( DoS_checkSig )
{
// Test signature caching code (see key.cpp Verify() methods)
CKey key ;
key . MakeNewKey ( true ) ;
CBasicKeyStore keystore ;
keystore . AddKey ( key ) ;
// 100 orphan transactions:
static const int NPREV = 100 ;
CTransaction orphans [ NPREV ] ;
for ( int i = 0 ; i < NPREV ; i + + )
{
CTransaction & tx = orphans [ i ] ;
tx . vin . resize ( 1 ) ;
tx . vin [ 0 ] . prevout . n = 0 ;
tx . vin [ 0 ] . prevout . hash = GetRandHash ( ) ;
tx . vin [ 0 ] . scriptSig < < OP_1 ;
tx . vout . resize ( 1 ) ;
tx . vout [ 0 ] . nValue = 1 * CENT ;
tx . vout [ 0 ] . scriptPubKey . SetBitcoinAddress ( key . GetPubKey ( ) ) ;
CDataStream ds ( SER_DISK , CLIENT_VERSION ) ;
ds < < tx ;
AddOrphanTx ( ds ) ;
}
// Create a transaction that depends on orphans:
CTransaction tx ;
tx . vout . resize ( 1 ) ;
tx . vout [ 0 ] . nValue = 1 * CENT ;
tx . vout [ 0 ] . scriptPubKey . SetBitcoinAddress ( key . GetPubKey ( ) ) ;
tx . vin . resize ( NPREV ) ;
for ( int j = 0 ; j < tx . vin . size ( ) ; j + + )
{
tx . vin [ j ] . prevout . n = 0 ;
tx . vin [ j ] . prevout . hash = orphans [ j ] . GetHash ( ) ;
}
// Creating signatures primes the cache:
boost : : posix_time : : ptime mst1 = boost : : posix_time : : microsec_clock : : local_time ( ) ;
for ( int j = 0 ; j < tx . vin . size ( ) ; j + + )
BOOST_CHECK ( SignSignature ( keystore , orphans [ j ] , tx , j ) ) ;
boost : : posix_time : : ptime mst2 = boost : : posix_time : : microsec_clock : : local_time ( ) ;
boost : : posix_time : : time_duration msdiff = mst2 - mst1 ;
long nOneValidate = msdiff . total_milliseconds ( ) ;
if ( fDebug ) printf ( " DoS_Checksig sign: %ld \n " , nOneValidate ) ;
// ... now validating repeatedly should be quick:
// 2.8GHz machine, -g build: Sign takes ~760ms,
// uncached Verify takes ~250ms, cached Verify takes ~50ms
// (for 100 single-signature inputs)
mst1 = boost : : posix_time : : microsec_clock : : local_time ( ) ;
for ( int i = 0 ; i < 5 ; i + + )
for ( int j = 0 ; j < tx . vin . size ( ) ; j + + )
BOOST_CHECK ( VerifySignature ( orphans [ j ] , tx , j , true , SIGHASH_ALL ) ) ;
mst2 = boost : : posix_time : : microsec_clock : : local_time ( ) ;
msdiff = mst2 - mst1 ;
long nManyValidate = msdiff . total_milliseconds ( ) ;
if ( fDebug ) printf ( " DoS_Checksig five: %ld \n " , nManyValidate ) ;
BOOST_CHECK_MESSAGE ( nManyValidate < nOneValidate , " Signature cache timing failed " ) ;
// Empty a signature, validation should fail:
CScript save = tx . vin [ 0 ] . scriptSig ;
tx . vin [ 0 ] . scriptSig = CScript ( ) ;
BOOST_CHECK ( ! VerifySignature ( orphans [ 0 ] , tx , 0 , true , SIGHASH_ALL ) ) ;
tx . vin [ 0 ] . scriptSig = save ;
// Swap signatures, validation should fail:
std : : swap ( tx . vin [ 0 ] . scriptSig , tx . vin [ 1 ] . scriptSig ) ;
BOOST_CHECK ( ! VerifySignature ( orphans [ 0 ] , tx , 0 , true , SIGHASH_ALL ) ) ;
BOOST_CHECK ( ! VerifySignature ( orphans [ 1 ] , tx , 1 , true , SIGHASH_ALL ) ) ;
std : : swap ( tx . vin [ 0 ] . scriptSig , tx . vin [ 1 ] . scriptSig ) ;
// Exercise -maxsigcachesize code:
mapArgs [ " -maxsigcachesize " ] = " 10 " ;
// Generate a new, different signature for vin[0] to trigger cache clear:
CScript oldSig = tx . vin [ 0 ] . scriptSig ;
BOOST_CHECK ( SignSignature ( keystore , orphans [ 0 ] , tx , 0 ) ) ;
BOOST_CHECK ( tx . vin [ 0 ] . scriptSig ! = oldSig ) ;
for ( int j = 0 ; j < tx . vin . size ( ) ; j + + )
BOOST_CHECK ( VerifySignature ( orphans [ j ] , tx , j , true , SIGHASH_ALL ) ) ;
mapArgs . erase ( " -maxsigcachesize " ) ;
LimitOrphanTxSize ( 0 ) ;
}
BOOST_AUTO_TEST_SUITE_END ( )
BOOST_AUTO_TEST_SUITE_END ( )