Line data Source code
1 : // Copyright (c) 2011-2014 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 "data/tx_invalid.json.h"
6 : #include "data/tx_valid.json.h"
7 : #include "test/test_bitcoin.h"
8 :
9 : #include "clientversion.h"
10 : #include "consensus/validation.h"
11 : #include "core_io.h"
12 : #include "key.h"
13 : #include "keystore.h"
14 : #include "main.h" // For CheckTransaction
15 : #include "policy/policy.h"
16 : #include "script/script.h"
17 : #include "script/script_error.h"
18 : #include "utilstrencodings.h"
19 :
20 : #include <map>
21 : #include <string>
22 :
23 : #include <boost/algorithm/string/classification.hpp>
24 : #include <boost/algorithm/string/split.hpp>
25 : #include <boost/assign/list_of.hpp>
26 : #include <boost/test/unit_test.hpp>
27 : #include <boost/assign/list_of.hpp>
28 :
29 : #include <univalue.h>
30 :
31 : using namespace std;
32 :
33 : // In script_tests.cpp
34 : extern UniValue read_json(const std::string& jsondata);
35 :
36 1 : static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
37 : (string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE)
38 6 : (string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH)
39 4 : (string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC)
40 4 : (string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG)
41 4 : (string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S)
42 4 : (string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY)
43 4 : (string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA)
44 4 : (string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY)
45 4 : (string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
46 4 : (string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK)
47 4 : (string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY);
48 :
49 1144 : unsigned int ParseScriptFlags(string strFlags)
50 : {
51 1144 : if (strFlags.empty()) {
52 : return 0;
53 : }
54 1027 : unsigned int flags = 0;
55 : vector<string> words;
56 1027 : boost::algorithm::split(words, strFlags, boost::algorithm::is_any_of(","));
57 :
58 17112 : BOOST_FOREACH(string word, words)
59 : {
60 1825 : if (!mapFlagNames.count(word))
61 0 : BOOST_ERROR("Bad test: unknown verification flag '" << word << "'");
62 1825 : flags |= mapFlagNames[word];
63 : }
64 :
65 1027 : return flags;
66 : }
67 :
68 79 : string FormatScriptFlags(unsigned int flags)
69 : {
70 79 : if (flags == 0) {
71 76 : return "";
72 : }
73 : string ret;
74 41 : std::map<string, unsigned int>::const_iterator it = mapFlagNames.begin();
75 533 : while (it != mapFlagNames.end()) {
76 451 : if (flags & it->second) {
77 88 : ret += it->first + ",";
78 : }
79 451 : it++;
80 : }
81 41 : return ret.substr(0, ret.size() - 1);
82 : }
83 :
84 1 : BOOST_FIXTURE_TEST_SUITE(transaction_tests, BasicTestingSetup)
85 :
86 6 : BOOST_AUTO_TEST_CASE(tx_valid)
87 : {
88 : // Read tests from test/data/tx_valid.json
89 : // Format is an array of arrays
90 : // Inner arrays are either [ "comment" ]
91 : // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, verifyFlags
92 : // ... where all scripts are stringified scripts.
93 : //
94 : // verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
95 4 : UniValue tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
96 :
97 : ScriptError err;
98 238 : for (unsigned int idx = 0; idx < tests.size(); idx++) {
99 118 : UniValue test = tests[idx];
100 118 : string strTest = test.write();
101 118 : if (test[0].isArray())
102 : {
103 52 : if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
104 : {
105 0 : BOOST_ERROR("Bad test: " << strTest);
106 0 : continue;
107 : }
108 :
109 : map<COutPoint, CScript> mapprevOutScriptPubKeys;
110 104 : UniValue inputs = test[0].get_array();
111 : bool fValid = true;
112 284 : for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
113 60 : const UniValue& input = inputs[inpIdx];
114 60 : if (!input.isArray())
115 : {
116 : fValid = false;
117 0 : break;
118 : }
119 60 : UniValue vinput = input.get_array();
120 60 : if (vinput.size() != 3)
121 : {
122 0 : fValid = false;
123 0 : break;
124 : }
125 :
126 360 : mapprevOutScriptPubKeys[COutPoint(uint256S(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str());
127 60 : }
128 52 : if (!fValid)
129 : {
130 0 : BOOST_ERROR("Bad test: " << strTest);
131 0 : continue;
132 : }
133 :
134 52 : string transaction = test[1].get_str();
135 104 : CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
136 52 : CTransaction tx;
137 : stream >> tx;
138 :
139 52 : CValidationState state;
140 364 : BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
141 468 : BOOST_CHECK(state.IsValid());
142 :
143 172 : for (unsigned int i = 0; i < tx.vin.size(); i++)
144 : {
145 180 : if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
146 : {
147 0 : BOOST_ERROR("Bad test: " << strTest);
148 : break;
149 : }
150 :
151 120 : unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
152 600 : BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
153 : verify_flags, TransactionSignatureChecker(&tx, i), &err),
154 : strTest);
155 420 : BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
156 : }
157 : }
158 119 : }
159 1 : }
160 :
161 6 : BOOST_AUTO_TEST_CASE(tx_invalid)
162 : {
163 : // Read tests from test/data/tx_invalid.json
164 : // Format is an array of arrays
165 : // Inner arrays are either [ "comment" ]
166 : // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, verifyFlags
167 : // ... where all scripts are stringified scripts.
168 : //
169 : // verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
170 4 : UniValue tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
171 :
172 : ScriptError err;
173 206 : for (unsigned int idx = 0; idx < tests.size(); idx++) {
174 102 : UniValue test = tests[idx];
175 102 : string strTest = test.write();
176 102 : if (test[0].isArray())
177 : {
178 46 : if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
179 : {
180 0 : BOOST_ERROR("Bad test: " << strTest);
181 0 : continue;
182 : }
183 :
184 : map<COutPoint, CScript> mapprevOutScriptPubKeys;
185 92 : UniValue inputs = test[0].get_array();
186 : bool fValid = true;
187 236 : for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
188 48 : const UniValue& input = inputs[inpIdx];
189 48 : if (!input.isArray())
190 : {
191 : fValid = false;
192 0 : break;
193 : }
194 48 : UniValue vinput = input.get_array();
195 48 : if (vinput.size() != 3)
196 : {
197 0 : fValid = false;
198 0 : break;
199 : }
200 :
201 288 : mapprevOutScriptPubKeys[COutPoint(uint256S(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str());
202 48 : }
203 46 : if (!fValid)
204 : {
205 0 : BOOST_ERROR("Bad test: " << strTest);
206 0 : continue;
207 : }
208 :
209 46 : string transaction = test[1].get_str();
210 92 : CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
211 46 : CTransaction tx;
212 : stream >> tx;
213 :
214 46 : CValidationState state;
215 46 : fValid = CheckTransaction(tx, state) && state.IsValid();
216 :
217 166 : for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
218 : {
219 111 : if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
220 : {
221 0 : BOOST_ERROR("Bad test: " << strTest);
222 : break;
223 : }
224 :
225 74 : unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
226 74 : fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
227 74 : verify_flags, TransactionSignatureChecker(&tx, i), &err);
228 : }
229 322 : BOOST_CHECK_MESSAGE(!fValid, strTest);
230 322 : BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));
231 : }
232 103 : }
233 1 : }
234 :
235 6 : BOOST_AUTO_TEST_CASE(basic_transaction_tests)
236 : {
237 : // Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436)
238 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};
239 2 : vector<unsigned char> vch(ch, ch + sizeof(ch) -1);
240 : CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
241 1 : CMutableTransaction tx;
242 : stream >> tx;
243 1 : CValidationState state;
244 8 : BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid.");
245 :
246 : // Check that duplicate txins fail
247 1 : tx.vin.push_back(tx.vin[0]);
248 8 : BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
249 1 : }
250 :
251 : //
252 : // Helper: create two dummy transactions, each with
253 : // two outputs. The first has 11 and 50 CENT outputs
254 : // paid to a TX_PUBKEY, the second 21 and 22 CENT outputs
255 : // paid to a TX_PUBKEYHASH.
256 : //
257 : static std::vector<CMutableTransaction>
258 2 : SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
259 : {
260 : std::vector<CMutableTransaction> dummyTransactions;
261 4 : dummyTransactions.resize(2);
262 :
263 : // Add some keys to the keystore:
264 20 : CKey key[4];
265 8 : for (int i = 0; i < 4; i++)
266 : {
267 8 : key[i].MakeNewKey(i % 2);
268 8 : keystoreRet.AddKey(key[i]);
269 : }
270 :
271 : // Create some dummy input transactions
272 4 : dummyTransactions[0].vout.resize(2);
273 2 : dummyTransactions[0].vout[0].nValue = 11*CENT;
274 4 : dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
275 2 : dummyTransactions[0].vout[1].nValue = 50*CENT;
276 4 : dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
277 6 : coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0);
278 :
279 4 : dummyTransactions[1].vout.resize(2);
280 2 : dummyTransactions[1].vout[0].nValue = 21*CENT;
281 8 : dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
282 2 : dummyTransactions[1].vout[1].nValue = 22*CENT;
283 8 : dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
284 10 : coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0);
285 :
286 2 : return dummyTransactions;
287 : }
288 :
289 6 : BOOST_AUTO_TEST_CASE(test_Get)
290 : {
291 1 : CBasicKeyStore keystore;
292 : CCoinsView coinsDummy;
293 2 : CCoinsViewCache coins(&coinsDummy);
294 2 : std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
295 :
296 1 : CMutableTransaction t1;
297 2 : t1.vin.resize(3);
298 1 : t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
299 1 : t1.vin[0].prevout.n = 1;
300 3 : t1.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
301 3 : t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();
302 1 : t1.vin[1].prevout.n = 0;
303 5 : t1.vin[1].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
304 3 : t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();
305 1 : t1.vin[2].prevout.n = 1;
306 5 : t1.vin[2].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
307 2 : t1.vout.resize(2);
308 1 : t1.vout[0].nValue = 90*CENT;
309 1 : t1.vout[0].scriptPubKey << OP_1;
310 :
311 9 : BOOST_CHECK(AreInputsStandard(t1, coins));
312 6 : BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT);
313 :
314 : // Adding extra junk to the scriptSig should make it non-standard:
315 1 : t1.vin[0].scriptSig << OP_11;
316 9 : BOOST_CHECK(!AreInputsStandard(t1, coins));
317 :
318 : // ... as should not having enough:
319 2 : t1.vin[0].scriptSig = CScript();
320 10 : BOOST_CHECK(!AreInputsStandard(t1, coins));
321 1 : }
322 :
323 6 : BOOST_AUTO_TEST_CASE(test_IsStandard)
324 : {
325 1 : LOCK(cs_main);
326 2 : CBasicKeyStore keystore;
327 : CCoinsView coinsDummy;
328 2 : CCoinsViewCache coins(&coinsDummy);
329 2 : std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
330 :
331 1 : CMutableTransaction t;
332 2 : t.vin.resize(1);
333 1 : t.vin[0].prevout.hash = dummyTransactions[0].GetHash();
334 1 : t.vin[0].prevout.n = 1;
335 3 : t.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
336 2 : t.vout.resize(1);
337 1 : t.vout[0].nValue = 90*CENT;
338 : CKey key;
339 1 : key.MakeNewKey(true);
340 4 : t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
341 :
342 : string reason;
343 9 : BOOST_CHECK(IsStandardTx(t, reason));
344 :
345 1 : t.vout[0].nValue = 501; // dust
346 9 : BOOST_CHECK(!IsStandardTx(t, reason));
347 :
348 1 : t.vout[0].nValue = 2730; // not dust
349 9 : BOOST_CHECK(IsStandardTx(t, reason));
350 :
351 1 : t.vout[0].scriptPubKey = CScript() << OP_1;
352 9 : BOOST_CHECK(!IsStandardTx(t, reason));
353 :
354 : // MAX_OP_RETURN_RELAY-byte TX_NULL_DATA (standard)
355 4 : t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
356 6 : BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size());
357 9 : BOOST_CHECK(IsStandardTx(t, reason));
358 :
359 : // MAX_OP_RETURN_RELAY+1-byte TX_NULL_DATA (non-standard)
360 4 : t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
361 6 : BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size());
362 9 : BOOST_CHECK(!IsStandardTx(t, reason));
363 :
364 : // Data payload can be encoded in any way...
365 4 : t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("");
366 9 : BOOST_CHECK(IsStandardTx(t, reason));
367 5 : t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("00") << ParseHex("01");
368 9 : BOOST_CHECK(IsStandardTx(t, reason));
369 : // OP_RESERVED *is* considered to be a PUSHDATA type opcode by IsPushOnly()!
370 21 : 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;
371 9 : BOOST_CHECK(IsStandardTx(t, reason));
372 7 : t.vout[0].scriptPubKey = CScript() << OP_RETURN << 0 << ParseHex("01") << 2 << ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
373 9 : BOOST_CHECK(IsStandardTx(t, reason));
374 :
375 : // ...so long as it only contains PUSHDATA's
376 2 : t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RETURN;
377 9 : BOOST_CHECK(!IsStandardTx(t, reason));
378 :
379 : // TX_NULL_DATA w/o PUSHDATA
380 2 : t.vout.resize(1);
381 2 : t.vout[0].scriptPubKey = CScript() << OP_RETURN;
382 9 : BOOST_CHECK(IsStandardTx(t, reason));
383 :
384 : // Only one TX_NULL_DATA permitted in all cases
385 2 : t.vout.resize(2);
386 4 : t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
387 4 : t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
388 9 : BOOST_CHECK(!IsStandardTx(t, reason));
389 :
390 4 : t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
391 2 : t.vout[1].scriptPubKey = CScript() << OP_RETURN;
392 9 : BOOST_CHECK(!IsStandardTx(t, reason));
393 :
394 2 : t.vout[0].scriptPubKey = CScript() << OP_RETURN;
395 2 : t.vout[1].scriptPubKey = CScript() << OP_RETURN;
396 9 : BOOST_CHECK(!IsStandardTx(t, reason));
397 1 : }
398 :
399 3 : BOOST_AUTO_TEST_SUITE_END()
|