Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
debugger.cpp
Go to the documentation of this file.
2
3#include <iostream>
4#include <optional>
5#include <regex>
6#include <string>
7#include <vector>
8
16
17// We'll instantiate all debug relation impls in this cpp, and not in each relation cpp.
19
20namespace bb::avm2 {
21namespace {
22
23std::vector<std::string> get_command()
24{
25 std::string line;
27 // Split the line into words.
28 return bb::detail::split_and_trim(line, ' ');
29}
30
31std::string str_replace(const std::string& s, const std::string& search, const std::string& replace)
32{
33 size_t pos = 0;
34 std::string res = s;
35 while ((pos = res.find(search, pos)) != std::string::npos) {
36 res.replace(pos, search.length(), replace);
37 pos += replace.length();
38 }
39 return res;
40}
41
42std::string to_binary(uint64_t n, bool leading_zeroes = true)
43{
44 std::string result;
45 for (int i = 0; i < 64; ++i) {
46 result = ((n & 1) ? "1" : "0") + result;
47 n >>= 1;
48 }
49 if (!leading_zeroes) {
50 size_t first_one = result.find('1');
51 if (first_one != std::string::npos) {
52 result = result.substr(first_one);
53 } else {
54 result = "0";
55 }
56 }
57 return result;
58}
59
60void help()
61{
62 std::cout << "Commands:" << std::endl;
63 std::cout << " ' - increment row" << std::endl;
64 std::cout << " , - decrement row" << std::endl;
65 std::cout << " @<row> - jump to row" << std::endl;
66 std::cout << " .<column_regex> [...column_regex] - print column values" << std::endl;
67 std::cout << " /set <column> <value> - set column" << std::endl;
68 std::cout << " /prefix <column_prefix> - set column prefix" << std::endl;
69 std::cout << " /noprefix - clear column prefix" << std::endl;
70 std::cout << " /testrelation <relation_name> [subrelation_name_or_number] - test relation" << std::endl;
71 std::cout << " exit, e, q - exit" << std::endl;
72}
73
74} // namespace
75
76void InteractiveDebugger::run(uint32_t starting_row)
77{
78 row = starting_row;
79 std::cout << "Entering interactive debugging mode at row " << row << "..." << std::endl;
80 while (true) {
81 // Print prompt with current row.
82 std::cout << this->row << "> ";
83 auto command = get_command();
84 if (command.empty()) {
85 continue;
86 }
87 if (command[0] == "'") {
88 row++;
89 } else if (command[0] == ",") {
90 if (row > 0) {
91 row--;
92 } else {
93 std::cout << "Cannot decrement row below 0." << std::endl;
94 }
95 } else if (command[0].starts_with("@")) {
96 row = static_cast<uint32_t>(std::stoi(command[0].substr(1)));
97 } else if (command[0] == "exit" || command[0] == "e" || command[0] == "q") {
98 break;
99 } else if (command[0] == "/set" || command[0] == "/s") {
100 if (command.size() != 3) {
101 std::cout << "Usage: /set <column> <value>" << std::endl;
102 } else {
103 set_column(command[1], command[2]);
104 }
105 } else if (command[0] == "/prefix" || command[0] == "/p") {
106 if (command.size() != 2) {
107 std::cout << "Usage: /prefix <column_prefix>" << std::endl;
108 } else {
109 prefix = command[1];
110 }
111 } else if (command[0] == "/noprefix" || command[0] == "/np") {
112 prefix = "";
113 } else if (command[0] == "/testrelation" || command[0] == "/tr") {
114 if (command.size() != 2 && command.size() != 3) {
115 std::cout << "Usage: /testrelation <relation_name> [subrelation_name_or_number]" << std::endl;
116 } else {
117 test_relation(command[1], command.size() == 3 ? std::make_optional(command[2]) : std::nullopt);
118 }
119 } else if (command[0].starts_with(".")) {
120 // Remove dot from first column name.
121 command[0].erase(0, 1);
122 // Print columns.
123 print_columns(command);
124 } else {
125 help();
126 }
127 }
128}
129
130void InteractiveDebugger::print_columns(const std::vector<std::string>& regexes)
131{
132 bool found = false;
133 std::string joined_regex;
134 for (const auto& str : regexes) {
135 joined_regex += prefix + str_replace(str, "'", "_shift") + "|";
136 }
137 joined_regex.pop_back(); // Remove trailing '|'.
138 std::regex re;
139 try {
140 re.assign(joined_regex);
141 } catch (std::regex_error& e) {
142 std::cout << "Invalid regex: " << e.what() << std::endl;
143 return;
144 }
145 for (size_t i = 0; i < COLUMN_NAMES.size(); ++i) {
146 if (std::regex_match(COLUMN_NAMES[i], re)) {
147 auto val = trace.get_column_or_shift(static_cast<ColumnAndShifts>(i), row);
148 std::cout << COLUMN_NAMES[i] << ": " << field_to_string(val);
149 // If the value is small enough, print it as decimal and binary.
150 if (val == FF(static_cast<uint64_t>(val))) {
151 uint64_t n = static_cast<uint64_t>(val);
152 std::cout << " (" << n << ", " << to_binary(n, /*leading_zeroes=*/false) << "b)";
153 }
155 found = true;
156 }
157 }
158 if (!found) {
159 std::cout << "No columns matched: " << joined_regex << std::endl;
160 }
161}
162
163void InteractiveDebugger::set_column(const std::string& column_name, const std::string& value)
164{
165 std::string final_name = prefix + column_name;
166 for (size_t i = 0; i < COLUMN_NAMES.size(); ++i) {
167 // We match both names, for copy-pasting ease.
168 if (COLUMN_NAMES[i] == final_name || COLUMN_NAMES[i] == column_name) {
169 trace.set(static_cast<Column>(i), row, std::stoi(value));
170 std::cout << "Column " << COLUMN_NAMES[i] << " set to value " << value << std::endl;
171 return;
172 }
173 }
174 std::cout << "Column " << column_name << " not found." << std::endl;
175}
176
177void InteractiveDebugger::test_relation(const std::string& relation_name, std::optional<std::string> subrelation_name)
178{
179 bool found = false;
180 bool failed = false;
181
182 bb::constexpr_for<0, std::tuple_size_v<typename AvmFlavor::MainRelations>, 1>([&]<size_t i>() {
184
185 if (Relation::NAME != relation_name) {
186 return;
187 }
188 found = true;
189
190 // TODO(fcarreiro): use check_relation.
192 Relation::accumulate(result, tracegen::get_full_row(trace, row), {}, 1);
193 for (size_t j = 0; j < result.size(); ++j) {
194 if (!result[j].is_zero() &&
195 (!subrelation_name || Relation::get_subrelation_label(j) == *subrelation_name)) {
196 std::cout << format("Relation ",
197 Relation::NAME,
198 ", subrelation ",
199 Relation::get_subrelation_label(j),
200 " failed at row ",
201 row)
202 << std::endl;
203 failed = true;
204 return;
205 }
206 }
207 });
208
209 if (!found) {
210 std::cout << "Relation " << relation_name << " not found." << std::endl;
211 } else if (!failed) {
212 std::cout << "Relation " << relation_name << " ("
213 << (subrelation_name.has_value() ? *subrelation_name : "all subrelations") << ")"
214 << " passed!" << std::endl;
215 }
216}
217
218} // namespace bb::avm2
A wrapper for Relations to expose methods used by the Sumcheck prover or verifier to add the contribu...
ArrayOfValues< FF, RelationImpl::SUBRELATION_PARTIAL_LENGTHS > SumcheckArrayOfValuesOverSubrelations
void run(uint32_t starting_row=0)
Definition debugger.cpp:76
tracegen::TraceContainer & trace
Definition debugger.hpp:30
void print_columns(const std::vector< std::string > &regex)
Definition debugger.cpp:130
void test_relation(const std::string &relation_name, std::optional< std::string > subrelation_name)
Definition debugger.cpp:177
void set_column(const std::string &column_name, const std::string &value)
Definition debugger.cpp:163
const FF & get_column_or_shift(ColumnAndShifts col, uint32_t row) const
void set(Column col, uint32_t row, const FF &value)
std::string format(Args... args)
Definition log.hpp:20
AvmFullRow get_full_row(const TraceContainer &trace, uint32_t row)
const std::vector< std::string > & COLUMN_NAMES
Definition columns.hpp:49
std::string field_to_string(const FF &ff)
Definition stringify.cpp:5
ColumnAndShifts
Definition columns.hpp:35
AvmFlavorSettings::FF FF
Definition field.hpp:10
std::vector< std::string > split_and_trim(const std::string &str, char delimiter)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13