Precompute sighashes
Original version by Nicolas Dorier. Precomputing version by Pieter Wuille.
This commit is contained in:
@@ -107,18 +107,20 @@ BOOST_AUTO_TEST_CASE(sign)
|
||||
}
|
||||
// All of the above should be OK, and the txTos have valid signatures
|
||||
// Check to make sure signature verification fails if we use the wrong ScriptSig:
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (int i = 0; i < 8; i++) {
|
||||
PrecomputedTransactionData txdata(txTo[i]);
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
CScript sigSave = txTo[i].vin[0].scriptSig;
|
||||
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
|
||||
bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false)();
|
||||
bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
|
||||
if (i == j)
|
||||
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
|
||||
else
|
||||
BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
|
||||
txTo[i].vin[0].scriptSig = sigSave;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(norecurse)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "test/test_bitcoin.h"
|
||||
|
||||
#include "clientversion.h"
|
||||
#include "checkqueue.h"
|
||||
#include "consensus/validation.h"
|
||||
#include "core_io.h"
|
||||
#include "key.h"
|
||||
@@ -153,6 +154,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
|
||||
BOOST_CHECK(state.IsValid());
|
||||
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
{
|
||||
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
|
||||
@@ -168,7 +170,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
|
||||
const CScriptWitness *witness = (i < tx.wit.vtxinwit.size()) ? &tx.wit.vtxinwit[i].scriptWitness : NULL;
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
|
||||
witness, verify_flags, TransactionSignatureChecker(&tx, i, amount), &err),
|
||||
witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err),
|
||||
strTest);
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
}
|
||||
@@ -237,6 +239,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
||||
CValidationState state;
|
||||
fValid = CheckTransaction(tx, state) && state.IsValid();
|
||||
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
|
||||
{
|
||||
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
|
||||
@@ -252,7 +255,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
||||
}
|
||||
const CScriptWitness *witness = (i < tx.wit.vtxinwit.size()) ? &tx.wit.vtxinwit[i].scriptWitness : NULL;
|
||||
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
|
||||
witness, verify_flags, TransactionSignatureChecker(&tx, i, amount), &err);
|
||||
witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err);
|
||||
}
|
||||
BOOST_CHECK_MESSAGE(!fValid, strTest);
|
||||
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
@@ -419,6 +422,86 @@ void ReplaceRedeemScript(CScript& script, const CScript& redeemScript)
|
||||
script = PushAll(stack);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
|
||||
CMutableTransaction mtx;
|
||||
mtx.nVersion = 1;
|
||||
|
||||
CKey key;
|
||||
key.MakeNewKey(false);
|
||||
CBasicKeyStore keystore;
|
||||
keystore.AddKeyPubKey(key, key.GetPubKey());
|
||||
CKeyID hash = key.GetPubKey().GetID();
|
||||
CScript scriptPubKey = CScript() << OP_0 << std::vector<unsigned char>(hash.begin(), hash.end());
|
||||
|
||||
vector<int> sigHashes;
|
||||
sigHashes.push_back(SIGHASH_NONE | SIGHASH_ANYONECANPAY);
|
||||
sigHashes.push_back(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY);
|
||||
sigHashes.push_back(SIGHASH_ALL | SIGHASH_ANYONECANPAY);
|
||||
sigHashes.push_back(SIGHASH_NONE);
|
||||
sigHashes.push_back(SIGHASH_SINGLE);
|
||||
sigHashes.push_back(SIGHASH_ALL);
|
||||
|
||||
// create a big transaction of 4500 inputs signed by the same key
|
||||
for(uint32_t ij = 0; ij < 4500; ij++) {
|
||||
uint32_t i = mtx.vin.size();
|
||||
uint256 prevId;
|
||||
prevId.SetHex("0000000000000000000000000000000000000000000000000000000000000100");
|
||||
COutPoint outpoint(prevId, i);
|
||||
|
||||
mtx.vin.resize(mtx.vin.size() + 1);
|
||||
mtx.vin[i].prevout = outpoint;
|
||||
mtx.vin[i].scriptSig = CScript();
|
||||
|
||||
mtx.vout.resize(mtx.vout.size() + 1);
|
||||
mtx.vout[i].nValue = 1000;
|
||||
mtx.vout[i].scriptPubKey = CScript() << OP_1;
|
||||
}
|
||||
|
||||
// sign all inputs
|
||||
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
|
||||
bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size()));
|
||||
assert(hashSigned);
|
||||
}
|
||||
|
||||
CTransaction tx;
|
||||
CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION);
|
||||
WithOrVersion(&ssout, 0) << mtx;
|
||||
WithOrVersion(&ssout, 0) >> tx;
|
||||
|
||||
// check all inputs concurrently, with the cache
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
boost::thread_group threadGroup;
|
||||
CCheckQueue<CScriptCheck> scriptcheckqueue(128);
|
||||
CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue);
|
||||
|
||||
for (int i=0; i<20; i++)
|
||||
threadGroup.create_thread(boost::bind(&CCheckQueue<CScriptCheck>::Thread, boost::ref(scriptcheckqueue)));
|
||||
|
||||
CCoins coins;
|
||||
coins.nVersion = 1;
|
||||
coins.fCoinBase = false;
|
||||
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
|
||||
CTxOut txout;
|
||||
txout.nValue = 1000;
|
||||
txout.scriptPubKey = scriptPubKey;
|
||||
coins.vout.push_back(txout);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
|
||||
std::vector<CScriptCheck> vChecks;
|
||||
CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
|
||||
vChecks.push_back(CScriptCheck());
|
||||
check.swap(vChecks.back());
|
||||
control.Add(vChecks);
|
||||
}
|
||||
|
||||
bool controlCheck = control.Wait();
|
||||
assert(controlCheck);
|
||||
|
||||
threadGroup.interrupt_all();
|
||||
threadGroup.join_all();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_witness)
|
||||
{
|
||||
CBasicKeyStore keystore, keystore2;
|
||||
|
||||
Reference in New Issue
Block a user