Bitcoin ABC 0.30.5
P2P Digital Currency
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
53std::string FormatStackItem(const std::vector<uint8_t> &data) {
54 if (data.empty()) {
55 return "\"\"";
56 } else {
57 return HexStr(data);
58 }
59}
60
62 const std::string &title, const IguanaTrace &trace,
63 const ScriptExecutionMetrics &metrics) {
64 std::cout << "======= " << title << " =======" << std::endl;
65
67
68 for (size_t entryIdx = 0; entryIdx < trace.entries.size(); ++entryIdx) {
69 const IguanaTraceEntry &entry = trace.entries[entryIdx];
70 std::cout << strprintf("OP%3d: %s", entryIdx,
71 FormatOpcode(entry.opcode));
72 if (!entry.pushdata.empty()) {
73 std::cout << " " << HexStr(entry.pushdata);
74 }
75 std::cout << std::endl;
76
77 if (entryIdx == trace.entries.size() - 1 &&
80 continue;
81 }
82
83 FormatStacks(entry.stacks);
84 }
85
86 if (!trace.errorMsg.empty() || trace.scriptError != ScriptError::OK) {
89 }
90
91 std::cerr << title << " failed execution: ";
92 if (trace.errorMsg.size() > 0) {
93 std::cerr << trace.errorMsg;
94 } else {
95 std::cerr << ScriptErrorString(trace.scriptError);
96 }
97 std::cerr << std::endl;
98 return false;
99 }
100
101 return true;
102}
103
105 std::cout << strprintf(" Stack (%d item%s):", stacks.stack.size(),
106 stacks.stack.size() == 1 ? "" : "s");
107 if (stacks.stack.empty()) {
108 std::cout << " (empty stack)";
109 }
110 std::cout << std::endl;
111 for (size_t itemIdx = 0; itemIdx < stacks.stack.size(); ++itemIdx) {
112 std::cout << strprintf(" %2d: %s", itemIdx,
113 FormatStackItem(stacks.stack[itemIdx]))
114 << std::endl;
115 }
116 if (!stacks.altstack.empty()) {
117 std::cout << strprintf(
118 " Altstack (%d item%s):", stacks.altstack.size(),
119 stacks.altstack.size() == 1 ? "" : "s")
120 << std::endl;
121 for (size_t itemIdx = 0; itemIdx < stacks.altstack.size(); ++itemIdx) {
122 std::cout << strprintf(" %2d: %s", itemIdx,
123 FormatStackItem(stacks.altstack[itemIdx]))
124 << std::endl;
125 }
126 }
127}
128
130 const ScriptExecutionMetrics &metrics) {
131 std::cout << "Number of sigChecks: " << metrics.nSigChecks << std::endl;
132}
133
135 // Calculate the maximum used stack size (to format the altstack)
136 size_t topStackSize = 0;
137 size_t topAltStackSize = 0;
138 TopStackSize(result.traceScriptSig, topStackSize, topAltStackSize);
139 TopStackSize(result.traceScriptPubKey, topStackSize, topAltStackSize);
140 if (result.traceRedeemScript) {
141 TopStackSize(*result.traceRedeemScript, topStackSize, topAltStackSize);
142 }
143
144 std::cout << "scriptName,index,opcode,";
145 for (size_t idx = 0; idx < topStackSize; ++idx) {
146 std::cout << "stack " << idx << ",";
147 }
148 for (size_t idx = 0; idx < topAltStackSize; ++idx) {
149 std::cout << "altstack " << idx << ",";
150 }
151 std::cout << std::endl;
152
153 if (!FormatTrace("scriptSig", result.traceScriptSig, result.metrics,
154 topStackSize)) {
155 return false;
156 }
157
158 if (!FormatTrace("scriptPubKey", result.traceScriptPubKey, result.metrics,
159 topStackSize)) {
160 return false;
161 }
162
163 if (result.traceRedeemScript) {
164 if (!FormatTrace("redeemScript", *result.traceRedeemScript,
165 result.metrics, topStackSize)) {
166 return false;
167 }
168 }
169
171 std::cout << "Script executed without errors" << std::endl;
172
173 return true;
174}
175
176void FormatterCsv::TopStackSize(const IguanaTrace &trace, size_t &topStackSize,
177 size_t &topAltStackSize) {
178 for (const IguanaTraceEntry &entry : trace.entries) {
179 topStackSize = std::max(topStackSize, entry.stacks.stack.size());
180 topAltStackSize =
181 std::max(topAltStackSize, entry.stacks.altstack.size());
182 }
183}
184
185bool FormatterCsv::FormatTrace(const std::string &traceName,
186 const IguanaTrace &trace,
187 const ScriptExecutionMetrics &metrics,
188 size_t topStackSize) {
189 for (size_t entryIdx = 0; entryIdx < trace.entries.size(); ++entryIdx) {
190 const IguanaTraceEntry &entry = trace.entries[entryIdx];
191 std::cout << traceName << ",";
192 std::cout << entryIdx << ",";
193 if (entry.pushdata.empty()) {
194 std::cout << FormatOpcode(entry.opcode) << ",";
195 } else {
196 std::cout << "0x" << HexStr(entry.pushdata) << ",";
197 }
198 FormatStacks(entry.stacks, topStackSize);
199 std::cout << std::endl;
200 }
201
202 if (!trace.errorMsg.empty() || trace.scriptError != ScriptError::OK) {
204 FormatExecutionMetrics(metrics);
205 }
206
207 std::cout << traceName << " failed execution: ";
208 if (trace.errorMsg.size() > 0) {
209 std::cout << trace.errorMsg;
210 } else {
211 std::cout << ScriptErrorString(trace.scriptError);
212 }
213 std::cout << std::endl;
214 return false;
215 }
216
217 return true;
218}
219
221 size_t topStackSize) {
222 FormatStack(stacks.stack);
223 if (!stacks.altstack.empty()) {
224 for (size_t padIdx = 0; padIdx < topStackSize - stacks.stack.size();
225 ++padIdx) {
226 std::cout << ",";
227 }
228 FormatStack(stacks.altstack);
229 }
230}
231
232void FormatterCsv::FormatStack(const std::vector<std::vector<uint8_t>> &stack) {
233 for (const std::vector<uint8_t> &item : stack) {
234 if (item.empty()) {
235 std::cout << "(empty)";
236 } else {
237 std::cout << "\"" << HexStr(item) << "\"";
238 }
239 std::cout << ",";
240 }
241}
242
244 const ScriptExecutionMetrics &metrics) {
245 std::cout << "#sigChecks"
246 << "," << metrics.nSigChecks << std::endl;
247}
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 FormatStackItem(const std::vector< uint8_t > &data)
std::string FormatOpcode(opcodetype opcode)
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)
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
std::string errorMsg
IguanaStacks initialStacks
ScriptError scriptError
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...
Definition: tinyformat.h:1202
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.