|
|
@ -231,91 +231,4 @@ 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); |
|
|
|
|
|
|
|
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 100 orphan transactions:
|
|
|
|
|
|
|
|
static const int NPREV=100; |
|
|
|
|
|
|
|
CMutableTransaction orphans[NPREV]; |
|
|
|
|
|
|
|
for (int i = 0; i < NPREV; i++) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
CMutableTransaction& 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.SetDestination(key.GetPubKey().GetID()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AddOrphanTx(tx); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create a transaction that depends on orphans:
|
|
|
|
|
|
|
|
CMutableTransaction tx; |
|
|
|
|
|
|
|
tx.vout.resize(1); |
|
|
|
|
|
|
|
tx.vout[0].nValue = 1*CENT; |
|
|
|
|
|
|
|
tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); |
|
|
|
|
|
|
|
tx.vin.resize(NPREV); |
|
|
|
|
|
|
|
for (unsigned 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 (unsigned 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 (unsigned int i = 0; i < 5; i++) |
|
|
|
|
|
|
|
for (unsigned int j = 0; j < tx.vin.size(); j++) |
|
|
|
|
|
|
|
BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, 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(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, 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(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL)); |
|
|
|
|
|
|
|
BOOST_CHECK(!VerifySignature(CCoins(orphans[1], MEMPOOL_HEIGHT), tx, 1, flags, 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 (unsigned int j = 0; j < tx.vin.size(); j++) |
|
|
|
|
|
|
|
BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL)); |
|
|
|
|
|
|
|
mapArgs.erase("-maxsigcachesize"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LimitOrphanTxSize(0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() |
|
|
|
BOOST_AUTO_TEST_SUITE_END() |
|
|
|