Branch data Line data Source code
# 1 : : // Copyright (c) 2012-2020 The Bitcoin Core developers
# 2 : : // Distributed under the MIT software license, see the accompanying
# 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
# 4 : :
# 5 : : #include <consensus/consensus.h>
# 6 : : #include <consensus/tx_verify.h>
# 7 : : #include <key.h>
# 8 : : #include <pubkey.h>
# 9 : : #include <script/script.h>
# 10 : : #include <script/standard.h>
# 11 : : #include <test/util/setup_common.h>
# 12 : : #include <uint256.h>
# 13 : :
# 14 : : #include <vector>
# 15 : :
# 16 : : #include <boost/test/unit_test.hpp>
# 17 : :
# 18 : : // Helpers:
# 19 : : static std::vector<unsigned char>
# 20 : : Serialize(const CScript& s)
# 21 : 4 : {
# 22 : 4 : std::vector<unsigned char> sSerialized(s.begin(), s.end());
# 23 : 4 : return sSerialized;
# 24 : 4 : }
# 25 : :
# 26 : : BOOST_FIXTURE_TEST_SUITE(sigopcount_tests, BasicTestingSetup)
# 27 : :
# 28 : : BOOST_AUTO_TEST_CASE(GetSigOpCount)
# 29 : 2 : {
# 30 : : // Test CScript::GetSigOpCount()
# 31 : 2 : CScript s1;
# 32 : 2 : BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 0U);
# 33 : 2 : BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 0U);
# 34 : :
# 35 : 2 : uint160 dummy;
# 36 : 2 : s1 << OP_1 << ToByteVector(dummy) << ToByteVector(dummy) << OP_2 << OP_CHECKMULTISIG;
# 37 : 2 : BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 2U);
# 38 : 2 : s1 << OP_IF << OP_CHECKSIG << OP_ENDIF;
# 39 : 2 : BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3U);
# 40 : 2 : BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21U);
# 41 : :
# 42 : 2 : CScript p2sh = GetScriptForDestination(ScriptHash(s1));
# 43 : 2 : CScript scriptSig;
# 44 : 2 : scriptSig << OP_0 << Serialize(s1);
# 45 : 2 : BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U);
# 46 : :
# 47 : 2 : std::vector<CPubKey> keys;
# 48 [ + + ]: 8 : for (int i = 0; i < 3; i++)
# 49 : 6 : {
# 50 : 6 : CKey k;
# 51 : 6 : k.MakeNewKey(true);
# 52 : 6 : keys.push_back(k.GetPubKey());
# 53 : 6 : }
# 54 : 2 : CScript s2 = GetScriptForMultisig(1, keys);
# 55 : 2 : BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3U);
# 56 : 2 : BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20U);
# 57 : :
# 58 : 2 : p2sh = GetScriptForDestination(ScriptHash(s2));
# 59 : 2 : BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0U);
# 60 : 2 : BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0U);
# 61 : 2 : CScript scriptSig2;
# 62 : 2 : scriptSig2 << OP_1 << ToByteVector(dummy) << ToByteVector(dummy) << Serialize(s2);
# 63 : 2 : BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U);
# 64 : 2 : }
# 65 : :
# 66 : : /**
# 67 : : * Verifies script execution of the zeroth scriptPubKey of tx output and
# 68 : : * zeroth scriptSig and witness of tx input.
# 69 : : */
# 70 : : static ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction& input, int flags)
# 71 : 12 : {
# 72 : 12 : ScriptError error;
# 73 : 12 : CTransaction inputi(input);
# 74 : 12 : bool ret = VerifyScript(inputi.vin[0].scriptSig, output.vout[0].scriptPubKey, &inputi.vin[0].scriptWitness, flags, TransactionSignatureChecker(&inputi, 0, output.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &error);
# 75 : 12 : BOOST_CHECK((ret == true) == (error == SCRIPT_ERR_OK));
# 76 : :
# 77 : 12 : return error;
# 78 : 12 : }
# 79 : :
# 80 : : /**
# 81 : : * Builds a creationTx from scriptPubKey and a spendingTx from scriptSig
# 82 : : * and witness such that spendingTx spends output zero of creationTx.
# 83 : : * Also inserts creationTx's output into the coins view.
# 84 : : */
# 85 : : static void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& witness)
# 86 : 16 : {
# 87 : 16 : creationTx.nVersion = 1;
# 88 : 16 : creationTx.vin.resize(1);
# 89 : 16 : creationTx.vin[0].prevout.SetNull();
# 90 : 16 : creationTx.vin[0].scriptSig = CScript();
# 91 : 16 : creationTx.vout.resize(1);
# 92 : 16 : creationTx.vout[0].nValue = 1;
# 93 : 16 : creationTx.vout[0].scriptPubKey = scriptPubKey;
# 94 : :
# 95 : 16 : spendingTx.nVersion = 1;
# 96 : 16 : spendingTx.vin.resize(1);
# 97 : 16 : spendingTx.vin[0].prevout.hash = creationTx.GetHash();
# 98 : 16 : spendingTx.vin[0].prevout.n = 0;
# 99 : 16 : spendingTx.vin[0].scriptSig = scriptSig;
# 100 : 16 : spendingTx.vin[0].scriptWitness = witness;
# 101 : 16 : spendingTx.vout.resize(1);
# 102 : 16 : spendingTx.vout[0].nValue = 1;
# 103 : 16 : spendingTx.vout[0].scriptPubKey = CScript();
# 104 : :
# 105 : 16 : AddCoins(coins, CTransaction(creationTx), 0);
# 106 : 16 : }
# 107 : :
# 108 : : BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
# 109 : 2 : {
# 110 : : // Transaction creates outputs
# 111 : 2 : CMutableTransaction creationTx;
# 112 : : // Transaction that spends outputs and whose
# 113 : : // sig op cost is going to be tested
# 114 : 2 : CMutableTransaction spendingTx;
# 115 : :
# 116 : : // Create utxo set
# 117 : 2 : CCoinsView coinsDummy;
# 118 : 2 : CCoinsViewCache coins(&coinsDummy);
# 119 : : // Create key
# 120 : 2 : CKey key;
# 121 : 2 : key.MakeNewKey(true);
# 122 : 2 : CPubKey pubkey = key.GetPubKey();
# 123 : : // Default flags
# 124 : 2 : int flags = SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH;
# 125 : :
# 126 : : // Multisig script (legacy counting)
# 127 : 2 : {
# 128 : 2 : CScript scriptPubKey = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY;
# 129 : : // Do not use a valid signature to avoid using wallet operations.
# 130 : 2 : CScript scriptSig = CScript() << OP_0 << OP_0;
# 131 : :
# 132 : 2 : BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CScriptWitness());
# 133 : : // Legacy counting only includes signature operations in scriptSigs and scriptPubKeys
# 134 : : // of a transaction and does not take the actual executed sig operations into account.
# 135 : : // spendingTx in itself does not contain a signature operation.
# 136 : 2 : assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 0);
# 137 : : // creationTx contains two signature operations in its scriptPubKey, but legacy counting
# 138 : : // is not accurate.
# 139 : 2 : assert(GetTransactionSigOpCost(CTransaction(creationTx), coins, flags) == MAX_PUBKEYS_PER_MULTISIG * WITNESS_SCALE_FACTOR);
# 140 : : // Sanity check: script verification fails because of an invalid signature.
# 141 : 2 : assert(VerifyWithFlag(CTransaction(creationTx), spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY);
# 142 : 2 : }
# 143 : :
# 144 : : // Multisig nested in P2SH
# 145 : 2 : {
# 146 : 2 : CScript redeemScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY;
# 147 : 2 : CScript scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
# 148 : 2 : CScript scriptSig = CScript() << OP_0 << OP_0 << ToByteVector(redeemScript);
# 149 : :
# 150 : 2 : BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CScriptWitness());
# 151 : 2 : assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 2 * WITNESS_SCALE_FACTOR);
# 152 : 2 : assert(VerifyWithFlag(CTransaction(creationTx), spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY);
# 153 : 2 : }
# 154 : :
# 155 : : // P2WPKH witness program
# 156 : 2 : {
# 157 : 2 : CScript scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkey));
# 158 : 2 : CScript scriptSig = CScript();
# 159 : 2 : CScriptWitness scriptWitness;
# 160 : 2 : scriptWitness.stack.push_back(std::vector<unsigned char>(0));
# 161 : 2 : scriptWitness.stack.push_back(std::vector<unsigned char>(0));
# 162 : :
# 163 : :
# 164 : 2 : BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, scriptWitness);
# 165 : 2 : assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 1);
# 166 : : // No signature operations if we don't verify the witness.
# 167 : 2 : assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags & ~SCRIPT_VERIFY_WITNESS) == 0);
# 168 : 2 : assert(VerifyWithFlag(CTransaction(creationTx), spendingTx, flags) == SCRIPT_ERR_EQUALVERIFY);
# 169 : :
# 170 : : // The sig op cost for witness version != 0 is zero.
# 171 : 2 : assert(scriptPubKey[0] == 0x00);
# 172 : 2 : scriptPubKey[0] = 0x51;
# 173 : 2 : BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, scriptWitness);
# 174 : 2 : assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 0);
# 175 : 2 : scriptPubKey[0] = 0x00;
# 176 : 2 : BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, scriptWitness);
# 177 : :
# 178 : : // The witness of a coinbase transaction is not taken into account.
# 179 : 2 : spendingTx.vin[0].prevout.SetNull();
# 180 : 2 : assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 0);
# 181 : 2 : }
# 182 : :
# 183 : : // P2WPKH nested in P2SH
# 184 : 2 : {
# 185 : 2 : CScript scriptSig = GetScriptForDestination(WitnessV0KeyHash(pubkey));
# 186 : 2 : CScript scriptPubKey = GetScriptForDestination(ScriptHash(scriptSig));
# 187 : 2 : scriptSig = CScript() << ToByteVector(scriptSig);
# 188 : 2 : CScriptWitness scriptWitness;
# 189 : 2 : scriptWitness.stack.push_back(std::vector<unsigned char>(0));
# 190 : 2 : scriptWitness.stack.push_back(std::vector<unsigned char>(0));
# 191 : :
# 192 : 2 : BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, scriptWitness);
# 193 : 2 : assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 1);
# 194 : 2 : assert(VerifyWithFlag(CTransaction(creationTx), spendingTx, flags) == SCRIPT_ERR_EQUALVERIFY);
# 195 : 2 : }
# 196 : :
# 197 : : // P2WSH witness program
# 198 : 2 : {
# 199 : 2 : CScript witnessScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY;
# 200 : 2 : CScript scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
# 201 : 2 : CScript scriptSig = CScript();
# 202 : 2 : CScriptWitness scriptWitness;
# 203 : 2 : scriptWitness.stack.push_back(std::vector<unsigned char>(0));
# 204 : 2 : scriptWitness.stack.push_back(std::vector<unsigned char>(0));
# 205 : 2 : scriptWitness.stack.push_back(std::vector<unsigned char>(witnessScript.begin(), witnessScript.end()));
# 206 : :
# 207 : 2 : BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, scriptWitness);
# 208 : 2 : assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 2);
# 209 : 2 : assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags & ~SCRIPT_VERIFY_WITNESS) == 0);
# 210 : 2 : assert(VerifyWithFlag(CTransaction(creationTx), spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY);
# 211 : 2 : }
# 212 : :
# 213 : : // P2WSH nested in P2SH
# 214 : 2 : {
# 215 : 2 : CScript witnessScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY;
# 216 : 2 : CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
# 217 : 2 : CScript scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
# 218 : 2 : CScript scriptSig = CScript() << ToByteVector(redeemScript);
# 219 : 2 : CScriptWitness scriptWitness;
# 220 : 2 : scriptWitness.stack.push_back(std::vector<unsigned char>(0));
# 221 : 2 : scriptWitness.stack.push_back(std::vector<unsigned char>(0));
# 222 : 2 : scriptWitness.stack.push_back(std::vector<unsigned char>(witnessScript.begin(), witnessScript.end()));
# 223 : :
# 224 : 2 : BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, scriptWitness);
# 225 : 2 : assert(GetTransactionSigOpCost(CTransaction(spendingTx), coins, flags) == 2);
# 226 : 2 : assert(VerifyWithFlag(CTransaction(creationTx), spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY);
# 227 : 2 : }
# 228 : 2 : }
# 229 : :
# 230 : : BOOST_AUTO_TEST_SUITE_END()
|