Bitcoin ABC 0.26.3
P2P Digital Currency
Loading...
Searching...
No Matches
iguana_formatter.cpp
Go to the documentation of this file.
1// Copyright (c) 2024 The Bitcoin 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 <iguana_formatter.h>
7#include <iostream>
8#include <tinyformat.h>
9#include <util/strencodings.h>
10
12 if (!FormatTrace("scriptSig", result.traceScriptSig, result.metrics)) {
13 return false;
14 }
15
16 if (!FormatTrace("scriptPubKey", result.traceScriptPubKey,
17 result.metrics)) {
18 return false;
19 }
20
21 if (!result.traceScriptPubKey.entries.empty()) {
22 FormatStacks(result.traceScriptPubKey.entries.back().stacks);
23 }
24
25 if (result.traceRedeemScript) {
26 if (!FormatTrace("redeemScript", *result.traceRedeemScript,
27 result.metrics)) {
28 return false;
29 }
30
31 if (!result.traceRedeemScript->entries.empty()) {
32 FormatStacks(result.traceRedeemScript->entries.back().stacks);
33 }
34 }
35
36 std::cout << "Script executed without errors" << std::endl;
37
38 return true;
39}
40
41std::string FormatOpcode(opcodetype opcode) {
42 if (opcode > OP_0 && opcode < OP_PUSHDATA1) {
43 return strprintf("0x%02x", int32_t(opcode));
44 } else if (opcode == OP_1NEGATE) {
45 return "OP_1NEGATE";
46 } else if (opcode == OP_0 || (opcode >= OP_1 && opcode <= OP_16)) {
47 return strprintf("OP_%s", GetOpName(opcode));
48 } else {
49 return GetOpName(opcode);
50 }
51}
52
54 const std::string &title, const IguanaTrace &trace,
55 const ScriptExecutionMetrics &metrics) {
56 std::cout << "======= " << title << " =======" << std::endl;
57
58 FormatStacks(trace.initialStacks);
59
60 for (size_t entryIdx = 0; entryIdx < trace.entries.size(); ++entryIdx) {
61 const IguanaTraceEntry &entry = trace.entries[entryIdx];
62 std::cout << strprintf("OP%3d: %s", entryIdx,
63 FormatOpcode(entry.opcode));
64 if (!entry.pushdata.empty()) {
65 std::cout << " " << HexStr(entry.pushdata);
66 }
67 std::cout << std::endl;
68
69 if (entryIdx == trace.entries.size() - 1 &&
70 trace.scriptError != ScriptError::CLEANSTACK &&
71 trace.scriptError != ScriptError::INPUT_SIGCHECKS) {
72 continue;
73 }
74
75 FormatStacks(entry.stacks);
76 }
77
78 if (!trace.errorMsg.empty() || trace.scriptError != ScriptError::OK) {
79 if (trace.scriptError == ScriptError::INPUT_SIGCHECKS) {
81 }
82
83 std::cerr << title << " failed execution: ";
84 if (trace.errorMsg.size() > 0) {
85 std::cerr << trace.errorMsg;
86 } else {
87 std::cerr << ScriptErrorString(trace.scriptError);
88 }
89 std::cerr << std::endl;
90 return false;
91 }
92
93 return true;
94}
95
97 std::cout << strprintf(" Stack (%d item%s):", stacks.stack.size(),
98 stacks.stack.size() == 1 ? "" : "s");
99 if (stacks.stack.empty()) {
100 std::cout << " (empty stack)";
101 }
102 std::cout << std::endl;
103 for (size_t itemIdx = 0; itemIdx < stacks.stack.size(); ++itemIdx) {
104 std::cout << strprintf(" %2d: %s", itemIdx,
105 HexStr(stacks.stack[itemIdx]))
106 << std::endl;
107 }
108 if (!stacks.altstack.empty()) {
109 std::cout << strprintf(
110 " Altstack (%d item%s):", stacks.altstack.size(),
111 stacks.altstack.size() == 1 ? "" : "s")
112 << std::endl;
113 for (size_t itemIdx = 0; itemIdx < stacks.altstack.size(); ++itemIdx) {
114 std::cout << strprintf(" %2d: %s", itemIdx,
115 HexStr(stacks.altstack[itemIdx]))
116 << std::endl;
117 }
118 }
119}
120
122 const ScriptExecutionMetrics &metrics) {
123 std::cout << "Number of sigChecks: " << metrics.nSigChecks << std::endl;
124}
125
127 // Calculate the maximum used stack size (to format the altstack)
128 size_t topStackSize = 0;
129 size_t topAltStackSize = 0;
132 if (result.traceRedeemScript) {
134 }
135
136 std::cout << "scriptName,index,opcode,";
137 for (size_t idx = 0; idx < topStackSize; ++idx) {
138 std::cout << "stack " << idx << ",";
139 }
140 for (size_t idx = 0; idx < topAltStackSize; ++idx) {
141 std::cout << "altstack " << idx << ",";
142 }
143 std::cout << std::endl;
144
145 if (!FormatTrace("scriptSig", result.traceScriptSig, result.metrics,
146 topStackSize)) {
147 return false;
148 }
149
150 if (!FormatTrace("scriptPubKey", result.traceScriptPubKey, result.metrics,
151 topStackSize)) {
152 return false;
153 }
154
155 if (result.traceRedeemScript) {
156 if (!FormatTrace("redeemScript", *result.traceRedeemScript,
157 result.metrics, topStackSize)) {
158 return false;
159 }
160 }
161
163 std::cout << "Script executed without errors" << std::endl;
164
165 return true;
166}
167
169 size_t &topAltStackSize) {
170 for (const IguanaTraceEntry &entry : trace.entries) {
171 topStackSize = std::max(topStackSize, entry.stacks.stack.size());
173 std::max(topAltStackSize, entry.stacks.altstack.size());
174 }
175}
176
177bool FormatterCsv::FormatTrace(const std::string &traceName,
178 const IguanaTrace &trace,
179 const ScriptExecutionMetrics &metrics,
180 size_t topStackSize) {
181 for (size_t entryIdx = 0; entryIdx < trace.entries.size(); ++entryIdx) {
182 const IguanaTraceEntry &entry = trace.entries[entryIdx];
183 std::cout << traceName << ",";
184 std::cout << entryIdx << ",";
185 if (entry.pushdata.empty()) {
186 std::cout << FormatOpcode(entry.opcode) << ",";
187 } else {
188 std::cout << "0x" << HexStr(entry.pushdata) << ",";
189 }
191 std::cout << std::endl;
192 }
193
194 if (!trace.errorMsg.empty() || trace.scriptError != ScriptError::OK) {
195 if (trace.scriptError == ScriptError::INPUT_SIGCHECKS) {
196 FormatExecutionMetrics(metrics);
197 }
198
199 std::cout << traceName << " failed execution: ";
200 if (trace.errorMsg.size() > 0) {
201 std::cout << trace.errorMsg;
202 } else {
203 std::cout << ScriptErrorString(trace.scriptError);
204 }
205 std::cout << std::endl;
206 return false;
207 }
208
209 return true;
210}
211
213 size_t topStackSize) {
214 FormatStack(stacks.stack);
215 if (!stacks.altstack.empty()) {
216 for (size_t padIdx = 0; padIdx < topStackSize - stacks.stack.size();
217 ++padIdx) {
218 std::cout << ",";
219 }
220 FormatStack(stacks.altstack);
221 }
222}
223
224void FormatterCsv::FormatStack(const std::vector<std::vector<uint8_t>> &stack) {
225 for (const std::vector<uint8_t> &item : stack) {
226 if (item.empty()) {
227 std::cout << "(empty)";
228 } else {
229 std::cout << "\"" << HexStr(item) << "\"";
230 }
231 std::cout << ",";
232 }
233}
234
236 const ScriptExecutionMetrics &metrics) {
237 std::cout << "#sigChecks"
238 << "," << metrics.nSigChecks << std::endl;
239}
void FormatStack(const std::vector< std::vector< uint8_t > > &stack)
bool FormatTrace(const std::string &title, const IguanaTrace &trace, const ScriptExecutionMetrics &metrics, size_t topStackSize)
void FormatExecutionMetrics(const ScriptExecutionMetrics &metrics)
void TopStackSize(const IguanaTrace &trace, size_t &topStackSize, size_t &topAltStackSize)
virtual bool Format(const IguanaResult &result) override
void FormatStacks(const IguanaStacks &stacks, size_t topStackSize)
void FormatStacks(const IguanaStacks &stacks)
bool FormatTrace(const std::string &title, const IguanaTrace &trace, const ScriptExecutionMetrics &metrics)
void FormatExecutionMetrics(const ScriptExecutionMetrics &metrics)
virtual bool Format(const IguanaResult &result) override
std::string FormatOpcode(opcodetype opcode)
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition random.h:85
std::string GetOpName(opcodetype opcode)
Definition script.cpp:14
opcodetype
Script opcodes.
Definition script.h:47
@ OP_1NEGATE
Definition script.h:54
@ OP_16
Definition script.h:72
@ OP_1
Definition script.h:56
@ OP_PUSHDATA1
Definition script.h:51
@ OP_0
Definition script.h:49
std::string ScriptErrorString(const ScriptError serror)
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
IguanaTrace traceScriptSig
IguanaTrace traceScriptPubKey
ScriptExecutionMetrics metrics
std::optional< IguanaTrace > traceRedeemScript
std::vector< std::vector< uint8_t > > stack
std::vector< std::vector< uint8_t > > altstack
IguanaStacks stacks
opcodetype opcode
std::vector< uint8_t > pushdata
std::vector< IguanaTraceEntry > entries
Struct for holding cumulative results from executing a script or a sequence of scripts.
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...