Bitcoin ABC 0.32.12
P2P Digital Currency
core_read.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2016 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 <core_io.h>
6
7#include <primitives/block.h>
9#include <psbt.h>
10#include <script/script.h>
11#include <script/sign.h>
12#include <serialize.h>
13#include <streams.h>
14#include <util/strencodings.h>
15#include <util/string.h>
16
17#include <univalue.h>
18
19#include <algorithm>
20#include <string>
21
23using util::ToString;
24
25namespace {
26
27opcodetype ParseOpCode(const std::string &s) {
28 static std::map<std::string, opcodetype> mapOpNames;
29
30 if (mapOpNames.empty()) {
31 for (int op = 0; op < FIRST_UNDEFINED_OP_VALUE; op++) {
32 if (op < OP_PUSHDATA1) {
33 continue;
34 }
35
36 std::string strName = GetOpName(static_cast<opcodetype>(op));
37 if (strName == "OP_UNKNOWN") {
38 continue;
39 }
40
41 mapOpNames[strName] = static_cast<opcodetype>(op);
42 // Convenience: OP_ADD and just ADD are both recognized:
43 // strName starts with "OP_"
44 if (strName.compare(0, 3, "OP_") == 0) {
45 mapOpNames[strName.substr(3)] = static_cast<opcodetype>(op);
46 }
47 }
48 }
49
50 auto it = mapOpNames.find(s);
51 if (it == mapOpNames.end()) {
52 throw std::runtime_error("script parse error: unknown opcode " + s);
53 }
54 return it->second;
55}
56
57} // namespace
58
59CScript ParseScript(const std::string &s) {
60 CScript result;
61
62 std::vector<std::string> words = SplitString(s, " \t\n");
63
64 size_t push_size = 0, next_push_size = 0;
65 size_t script_size = 0;
66 // Deal with PUSHDATA1 operation with some more hacks.
67 size_t push_data_size = 0;
68
69 for (const auto &w : words) {
70 if (w.empty()) {
71 // Empty string, ignore. (SplitString doesn't combine multiple
72 // separators)
73 continue;
74 }
75
76 // Update script size.
77 script_size = result.size();
78
79 // Make sure we keep track of the size of push operations.
80 push_size = next_push_size;
81 next_push_size = 0;
82
83 // Decimal numbers
84 if (std::all_of(w.begin(), w.end(), ::IsDigit) ||
85 (w.front() == '-' && w.size() > 1 &&
86 std::all_of(w.begin() + 1, w.end(), ::IsDigit))) {
87 // Number
88 const auto num{ToIntegral<int64_t>(w)};
89
90 // Limit the range of numbers ParseScript accepts in decimal
91 // since numbers outside -0x7FFFFFFFFFFFFFFF...0x7FFFFFFFFFFFFFFF
92 // are illegal in scripts.
93 // This means, only the int64_t -0x8000000000000000 is illegal.
94 if (!num.has_value() ||
95 num == std::numeric_limits<int64_t>::min()) {
96 throw std::runtime_error(
97 "script parse error: decimal numeric value only allowed in "
98 "the range -0x7FFFFFFFFFFFFFFF...0x7FFFFFFFFFFFFFFF");
99 }
100
101 result << num.value();
102 goto next;
103 }
104
105 // Hex Data
106 if (w.substr(0, 2) == "0x" && w.size() > 2) {
107 if (!IsHex(std::string(w.begin() + 2, w.end()))) {
108 // Should only arrive here for improperly formatted hex values
109 throw std::runtime_error("Hex numbers expected to be formatted "
110 "in full-byte chunks (ex: 0x00 "
111 "instead of 0x0)");
112 }
113
114 // Raw hex data, inserted NOT pushed onto stack:
115 std::vector<uint8_t> raw =
116 ParseHex(std::string(w.begin() + 2, w.end()));
117
118 result.insert(result.end(), raw.begin(), raw.end());
119 goto next;
120 }
121
122 if (w.size() >= 2 && w.front() == '\'' && w.back() == '\'') {
123 // Single-quoted string, pushed as data. NOTE: this is poor-man's
124 // parsing, spaces/tabs/newlines in single-quoted strings won't
125 // work.
126 std::vector<uint8_t> value(w.begin() + 1, w.end() - 1);
127 result << value;
128 goto next;
129 }
130
131 // opcode, e.g. OP_ADD or ADD:
132 result << ParseOpCode(w);
133
134 next:
135 size_t size_change = result.size() - script_size;
136
137 // If push_size is set, ensure have added the right amount of stuff.
138 if (push_size != 0 && size_change != push_size) {
139 throw std::runtime_error(
140 "Wrong number of bytes being pushed. Expected:" +
141 ToString(push_size) + " Pushed:" + ToString(size_change));
142 }
143
144 // If push_size is set, and we have push_data_size set, then we have a
145 // PUSHDATAX opcode. We need to read it's push size as a LE value for
146 // the next iteration of this loop.
147 if (push_size != 0 && push_data_size != 0) {
148 auto offset = &result[script_size];
149
150 // Push data size is not a CScriptNum (Because it is
151 // 2's-complement instead of 1's complement). We need to use
152 // ReadLE(N) instead of converting to a CScriptNum.
153 if (push_data_size == 1) {
154 next_push_size = *offset;
155 } else if (push_data_size == 2) {
156 next_push_size = ReadLE16(offset);
157 } else if (push_data_size == 4) {
158 next_push_size = ReadLE32(offset);
159 }
160
161 push_data_size = 0;
162 }
163
164 // If push_size is unset, but size_change is 1, that means we have an
165 // opcode in the form of `0x00` or <opcodename>. We will check to see
166 // if it is a push operation and set state accordingly
167 if (push_size == 0 && size_change == 1) {
168 opcodetype op = opcodetype(*result.rbegin());
169
170 // If we have what looks like an immediate push, figure out its
171 // size.
172 if (op < OP_PUSHDATA1) {
173 next_push_size = op;
174 continue;
175 }
176
177 switch (op) {
178 case OP_PUSHDATA1:
179 push_data_size = next_push_size = 1;
180 break;
181 case OP_PUSHDATA2:
182 push_data_size = next_push_size = 2;
183 break;
184 case OP_PUSHDATA4:
185 push_data_size = next_push_size = 4;
186 break;
187 default:
188 break;
189 }
190 }
191 }
192
193 return result;
194}
195
196bool DecodeHexTx(CMutableTransaction &tx, const std::string &strHexTx) {
197 if (!IsHex(strHexTx)) {
198 return false;
199 }
200
201 std::vector<uint8_t> txData(ParseHex(strHexTx));
202
203 DataStream ssData{txData};
204 try {
205 ssData >> tx;
206 if (ssData.eof()) {
207 return true;
208 }
209 } catch (const std::exception &e) {
210 // Fall through.
211 }
212
213 return false;
214}
215
216bool DecodeHexBlockHeader(CBlockHeader &header, const std::string &hex_header) {
217 if (!IsHex(hex_header)) {
218 return false;
219 }
220
221 const std::vector<uint8_t> header_data{ParseHex(hex_header)};
222 DataStream ser_header{header_data};
223 try {
224 ser_header >> header;
225 } catch (const std::exception &) {
226 return false;
227 }
228 return true;
229}
230
231bool DecodeHexBlk(CBlock &block, const std::string &strHexBlk) {
232 if (!IsHex(strHexBlk)) {
233 return false;
234 }
235
236 std::vector<uint8_t> blockData(ParseHex(strHexBlk));
237 DataStream ssBlock{blockData};
238 try {
239 ssBlock >> block;
240 } catch (const std::exception &) {
241 return false;
242 }
243
244 return true;
245}
246
247bool ParseHashStr(const std::string &strHex, uint256 &result) {
248 if ((strHex.size() != 64) || !IsHex(strHex)) {
249 return false;
250 }
251
252 result.SetHex(strHex);
253 return true;
254}
255
256std::vector<uint8_t> ParseHexUV(const UniValue &v, const std::string &strName) {
257 std::string strHex;
258 if (v.isStr()) {
259 strHex = v.getValStr();
260 }
261
262 if (!IsHex(strHex)) {
263 throw std::runtime_error(
264 strName + " must be hexadecimal string (not '" + strHex + "')");
265 }
266
267 return ParseHex(strHex);
268}
269
271 SigHashType sigHashType = SigHashType().withForkId();
272 if (!sighash.isNull()) {
273 static std::map<std::string, int> map_sighash_values = {
274 {"ALL", SIGHASH_ALL},
275 {"ALL|ANYONECANPAY", SIGHASH_ALL | SIGHASH_ANYONECANPAY},
276 {"ALL|FORKID", SIGHASH_ALL | SIGHASH_FORKID},
277 {"ALL|FORKID|ANYONECANPAY",
279 {"NONE", SIGHASH_NONE},
280 {"NONE|ANYONECANPAY", SIGHASH_NONE | SIGHASH_ANYONECANPAY},
281 {"NONE|FORKID", SIGHASH_NONE | SIGHASH_FORKID},
282 {"NONE|FORKID|ANYONECANPAY",
284 {"SINGLE", SIGHASH_SINGLE},
285 {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE | SIGHASH_ANYONECANPAY},
286 {"SINGLE|FORKID", SIGHASH_SINGLE | SIGHASH_FORKID},
287 {"SINGLE|FORKID|ANYONECANPAY",
289 };
290 const std::string &strHashType = sighash.get_str();
291 const auto &it = map_sighash_values.find(strHashType);
292 if (it != map_sighash_values.end()) {
293 sigHashType = SigHashType(it->second);
294 } else {
295 throw std::runtime_error(strHashType +
296 " is not a valid sighash parameter.");
297 }
298 }
299 return sigHashType;
300}
Nodes collect new transactions into a block, hash them into a hash tree, and scan through nonce value...
Definition: block.h:23
Definition: block.h:60
A mutable version of CTransaction.
Definition: transaction.h:274
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:118
Signature hash type wrapper class.
Definition: sighashtype.h:37
SigHashType withForkId(bool forkId=true) const
Definition: sighashtype.h:54
const std::string & get_str() const
bool isNull() const
Definition: univalue.h:104
const std::string & getValStr() const
Definition: univalue.h:89
bool isStr() const
Definition: univalue.h:108
void SetHex(const char *psz)
Definition: uint256.cpp:24
256-bit opaque blob.
Definition: uint256.h:129
CScript ParseScript(const std::string &s)
Definition: core_read.cpp:59
bool DecodeHexBlockHeader(CBlockHeader &header, const std::string &hex_header)
Definition: core_read.cpp:216
bool DecodeHexTx(CMutableTransaction &tx, const std::string &strHexTx)
Definition: core_read.cpp:196
std::vector< uint8_t > ParseHexUV(const UniValue &v, const std::string &strName)
Definition: core_read.cpp:256
bool ParseHashStr(const std::string &strHex, uint256 &result)
Parse a hex string into 256 bits.
Definition: core_read.cpp:247
SigHashType ParseSighashString(const UniValue &sighash)
Definition: core_read.cpp:270
bool DecodeHexBlk(CBlock &block, const std::string &strHexBlk)
Definition: core_read.cpp:231
static uint16_t ReadLE16(const uint8_t *ptr)
Definition: common.h:13
static uint32_t ReadLE32(const uint8_t *ptr)
Definition: common.h:19
std::vector< std::string > SplitString(std::string_view str, char sep)
Definition: string.h:59
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:150
std::string GetOpName(opcodetype opcode)
Definition: script.cpp:14
opcodetype
Script opcodes.
Definition: script.h:51
@ OP_PUSHDATA4
Definition: script.h:57
@ FIRST_UNDEFINED_OP_VALUE
Definition: script.h:194
@ OP_PUSHDATA1
Definition: script.h:55
@ OP_PUSHDATA2
Definition: script.h:56
static std::string ToString(const CService &ip)
Definition: db.h:36
@ SIGHASH_FORKID
Definition: sighashtype.h:18
@ SIGHASH_ANYONECANPAY
Definition: sighashtype.h:19
@ SIGHASH_ALL
Definition: sighashtype.h:15
@ SIGHASH_NONE
Definition: sighashtype.h:16
@ SIGHASH_SINGLE
Definition: sighashtype.h:17
constexpr bool IsDigit(char c)
Tests if the given character is a decimal digit.
Definition: strencodings.h:133
template std::vector< std::byte > ParseHex(std::string_view)
bool IsHex(std::string_view str)
Returns true if each character in str is a hex character, and has an even number of hex digits.