LCOV - code coverage report
Current view: top level - src/test - transaction_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 258 277 93.1 %
Date: 2025-02-23 09:33:43 Functions: 16 16 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2011-2014 The Bitcoin Core developers
       2             : // Copyright (c) 2017-2021 The PIVX Core developers
       3             : // Distributed under the MIT/X11 software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include "test/test_pivx.h"
       7             : 
       8             : #include "test/data/tx_invalid.json.h"
       9             : #include "test/data/tx_valid.json.h"
      10             : 
      11             : #include "consensus/tx_verify.h"
      12             : #include "clientversion.h"
      13             : #include "checkqueue.h"
      14             : #include "core_io.h"
      15             : #include "key.h"
      16             : #include "keystore.h"
      17             : #include "policy/policy.h"
      18             : #include "script/script.h"
      19             : #include "script/script_error.h"
      20             : #include "script/sign.h"
      21             : #include "validation.h"
      22             : 
      23             : #include <boost/algorithm/string/classification.hpp>
      24             : #include <boost/algorithm/string/split.hpp>
      25             : #include <boost/test/unit_test.hpp>
      26             : 
      27             : #include <univalue.h>
      28             : 
      29             : // In script_tests.cpp
      30             : extern UniValue read_json(const std::string& jsondata);
      31             : 
      32             : // Helper
      33          17 : bool IsStandardTx(const CTransaction& tx, int nBlockHeight, std::string& reason)
      34             : {
      35          34 :     return IsStandardTx(MakeTransactionRef(tx), nBlockHeight, reason);
      36             : }
      37             : 
      38             : static std::map<std::string, unsigned int> mapFlagNames = {
      39             :     {std::string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE},
      40             :     {std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH},
      41             :     {std::string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC},
      42             :     {std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG},
      43             :     {std::string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S},
      44             :     {std::string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY},
      45             :     {std::string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA},
      46             :     {std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY},
      47             :     {std::string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS},
      48             :     {std::string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK},
      49             :     {std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
      50             :     {std::string("EXCHANGEADDRVERIFY"), (unsigned int)SCRIPT_VERIFY_EXCHANGEADDR},
      51             : };
      52             : 
      53        1116 : unsigned int ParseScriptFlags(std::string strFlags)
      54             : {
      55        1116 :     if (strFlags.empty()) {
      56             :         return 0;
      57             :     }
      58         998 :     unsigned int flags = 0;
      59         998 :     std::vector<std::string> words;
      60         998 :     boost::algorithm::split(words, strFlags, boost::algorithm::is_any_of(","));
      61             : 
      62        2766 :     for (std::string word : words)
      63             :     {
      64        3536 :         if (!mapFlagNames.count(word))
      65           0 :             BOOST_ERROR("Bad test: unknown verification flag '" << word << "'");
      66        1768 :         flags |= mapFlagNames[word];
      67             :     }
      68             : 
      69         998 :     return flags;
      70             : }
      71             : 
      72          82 : std::string FormatScriptFlags(unsigned int flags)
      73             : {
      74          82 :     if (flags == 0) {
      75          39 :         return "";
      76             :     }
      77         125 :     std::string ret;
      78          43 :     std::map<std::string, unsigned int>::const_iterator it = mapFlagNames.begin();
      79         559 :     while (it != mapFlagNames.end()) {
      80         516 :         if (flags & it->second) {
      81          92 :             ret += it->first + ",";
      82             :         }
      83         559 :         it++;
      84             :     }
      85          43 :     return ret.substr(0, ret.size() - 1);
      86             : }
      87             : 
      88             : BOOST_FIXTURE_TEST_SUITE(transaction_tests, TestingSetup)
      89             : 
      90           2 : BOOST_AUTO_TEST_CASE(tx_valid)
      91             : {
      92             :     // Read tests from test/data/tx_valid.json
      93             :     // Format is an array of arrays
      94             :     // Inner arrays are either [ "comment" ]
      95             :     // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, verifyFlags
      96             :     // ... where all scripts are stringified scripts.
      97             :     //
      98             :     // verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
      99           3 :     UniValue tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
     100             : 
     101           1 :     ScriptError err;
     102         115 :     for (unsigned int idx = 0; idx < tests.size(); idx++) {
     103         114 :         UniValue test = tests[idx];
     104         228 :         std::string strTest = test.write();
     105         114 :         if (test[0].isArray())
     106             :         {
     107          50 :             if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
     108             :             {
     109           0 :                 BOOST_ERROR("Bad test: " << strTest);
     110           0 :                 continue;
     111             :             }
     112             : 
     113         100 :             std::map<COutPoint, CScript> mapprevOutScriptPubKeys;
     114         100 :             UniValue inputs = test[0].get_array();
     115         108 :             bool fValid = true;
     116         108 :         for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
     117          58 :             const UniValue& input = inputs[inpIdx];
     118          58 :                 if (!input.isArray())
     119             :                 {
     120             :                     fValid = false;
     121           0 :                     break;
     122             :                 }
     123          58 :                 UniValue vinput = input.get_array();
     124          58 :                 if (vinput.size() != 3)
     125             :                 {
     126           0 :                     fValid = false;
     127           0 :                     break;
     128             :                 }
     129             : 
     130         228 :                 mapprevOutScriptPubKeys[COutPoint(uint256S(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str());
     131             :             }
     132          50 :             if (!fValid)
     133             :             {
     134           0 :                 BOOST_ERROR("Bad test: " << strTest);
     135           0 :                 continue;
     136             :             }
     137             : 
     138         100 :             std::string transaction = test[1].get_str();
     139         150 :             CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
     140         100 :             CTransaction tx(deserialize, stream);
     141             : 
     142         100 :             CValidationState state;
     143         100 :             BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, false), strTest);
     144         100 :             BOOST_CHECK(state.IsValid());
     145             : 
     146          50 :             PrecomputedTransactionData precomTxData(tx);
     147         108 :             for (unsigned int i = 0; i < tx.vin.size(); i++)
     148             :             {
     149          58 :                 if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
     150             :                 {
     151           0 :                     BOOST_ERROR("Bad test: " << strTest);
     152           0 :                     break;
     153             :                 }
     154             : 
     155          58 :                 CAmount amount = 0;
     156         116 :                 unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
     157         174 :                 BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
     158             :                                                  verify_flags, TransactionSignatureChecker(&tx, i, amount, precomTxData), tx.GetRequiredSigVersion(), &err),
     159             :                                     strTest);
     160         116 :                 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
     161             :             }
     162             :         }
     163             :     }
     164           1 : }
     165             : 
     166           2 : BOOST_AUTO_TEST_CASE(tx_invalid)
     167             : {
     168             :     // Read tests from test/data/tx_invalid.json
     169             :     // Format is an array of arrays
     170             :     // Inner arrays are either [ "comment" ]
     171             :     // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, verifyFlags
     172             :     // ... where all scripts are stringified scripts.
     173             :     //
     174             :     // verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
     175           3 :     UniValue tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
     176             : 
     177           1 :     ScriptError err;
     178          87 :     for (unsigned int idx = 0; idx < tests.size(); idx++) {
     179          86 :         UniValue test = tests[idx];
     180         172 :         std::string strTest = test.write();
     181          86 :         if (test[0].isArray())
     182             :         {
     183          38 :             if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
     184             :             {
     185           0 :                 BOOST_ERROR("Bad test: " << strTest);
     186           0 :                 continue;
     187             :             }
     188             : 
     189          76 :             std::map<COutPoint, CScript> mapprevOutScriptPubKeys;
     190          76 :             UniValue inputs = test[0].get_array();
     191          78 :             bool fValid = true;
     192          78 :         for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
     193          40 :             const UniValue& input = inputs[inpIdx];
     194          40 :                 if (!input.isArray())
     195             :                 {
     196             :                     fValid = false;
     197           0 :                     break;
     198             :                 }
     199          40 :                 UniValue vinput = input.get_array();
     200          40 :                 if (vinput.size() != 3)
     201             :                 {
     202           0 :                     fValid = false;
     203           0 :                     break;
     204             :                 }
     205             : 
     206         158 :                 mapprevOutScriptPubKeys[COutPoint(uint256S(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str());
     207             :             }
     208          38 :             if (!fValid)
     209             :             {
     210           0 :                 BOOST_ERROR("Bad test: " << strTest);
     211           0 :                 continue;
     212             :             }
     213             : 
     214          76 :             std::string transaction = test[1].get_str();
     215         114 :             CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
     216          76 :             CTransaction tx(deserialize, stream);
     217             : 
     218          76 :             CValidationState state;
     219          38 :             fValid = CheckTransaction(tx, state, false) && state.IsValid();
     220             : 
     221          38 :             PrecomputedTransactionData precomTxData(tx);
     222          52 :             for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
     223             :             {
     224          14 :                 if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
     225             :                 {
     226           0 :                     BOOST_ERROR("Bad test: " << strTest);
     227           0 :                     break;
     228             :                 }
     229             : 
     230          14 :                 CAmount amount = 0;
     231          28 :                 unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
     232          28 :                 fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
     233          28 :                                       verify_flags, TransactionSignatureChecker(&tx, i, amount, precomTxData), tx.GetRequiredSigVersion(), &err);
     234             :             }
     235          76 :             BOOST_CHECK_MESSAGE(!fValid, strTest);
     236          76 :             BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));
     237             :         }
     238             :     }
     239           1 : }
     240             : 
     241           2 : BOOST_AUTO_TEST_CASE(basic_transaction_tests)
     242             : {
     243             :     // Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436)
     244           1 :     unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00};
     245           1 :     std::vector<unsigned char> vch(ch, ch + sizeof(ch) -1);
     246           2 :     CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
     247           2 :     CMutableTransaction tx;
     248           1 :     stream >> tx;
     249           2 :     CValidationState state;
     250           2 :     BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, false) && state.IsValid(), "Simple deserialized transaction should be valid.");
     251             : 
     252             :     // Check that duplicate txins fail
     253           1 :     tx.vin.push_back(tx.vin[0]);
     254           2 :     BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state, false) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
     255           1 : }
     256             : 
     257             : //
     258             : // Helper: create two dummy transactions, each with
     259             : // two outputs.  The first has 11 and 50 CENT outputs
     260             : // paid to a TX_PUBKEY, the second 21 and 22 CENT outputs
     261             : // paid to a TX_PUBKEYHASH.
     262             : //
     263             : static std::vector<CMutableTransaction>
     264           2 : SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
     265             : {
     266           2 :     std::vector<CMutableTransaction> dummyTransactions;
     267           2 :     dummyTransactions.resize(2);
     268             : 
     269             :     // Add some keys to the keystore:
     270          20 :     CKey key[4];
     271          10 :     for (int i = 0; i < 4; i++)
     272             :     {
     273           8 :         key[i].MakeNewKey(i % 2);
     274           8 :         keystoreRet.AddKey(key[i]);
     275             :     }
     276             : 
     277             :     // Create some dummy input transactions
     278           2 :     dummyTransactions[0].vout.resize(2);
     279           2 :     dummyTransactions[0].vout[0].nValue = 11*CENT;
     280           2 :     dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
     281           2 :     dummyTransactions[0].vout[1].nValue = 50*CENT;
     282           2 :     dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
     283           2 :     AddCoins(coinsRet, dummyTransactions[0], 0);
     284             : 
     285           2 :     dummyTransactions[1].vout.resize(2);
     286           2 :     dummyTransactions[1].vout[0].nValue = 21*CENT;
     287           2 :     dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
     288           2 :     dummyTransactions[1].vout[1].nValue = 22*CENT;
     289           2 :     dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
     290           2 :     AddCoins(coinsRet, dummyTransactions[1], 0);
     291             : 
     292           4 :     return dummyTransactions;
     293             : }
     294             : 
     295           2 : BOOST_AUTO_TEST_CASE(test_Get)
     296             : {
     297           1 :     CBasicKeyStore keystore;
     298           1 :     CCoinsView coinsDummy;
     299           2 :     CCoinsViewCache coins(&coinsDummy);
     300           2 :     std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
     301             : 
     302           2 :     CMutableTransaction t1;
     303           1 :     t1.vin.resize(3);
     304           1 :     t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
     305           1 :     t1.vin[0].prevout.n = 1;
     306           1 :     t1.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
     307           1 :     t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();
     308           1 :     t1.vin[1].prevout.n = 0;
     309           2 :     t1.vin[1].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
     310           1 :     t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();
     311           1 :     t1.vin[2].prevout.n = 1;
     312           2 :     t1.vin[2].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
     313           1 :     t1.vout.resize(2);
     314           1 :     t1.vout[0].nValue = 90*CENT;
     315           1 :     t1.vout[0].scriptPubKey << OP_1;
     316             : 
     317           2 :     BOOST_CHECK(AreInputsStandard(t1, coins));
     318           1 :     BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT);
     319           1 : }
     320             : 
     321           2 : BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
     322           1 :     CMutableTransaction mtx;
     323           1 :     mtx.nVersion = CTransaction::TxVersion::SAPLING;
     324             : 
     325           2 :     CKey key;
     326           1 :     key.MakeNewKey(false);
     327           2 :     CBasicKeyStore keystore;
     328           1 :     keystore.AddKeyPubKey(key, key.GetPubKey());
     329           1 :     CKeyID hash = key.GetPubKey().GetID();
     330           2 :     CScript scriptPubKey = GetScriptForDestination(hash);
     331             : 
     332           2 :     std::vector<int> sigHashes;
     333           1 :     sigHashes.push_back(SIGHASH_NONE | SIGHASH_ANYONECANPAY);
     334           1 :     sigHashes.push_back(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY);
     335           1 :     sigHashes.push_back(SIGHASH_ALL | SIGHASH_ANYONECANPAY);
     336           1 :     sigHashes.push_back(SIGHASH_NONE);
     337           1 :     sigHashes.push_back(SIGHASH_SINGLE);
     338           1 :     sigHashes.push_back(SIGHASH_ALL);
     339             : 
     340             :     // create a big transaction of 4500 inputs signed by the same key
     341        4501 :     for(uint32_t ij = 0; ij < 4500; ij++) {
     342        4500 :         uint32_t i = mtx.vin.size();
     343        4500 :         uint256 prevId;
     344        4500 :         prevId.SetHex("0000000000000000000000000000000000000000000000000000000000000100");
     345        4500 :         COutPoint outpoint(prevId, i);
     346             : 
     347        4500 :         mtx.vin.resize(mtx.vin.size() + 1);
     348        4500 :         mtx.vin[i].prevout = outpoint;
     349        4500 :         mtx.vin[i].scriptSig = CScript();
     350             : 
     351        4500 :         mtx.vout.resize(mtx.vout.size() + 1);
     352        4500 :         mtx.vout[i].nValue = 1000;
     353        4500 :         mtx.vout[i].scriptPubKey = CScript() << OP_1;
     354             :     }
     355             : 
     356             :     // sign all inputs
     357        4501 :     for(uint32_t i = 0; i < mtx.vin.size(); i++) {
     358        4500 :         bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size()));
     359        4500 :         assert(hashSigned);
     360             :     }
     361             : 
     362           2 :     CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION);
     363           1 :     ssout << mtx;
     364           2 :     CTransaction tx(deserialize, ssout);
     365             : 
     366             :     // check all inputs concurrently, with the cache
     367           1 :     PrecomputedTransactionData precomTxData(tx);
     368           2 :     boost::thread_group threadGroup;
     369           1 :     CCheckQueue<CScriptCheck> scriptcheckqueue(128);
     370           2 :     CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue);
     371             : 
     372          21 :     for (int i=0; i<20; i++)
     373          20 :         threadGroup.create_thread(std::bind(&CCheckQueue<CScriptCheck>::Thread, std::ref(scriptcheckqueue)));
     374             : 
     375           2 :     std::vector<Coin> coins;
     376        4501 :     for(uint32_t i = 0; i < mtx.vin.size(); i++) {
     377        9000 :         Coin coin;
     378        4500 :         coin.nHeight = 1;
     379        4500 :         coin.out.nValue = 1000;
     380        4500 :         coin.out.scriptPubKey = scriptPubKey;
     381        4500 :         coins.emplace_back(std::move(coin));
     382             :     }
     383             : 
     384        4501 :     for(uint32_t i = 0; i < mtx.vin.size(); i++) {
     385        4500 :         std::vector<CScriptCheck> vChecks;
     386        9000 :         CScriptCheck check(coins[tx.vin[i].prevout.n].out, tx, i, SCRIPT_VERIFY_P2SH, false, &precomTxData);
     387        4500 :         vChecks.emplace_back();
     388        4500 :         check.swap(vChecks.back());
     389        9000 :         control.Add(vChecks);
     390             :     }
     391             : 
     392           1 :     bool controlCheck = control.Wait();
     393           1 :     assert(controlCheck);
     394             : 
     395           1 :     threadGroup.interrupt_all();
     396           1 :     threadGroup.join_all();
     397           1 : }
     398             : 
     399           2 : BOOST_AUTO_TEST_CASE(test_IsStandard)
     400             : {
     401           1 :     LOCK(cs_main);
     402           2 :     CBasicKeyStore keystore;
     403           1 :     CCoinsView coinsDummy;
     404           2 :     CCoinsViewCache coins(&coinsDummy);
     405           2 :     std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
     406             : 
     407           1 :     CMutableTransaction t;
     408           1 :     t.vin.resize(1);
     409           1 :     t.vin[0].prevout.hash = dummyTransactions[0].GetHash();
     410           1 :     t.vin[0].prevout.n = 1;
     411           1 :     t.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
     412           1 :     t.vout.resize(1);
     413           1 :     t.vout[0].nValue = 90*CENT;
     414           2 :     CKey key;
     415           1 :     key.MakeNewKey(true);
     416           1 :     t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
     417             : 
     418           2 :     std::string reason;
     419           2 :     BOOST_CHECK(IsStandardTx(t, 0, reason));
     420             : 
     421             :     // Check dust with default relay fee:
     422           1 :     CAmount nDustThreshold = GetDustThreshold(dustRelayFee);
     423           1 :     BOOST_CHECK_EQUAL(nDustThreshold, 5460);
     424             :     // dust:
     425           1 :     t.vout[0].nValue = nDustThreshold - 1;
     426           2 :     BOOST_CHECK(!IsStandardTx(t, 0, reason));
     427             :     // not dust:
     428           1 :     t.vout[0].nValue = nDustThreshold;
     429           2 :     BOOST_CHECK(IsStandardTx(t, 0, reason));
     430             : 
     431             :     // Check dust with odd relay fee to verify rounding:
     432             :     // nDustThreshold = 182 * 3702 / 1000
     433           1 :     dustRelayFee = CFeeRate(3702);
     434             :     // dust:
     435           1 :     t.vout[0].nValue = 673 - 1;
     436           2 :     BOOST_CHECK(!IsStandardTx(t, 0, reason));
     437             :     // not dust:
     438           1 :     t.vout[0].nValue = 673;
     439           2 :     BOOST_CHECK(IsStandardTx(t, 0, reason));
     440           1 :     dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
     441             : 
     442           1 :     t.vout[0].scriptPubKey = CScript() << OP_1;
     443           2 :     BOOST_CHECK(!IsStandardTx(t, 0, reason));
     444             : 
     445             :     // MAX_OP_RETURN_RELAY-byte TX_NULL_DATA (standard)
     446           2 :     t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
     447           2 :     BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size());
     448           2 :     BOOST_CHECK(IsStandardTx(t, 0, reason));
     449             : 
     450             :     // MAX_OP_RETURN_RELAY+1-byte TX_NULL_DATA (non-standard)
     451           2 :     t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
     452           2 :     BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size());
     453           2 :     BOOST_CHECK(!IsStandardTx(t, 0, reason));
     454             : 
     455             :     // Data payload can be encoded in any way...
     456           1 :     t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("");
     457           2 :     BOOST_CHECK(IsStandardTx(t, 0, reason));
     458           3 :     t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("00") << ParseHex("01");
     459           2 :     BOOST_CHECK(IsStandardTx(t, 0, reason));
     460             :     // OP_RESERVED *is* considered to be a PUSHDATA type opcode by IsPushOnly()!
     461           2 :     t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RESERVED << -1 << 0 << ParseHex("01") << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16;
     462           2 :     BOOST_CHECK(IsStandardTx(t, 0, reason));
     463           3 :     t.vout[0].scriptPubKey = CScript() << OP_RETURN << 0 << ParseHex("01") << 2 << ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
     464           2 :     BOOST_CHECK(IsStandardTx(t, 0, reason));
     465             : 
     466             :     // ...so long as it only contains PUSHDATA's
     467           1 :     t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RETURN;
     468           2 :     BOOST_CHECK(!IsStandardTx(t, 0, reason));
     469             : 
     470             :     // TX_NULL_DATA w/o PUSHDATA
     471           1 :     t.vout.resize(1);
     472           1 :     t.vout[0].scriptPubKey = CScript() << OP_RETURN;
     473           2 :     BOOST_CHECK(IsStandardTx(t, 0, reason));
     474             : 
     475             :     // Only one TX_NULL_DATA permitted in all cases
     476           1 :     t.vout.resize(2);
     477           2 :     t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
     478           2 :     t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
     479           2 :     BOOST_CHECK(!IsStandardTx(t, 0, reason));
     480             : 
     481           2 :     t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
     482           1 :     t.vout[1].scriptPubKey = CScript() << OP_RETURN;
     483           2 :     BOOST_CHECK(!IsStandardTx(t, 0, reason));
     484             : 
     485           1 :     t.vout[0].scriptPubKey = CScript() << OP_RETURN;
     486           1 :     t.vout[1].scriptPubKey = CScript() << OP_RETURN;
     487           2 :     BOOST_CHECK(!IsStandardTx(t, 0, reason));
     488           1 : }
     489             : 
     490             : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.14