|
|
|
@ -231,91 +231,4 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
|
|
|
|
|
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()
|
|
|
|
|