]>
Commit | Line | Data |
---|---|---|
3fc68461 WL |
1 | // Copyright (c) 2013 The Bitcoin Core developers |
2 | // Distributed under the MIT/X11 software license, see the accompanying | |
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
4 | ||
6354935c | 5 | #include "data/sighash.json.h" |
f5857e5c | 6 | #include "main.h" |
6354935c | 7 | #include "random.h" |
43cb4185 | 8 | #include "serialize.h" |
cbd22a50 | 9 | #include "script/script.h" |
86dbeea2 | 10 | #include "scriptutils.h" |
6354935c | 11 | #include "util.h" |
43cb4185 | 12 | #include "version.h" |
43cb4185 | 13 | |
6354935c PK |
14 | #include <iostream> |
15 | ||
16 | #include <boost/test/unit_test.hpp> | |
43cb4185 MA |
17 | #include "json/json_spirit_reader_template.h" |
18 | #include "json/json_spirit_utils.h" | |
19 | #include "json/json_spirit_writer_template.h" | |
20 | ||
21 | using namespace json_spirit; | |
22 | extern Array read_json(const std::string& jsondata); | |
f5857e5c | 23 | |
f5857e5c PW |
24 | // Old script.cpp SignatureHash function |
25 | uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) | |
26 | { | |
27 | if (nIn >= txTo.vin.size()) | |
28 | { | |
29 | printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); | |
30 | return 1; | |
31 | } | |
4949004d | 32 | CMutableTransaction txTmp(txTo); |
f5857e5c PW |
33 | |
34 | // In case concatenating two scripts ends up with two codeseparators, | |
35 | // or an extra one at the end, this prevents all those possible incompatibilities. | |
36 | scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR)); | |
37 | ||
38 | // Blank out other inputs' signatures | |
39 | for (unsigned int i = 0; i < txTmp.vin.size(); i++) | |
40 | txTmp.vin[i].scriptSig = CScript(); | |
41 | txTmp.vin[nIn].scriptSig = scriptCode; | |
42 | ||
43 | // Blank out some of the outputs | |
44 | if ((nHashType & 0x1f) == SIGHASH_NONE) | |
45 | { | |
46 | // Wildcard payee | |
47 | txTmp.vout.clear(); | |
48 | ||
49 | // Let the others update at will | |
50 | for (unsigned int i = 0; i < txTmp.vin.size(); i++) | |
51 | if (i != nIn) | |
52 | txTmp.vin[i].nSequence = 0; | |
53 | } | |
54 | else if ((nHashType & 0x1f) == SIGHASH_SINGLE) | |
55 | { | |
56 | // Only lock-in the txout payee at same index as txin | |
57 | unsigned int nOut = nIn; | |
58 | if (nOut >= txTmp.vout.size()) | |
59 | { | |
60 | printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut); | |
61 | return 1; | |
62 | } | |
63 | txTmp.vout.resize(nOut+1); | |
64 | for (unsigned int i = 0; i < nOut; i++) | |
65 | txTmp.vout[i].SetNull(); | |
66 | ||
67 | // Let the others update at will | |
68 | for (unsigned int i = 0; i < txTmp.vin.size(); i++) | |
69 | if (i != nIn) | |
70 | txTmp.vin[i].nSequence = 0; | |
71 | } | |
72 | ||
73 | // Blank out other inputs completely, not recommended for open transactions | |
74 | if (nHashType & SIGHASH_ANYONECANPAY) | |
75 | { | |
76 | txTmp.vin[0] = txTmp.vin[nIn]; | |
77 | txTmp.vin.resize(1); | |
78 | } | |
79 | ||
80 | // Serialize and hash | |
81 | CHashWriter ss(SER_GETHASH, 0); | |
82 | ss << txTmp << nHashType; | |
83 | return ss.GetHash(); | |
84 | } | |
85 | ||
86 | void static RandomScript(CScript &script) { | |
87 | static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR}; | |
88 | script = CScript(); | |
89 | int ops = (insecure_rand() % 10); | |
90 | for (int i=0; i<ops; i++) | |
91 | script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))]; | |
92 | } | |
93 | ||
4949004d | 94 | void static RandomTransaction(CMutableTransaction &tx, bool fSingle) { |
f5857e5c PW |
95 | tx.nVersion = insecure_rand(); |
96 | tx.vin.clear(); | |
97 | tx.vout.clear(); | |
98 | tx.nLockTime = (insecure_rand() % 2) ? insecure_rand() : 0; | |
99 | int ins = (insecure_rand() % 4) + 1; | |
100 | int outs = fSingle ? ins : (insecure_rand() % 4) + 1; | |
101 | for (int in = 0; in < ins; in++) { | |
102 | tx.vin.push_back(CTxIn()); | |
103 | CTxIn &txin = tx.vin.back(); | |
104 | txin.prevout.hash = GetRandHash(); | |
105 | txin.prevout.n = insecure_rand() % 4; | |
106 | RandomScript(txin.scriptSig); | |
107 | txin.nSequence = (insecure_rand() % 2) ? insecure_rand() : (unsigned int)-1; | |
108 | } | |
109 | for (int out = 0; out < outs; out++) { | |
110 | tx.vout.push_back(CTxOut()); | |
111 | CTxOut &txout = tx.vout.back(); | |
112 | txout.nValue = insecure_rand() % 100000000; | |
113 | RandomScript(txout.scriptPubKey); | |
114 | } | |
115 | } | |
116 | ||
117 | BOOST_AUTO_TEST_SUITE(sighash_tests) | |
232aa9e0 | 118 | |
f5857e5c PW |
119 | BOOST_AUTO_TEST_CASE(sighash_test) |
120 | { | |
121 | seed_insecure_rand(false); | |
6354935c | 122 | |
232aa9e0 MA |
123 | #if defined(PRINT_SIGHASH_JSON) |
124 | std::cout << "[\n"; | |
125 | std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n"; | |
126 | #endif | |
127 | int nRandomTests = 50000; | |
128 | ||
129 | #if defined(PRINT_SIGHASH_JSON) | |
130 | nRandomTests = 500; | |
131 | #endif | |
132 | for (int i=0; i<nRandomTests; i++) { | |
f5857e5c | 133 | int nHashType = insecure_rand(); |
4949004d | 134 | CMutableTransaction txTo; |
f5857e5c PW |
135 | RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); |
136 | CScript scriptCode; | |
137 | RandomScript(scriptCode); | |
138 | int nIn = insecure_rand() % txTo.vin.size(); | |
43cb4185 MA |
139 | |
140 | uint256 sh, sho; | |
141 | sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType); | |
142 | sh = SignatureHash(scriptCode, txTo, nIn, nHashType); | |
232aa9e0 MA |
143 | #if defined(PRINT_SIGHASH_JSON) |
144 | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | |
145 | ss << txTo; | |
146 | ||
147 | std::cout << "\t[\"" ; | |
148 | std::cout << HexStr(ss.begin(), ss.end()) << "\", \""; | |
149 | std::cout << HexStr(scriptCode) << "\", "; | |
150 | std::cout << nIn << ", "; | |
151 | std::cout << nHashType << ", \""; | |
152 | std::cout << sho.GetHex() << "\"]"; | |
153 | if (i+1 != nRandomTests) { | |
154 | std::cout << ","; | |
155 | } | |
156 | std::cout << "\n"; | |
157 | #endif | |
43cb4185 | 158 | BOOST_CHECK(sh == sho); |
f5857e5c | 159 | } |
232aa9e0 MA |
160 | #if defined(PRINT_SIGHASH_JSON) |
161 | std::cout << "]\n"; | |
162 | #endif | |
f5857e5c PW |
163 | } |
164 | ||
43cb4185 | 165 | // Goal: check that SignatureHash generates correct hash |
43cb4185 MA |
166 | BOOST_AUTO_TEST_CASE(sighash_from_data) |
167 | { | |
168 | Array tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash))); | |
169 | ||
170 | BOOST_FOREACH(Value& tv, tests) | |
171 | { | |
172 | Array test = tv.get_array(); | |
173 | std::string strTest = write_string(tv, false); | |
174 | if (test.size() < 1) // Allow for extra stuff (useful for comments) | |
175 | { | |
176 | BOOST_ERROR("Bad test: " << strTest); | |
177 | continue; | |
178 | } | |
179 | if (test.size() == 1) continue; // comment | |
180 | ||
81bfb5ae MA |
181 | std::string raw_tx, raw_script, sigHashHex; |
182 | int nIn, nHashType; | |
43cb4185 | 183 | uint256 sh; |
43cb4185 | 184 | CTransaction tx; |
43cb4185 | 185 | CScript scriptCode = CScript(); |
43cb4185 | 186 | |
81bfb5ae MA |
187 | try { |
188 | // deserialize test data | |
189 | raw_tx = test[0].get_str(); | |
190 | raw_script = test[1].get_str(); | |
191 | nIn = test[2].get_int(); | |
192 | nHashType = test[3].get_int(); | |
193 | sigHashHex = test[4].get_str(); | |
194 | ||
195 | uint256 sh; | |
196 | CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION); | |
197 | stream >> tx; | |
198 | ||
199 | CValidationState state; | |
200 | BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest); | |
201 | BOOST_CHECK(state.IsValid()); | |
202 | ||
203 | std::vector<unsigned char> raw = ParseHex(raw_script); | |
204 | scriptCode.insert(scriptCode.end(), raw.begin(), raw.end()); | |
205 | } catch (...) { | |
206 | BOOST_ERROR("Bad test, couldn't deserialize data: " << strTest); | |
207 | continue; | |
208 | } | |
6354935c | 209 | |
43cb4185 | 210 | sh = SignatureHash(scriptCode, tx, nIn, nHashType); |
43cb4185 MA |
211 | BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); |
212 | } | |
213 | } | |
f5857e5c | 214 | BOOST_AUTO_TEST_SUITE_END() |