Bitcoin Core 29.99.0
P2P Digital Currency
script_assets_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-present 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
7#include <script/script.h>
8#include <script/sigcache.h>
9#include <script/sign.h>
11#include <span.h>
12#include <streams.h>
13#include <test/util/json.h>
14#include <util/check.h>
15#include <util/fs.h>
16#include <util/strencodings.h>
17
18#include <cstdint>
19#include <cstdlib>
20#include <fstream>
21#include <utility>
22#include <vector>
23
24#include <boost/test/unit_test.hpp>
25
26#include <univalue.h>
27
28unsigned int ParseScriptFlags(std::string strFlags);
29
30BOOST_AUTO_TEST_SUITE(script_assets_tests)
31
32template <typename T>
33CScript ToScript(const T& byte_container)
34{
35 auto span{MakeUCharSpan(byte_container)};
36 return {span.begin(), span.end()};
37}
38
39static CScript ScriptFromHex(const std::string& str)
40{
41 return ToScript(*Assert(TryParseHex(str)));
42}
43
44static CMutableTransaction TxFromHex(const std::string& str)
45{
48 return tx;
49}
50
51static std::vector<CTxOut> TxOutsFromJSON(const UniValue& univalue)
52{
53 assert(univalue.isArray());
54 std::vector<CTxOut> prevouts;
55 for (size_t i = 0; i < univalue.size(); ++i) {
56 CTxOut txout;
57 SpanReader{ParseHex(univalue[i].get_str())} >> txout;
58 prevouts.push_back(std::move(txout));
59 }
60 return prevouts;
61}
62
64{
65 assert(univalue.isArray());
66 CScriptWitness scriptwitness;
67 for (size_t i = 0; i < univalue.size(); ++i) {
68 auto bytes = ParseHex(univalue[i].get_str());
69 scriptwitness.stack.push_back(std::move(bytes));
70 }
71 return scriptwitness;
72}
73
74static std::vector<unsigned int> AllConsensusFlags()
75{
76 std::vector<unsigned int> ret;
77
78 for (unsigned int i = 0; i < 128; ++i) {
79 unsigned int flag = 0;
80 if (i & 1) flag |= SCRIPT_VERIFY_P2SH;
81 if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
82 if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY;
83 if (i & 8) flag |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
84 if (i & 16) flag |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
85 if (i & 32) flag |= SCRIPT_VERIFY_WITNESS;
86 if (i & 64) flag |= SCRIPT_VERIFY_TAPROOT;
87
88 // SCRIPT_VERIFY_WITNESS requires SCRIPT_VERIFY_P2SH
89 if (flag & SCRIPT_VERIFY_WITNESS && !(flag & SCRIPT_VERIFY_P2SH)) continue;
90 // SCRIPT_VERIFY_TAPROOT requires SCRIPT_VERIFY_WITNESS
91 if (flag & SCRIPT_VERIFY_TAPROOT && !(flag & SCRIPT_VERIFY_WITNESS)) continue;
92
93 ret.push_back(flag);
94 }
95
96 return ret;
97}
98
100static const std::vector<unsigned int> ALL_CONSENSUS_FLAGS = AllConsensusFlags();
101
102static void AssetTest(const UniValue& test, SignatureCache& signature_cache)
103{
104 BOOST_CHECK(test.isObject());
105
106 CMutableTransaction mtx = TxFromHex(test["tx"].get_str());
107 const std::vector<CTxOut> prevouts = TxOutsFromJSON(test["prevouts"]);
108 BOOST_CHECK(prevouts.size() == mtx.vin.size());
109 size_t idx = test["index"].getInt<int64_t>();
110 uint32_t test_flags{ParseScriptFlags(test["flags"].get_str())};
111 bool fin = test.exists("final") && test["final"].get_bool();
112
113 if (test.exists("success")) {
114 mtx.vin[idx].scriptSig = ScriptFromHex(test["success"]["scriptSig"].get_str());
115 mtx.vin[idx].scriptWitness = ScriptWitnessFromJSON(test["success"]["witness"]);
116 CTransaction tx(mtx);
118 txdata.Init(tx, std::vector<CTxOut>(prevouts));
119 CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, signature_cache, txdata);
120
121 for (const auto flags : ALL_CONSENSUS_FLAGS) {
122 // "final": true tests are valid for all flags. Others are only valid with flags that are
123 // a subset of test_flags.
124 if (fin || ((flags & test_flags) == flags)) {
125 bool ret = VerifyScript(tx.vin[idx].scriptSig, prevouts[idx].scriptPubKey, &tx.vin[idx].scriptWitness, flags, txcheck, nullptr);
127 }
128 }
129 }
130
131 if (test.exists("failure")) {
132 mtx.vin[idx].scriptSig = ScriptFromHex(test["failure"]["scriptSig"].get_str());
133 mtx.vin[idx].scriptWitness = ScriptWitnessFromJSON(test["failure"]["witness"]);
134 CTransaction tx(mtx);
136 txdata.Init(tx, std::vector<CTxOut>(prevouts));
137 CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, signature_cache, txdata);
138
139 for (const auto flags : ALL_CONSENSUS_FLAGS) {
140 // If a test is supposed to fail with test_flags, it should also fail with any superset thereof.
141 if ((flags & test_flags) == test_flags) {
142 bool ret = VerifyScript(tx.vin[idx].scriptSig, prevouts[idx].scriptPubKey, &tx.vin[idx].scriptWitness, flags, txcheck, nullptr);
144 }
145 }
146 }
147}
148
149BOOST_AUTO_TEST_CASE(script_assets_test)
150{
151 // See src/test/fuzz/script_assets_test_minimizer.cpp for information on how to generate
152 // the script_assets_test.json file used by this test.
154
155 const char* dir = std::getenv("DIR_UNIT_TEST_DATA");
156 BOOST_WARN_MESSAGE(dir != nullptr, "Variable DIR_UNIT_TEST_DATA unset, skipping script_assets_test");
157 if (dir == nullptr) return;
158 auto path = fs::path(dir) / "script_assets_test.json";
159 bool exists = fs::exists(path);
160 BOOST_WARN_MESSAGE(exists, "File $DIR_UNIT_TEST_DATA/script_assets_test.json not found, skipping script_assets_test");
161 if (!exists) return;
162 std::ifstream file{path};
163 BOOST_CHECK(file.is_open());
164 file.seekg(0, std::ios::end);
165 size_t length = file.tellg();
166 file.seekg(0, std::ios::beg);
167 std::string data(length, '\0');
168 file.read(data.data(), data.size());
170 BOOST_CHECK(tests.isArray());
171 BOOST_CHECK(tests.size() > 0);
172
173 for (size_t i = 0; i < tests.size(); i++) {
174 AssetTest(tests[i], signature_cache);
175 }
176 file.close();
177}
178
int ret
int flags
Definition: bitcoin-tx.cpp:529
#define Assert(val)
Identity function.
Definition: check.h:106
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:413
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:296
const std::vector< CTxIn > vin
Definition: transaction.h:306
An output of a transaction.
Definition: transaction.h:150
Valid signature cache, to avoid doing expensive ECDSA signature checking twice for every transaction ...
Definition: sigcache.h:39
Minimal stream for reading from an existing byte array by std::span.
Definition: streams.h:83
bool isArray() const
Definition: univalue.h:87
size_t size() const
Definition: univalue.h:71
Int getInt() const
Definition: univalue.h:140
bool exists(const std::string &key) const
Definition: univalue.h:79
bool get_bool() const
bool isObject() const
Definition: univalue.h:88
BOOST_AUTO_TEST_SUITE_END()
static bool exists(const path &p)
Definition: fs.h:89
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, const CScriptWitness *witness, unsigned int flags, const BaseSignatureChecker &checker, ScriptError *serror)
@ SCRIPT_VERIFY_NULLDUMMY
Definition: interpreter.h:64
@ SCRIPT_VERIFY_P2SH
Definition: interpreter.h:49
@ SCRIPT_VERIFY_WITNESS
Definition: interpreter.h:108
@ SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY
Definition: interpreter.h:99
@ SCRIPT_VERIFY_TAPROOT
Definition: interpreter.h:134
@ SCRIPT_VERIFY_DERSIG
Definition: interpreter.h:57
@ SCRIPT_VERIFY_CHECKSEQUENCEVERIFY
Definition: interpreter.h:104
UniValue read_json(std::string_view jsondata)
Definition: json.cpp:12
#define BOOST_CHECK(expr)
Definition: object.cpp:17
static constexpr TransactionSerParams TX_NO_WITNESS
Definition: transaction.h:196
BOOST_AUTO_TEST_CASE(script_assets_test)
static CScript ScriptFromHex(const std::string &str)
static CMutableTransaction TxFromHex(const std::string &str)
CScript ToScript(const T &byte_container)
unsigned int ParseScriptFlags(std::string strFlags)
static std::vector< unsigned int > AllConsensusFlags()
static std::vector< CTxOut > TxOutsFromJSON(const UniValue &univalue)
static void AssetTest(const UniValue &test, SignatureCache &signature_cache)
static CScriptWitness ScriptWitnessFromJSON(const UniValue &univalue)
static const std::vector< unsigned int > ALL_CONSENSUS_FLAGS
Precomputed list of all valid combinations of consensus-relevant script validation flags.
static constexpr size_t DEFAULT_SIGNATURE_CACHE_BYTES
Definition: sigcache.h:29
constexpr auto MakeUCharSpan(const V &v) -> decltype(UCharSpanCast(std::span{v}))
Like the std::span constructor, but for (const) unsigned char member types only.
Definition: span.h:111
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
Definition: strencodings.h:68
A mutable version of CTransaction.
Definition: transaction.h:378
std::vector< CTxIn > vin
Definition: transaction.h:379
std::vector< std::vector< unsigned char > > stack
Definition: script.h:588
void Init(const T &tx, std::vector< CTxOut > &&spent_outputs, bool force=false)
Initialize this PrecomputedTransactionData with transaction data.
constexpr std::array tests
Definition: unitester.cpp:100
std::optional< std::vector< Byte > > TryParseHex(std::string_view str)
Parse the hex string into bytes (uint8_t or std::byte).
assert(!tx.IsCoinBase())