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