Add GetTransactionSigOpCount unit tests

This commit is contained in:
lateminer
2018-11-11 17:11:01 +03:00
parent a1f776cd3c
commit aabee84651
4 changed files with 115 additions and 11 deletions

View File

@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "main.h"
#include "pubkey.h"
#include "key.h"
#include "script/script.h"
@@ -64,4 +65,93 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U);
}
/**
* Verifies script execution of the zeroth scriptPubKey of tx output and
* zeroth scriptSig and witness of tx input.
*/
ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction& input, int flags)
{
ScriptError error;
CTransaction inputi(input);
bool ret = VerifyScript(inputi.vin[0].scriptSig, output.vout[0].scriptPubKey, flags, TransactionSignatureChecker(&inputi, 0, output.vout[0].nValue), &error);
BOOST_CHECK((ret == true) == (error == SCRIPT_ERR_OK));
return error;
}
/**
* Builds a creationTx from scriptPubKey and a spendingTx from scriptSig
* such that spendingTx spends output zero of creationTx.
* Also inserts creationTx's output into the coins view.
*/
void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig)
{
creationTx.nVersion = 1;
creationTx.vin.resize(1);
creationTx.vin[0].prevout.SetNull();
creationTx.vin[0].scriptSig = CScript();
creationTx.vout.resize(1);
creationTx.vout[0].nValue = 1;
creationTx.vout[0].scriptPubKey = scriptPubKey;
spendingTx.nVersion = 1;
spendingTx.vin.resize(1);
spendingTx.vin[0].prevout.hash = creationTx.GetHash();
spendingTx.vin[0].prevout.n = 0;
spendingTx.vin[0].scriptSig = scriptSig;
spendingTx.vout.resize(1);
spendingTx.vout[0].nValue = 1;
spendingTx.vout[0].scriptPubKey = CScript();
coins.ModifyCoins(creationTx.GetHash())->FromTx(creationTx, 0);
}
BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
{
// Transaction creates outputs
CMutableTransaction creationTx;
// Transaction that spends outputs and whose
// sig op cost is going to be tested
CMutableTransaction spendingTx;
// Create utxo set
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
// Create key
CKey key;
key.MakeNewKey(true);
CPubKey pubkey = key.GetPubKey();
// Default flags
int flags = SCRIPT_VERIFY_P2SH;
// Multisig script
{
CScript scriptPubKey = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY;
// Do not use a valid signature to avoid using wallet operations.
CScript scriptSig = CScript() << OP_0 << OP_0;
BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig);
// Legacy counting only includes signature operations in scriptSigs and scriptPubKeys
// of a transaction and does not take the actual executed sig operations into account.
// spendingTx in itself does not contain a signature operation.
assert(GetTransactionSigOpCount(CTransaction(spendingTx), coins, flags) == 0);
// creationTx contains two signature operations in its scriptPubKey, but legacy counting
// is not accurate.
assert(GetTransactionSigOpCount(CTransaction(creationTx), coins, flags) == MAX_PUBKEYS_PER_MULTISIG);
// Sanity check: script verification fails because of an invalid signature.
assert(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY);
}
// Multisig nested in P2SH
{
CScript redeemScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY;
CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
CScript scriptSig = CScript() << OP_0 << OP_0 << ToByteVector(redeemScript);
BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig));
assert(GetTransactionSigOpCount(CTransaction(spendingTx), coins, flags) == 2);
assert(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY);
}
}
BOOST_AUTO_TEST_SUITE_END()