Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
cli.cpp
Go to the documentation of this file.
1
29#include "barretenberg/bbapi/generated/bb_dispatch.hpp"
40#include <atomic>
41#include <fstream>
42#include <iostream>
43#include <mutex>
44
45namespace bb {
46
47// TODO(https://github.com/AztecProtocol/barretenberg/issues/1257): Remove unused/seemingly unnecessary flags.
48// TODO(https://github.com/AztecProtocol/barretenberg/issues/1258): Improve defaults.
49
50// Helper function to recursively print active subcommands for CLI11 app debugging
51void print_active_subcommands(const CLI::App& app, const std::string& prefix = "bb command: ")
52{
53 // get_subcommands() returns a vector of pointers to subcommands
54 for (auto* subcmd : app.get_subcommands()) {
55 // Check if this subcommand was activated (nonzero count)
56 if (subcmd->count() > 0) {
57 vinfo(prefix, subcmd->get_name());
58 // Recursively print any subcommands of this subcommand
59 print_active_subcommands(*subcmd, prefix + " ");
60 }
61 }
62}
63
64// Recursive helper to find the deepest parsed subcommand.
65CLI::App* find_deepest_subcommand(CLI::App* app)
66{
67 for (auto& sub : app->get_subcommands()) {
68 if (sub->parsed()) {
69 // Check recursively if this subcommand has a deeper parsed subcommand.
70 if (CLI::App* deeper = find_deepest_subcommand(sub); deeper != nullptr) {
71 return deeper;
72 }
73 return sub;
74 }
75 }
76 return nullptr;
77}
78
79// Helper function to print options for a given subcommand.
80void print_subcommand_options(const CLI::App* sub)
81{
82 for (const auto& opt : sub->get_options()) {
83 if (opt->count() > 0) { // Only print options that were set.
84 if (opt->results().size() > 1) {
85 vinfo(" Warning: the following option is called more than once");
86 }
87 vinfo(" ", opt->get_name(), ": ", opt->results()[0]);
88 }
89 }
90}
91
111int parse_and_run_cli_command(int argc, char* argv[])
112{
113 std::string name = "Barretenberg\nYour favo(u)rite zkSNARK library written in C++, a perfectly good computer "
114 "programming language.";
115
116 // Check AVM support at runtime via global boolean
117 if (avm_enabled) {
118 name += "\nAztec Virtual Machine (AVM): enabled";
119 } else {
120 name += "\nAztec Virtual Machine (AVM): disabled";
121 }
122#ifdef ENABLE_AVM_TRANSPILER
123 name += "\nAVM Transpiler: enabled";
124#else
125 name += "\nAVM Transpiler: disabled";
126#endif
127#ifdef STARKNET_GARAGA_FLAVORS
128 name += "\nStarknet Garaga Extensions: enabled";
129#else
130 name += "\nStarknet Garaga Extensions: disabled";
131#endif
132 CLI::App app{ name };
133 argv = app.ensure_utf8(argv);
134 app.formatter(std::make_shared<Formatter>());
135
136 // If no arguments are provided, print help and exit.
137 if (argc == 1) {
138 std::cout << app.help() << std::endl;
139 return 0;
140 }
141
142 // prevent two or more subcommands being executed
143 app.require_subcommand(0, 1);
144
145 API::Flags flags{};
146 // Some paths, with defaults, that may or may not be set by commands
147 std::filesystem::path bytecode_path{ "./target/program.json" };
148 std::filesystem::path witness_path{ "./target/witness.gz" };
149 std::filesystem::path ivc_inputs_path{ "./ivc-inputs.msgpack" };
150 std::filesystem::path output_path{
151 "./out"
152 }; // sometimes a directory where things will be written, sometimes the path of a file to be written
153 std::filesystem::path public_inputs_path{ "./target/public_inputs" };
154 std::filesystem::path proof_path{ "./target/proof" };
155 std::filesystem::path vk_path{ "./target/vk" };
156 flags.scheme = "";
157 flags.oracle_hash_type = "poseidon2";
158 flags.crs_path = srs::bb_crs_path();
159 flags.include_gates_per_opcode = false;
160
161 /***************************************************************************************************************
162 * Flag: --help-extended (detected early to set group visibility)
163 ***************************************************************************************************************/
164 // Check if --help-extended was passed before parsing (since we need to modify group visibility before CLI setup)
165 bool show_extended_help = false;
166 for (int i = 1; i < argc; ++i) {
167 if (std::string(argv[i]) == "--help-extended") {
168 show_extended_help = true;
169 break;
170 }
171 }
172 // Group names - empty string hides the group from help, non-empty shows it
173 const std::string advanced_group = show_extended_help ? "Advanced Options (Aztec/Power Users)" : "";
174 const std::string aztec_internal_group = show_extended_help ? "Aztec Internal Commands" : "";
175
176 const auto add_output_path_option = [&](CLI::App* subcommand, auto& _output_path) {
177 return subcommand->add_option("--output_path, -o",
178 _output_path,
179 "Directory to write files or path of file to write, depending on subcommand.");
180 };
181
182 // Helper to add --help-extended to subcommands (for help consistency)
183 const auto add_help_extended_flag = [&](CLI::App* subcommand) {
184 subcommand->add_flag("--help-extended", "Show all options including advanced ones.");
185 };
186
187 /***************************************************************************************************************
188 * Subcommand: Adders for options that we will create for more than one subcommand
189 ***************************************************************************************************************/
190
191 const auto add_ipa_accumulation_flag = [&](CLI::App* subcommand) {
192 return subcommand
193 ->add_flag("--ipa_accumulation",
194 flags.ipa_accumulation,
195 "Accumulate/Aggregate IPA (Inner Product Argument) claims")
196 ->group(advanced_group);
197 };
198
199 const auto add_scheme_option = [&](CLI::App* subcommand) {
200 return subcommand
201 ->add_option(
202 "--scheme, -s",
203 flags.scheme,
204 "The type of proof to be constructed. This can specify a proving system, an accumulation scheme, or a "
205 "particular type of circuit to be constructed and proven for some implicit scheme.")
206 ->envname("BB_SCHEME")
207 ->default_val("ultra_honk")
208 ->check(CLI::IsMember({ "chonk", "avm", "ultra_honk" }).name("is_member"))
209 ->group(advanced_group);
210 };
211
212 const auto add_crs_path_option = [&](CLI::App* subcommand) {
213 return subcommand
214 ->add_option("--crs_path, -c",
215 flags.crs_path,
216 "Path CRS directory. Missing CRS files will be retrieved from the internet.")
217 ->check(CLI::ExistingDirectory)
218 ->group(advanced_group);
219 };
220
221 const auto add_oracle_hash_option = [&](CLI::App* subcommand) {
222 return subcommand
223 ->add_option(
224 "--oracle_hash",
225 flags.oracle_hash_type,
226 "The hash function used by the prover as random oracle standing in for a verifier's challenge "
227 "generation. Poseidon2 is to be used for proofs that are intended to be verified inside of a "
228 "circuit. Keccak is optimized for verification in an Ethereum smart contract, where Keccak "
229 "has a privileged position due to the existence of an EVM precompile. Starknet is optimized "
230 "for verification in a Starknet smart contract, which can be generated using the Garaga library. "
231 "Prefer using --verifier_target instead.")
232 ->check(CLI::IsMember({ "poseidon2", "keccak", "starknet" }).name("is_member"))
233 ->group(advanced_group);
234 };
235
236 const auto add_verifier_target_option = [&](CLI::App* subcommand) {
237 return subcommand
238 ->add_option("--verifier_target, -t",
239 flags.verifier_target,
240 "Target verification environment. Determines hash function and ZK settings.\n"
241 "\n"
242 "Options:\n"
243 " evm Ethereum/Solidity (keccak, ZK)\n"
244 " evm-no-zk Ethereum/Solidity without ZK\n"
245 " noir-recursive Noir circuits (poseidon2, ZK)\n"
246 " noir-recursive-no-zk Noir circuits without ZK\n"
247 " noir-rollup Rollup with IPA (poseidon2, ZK)\n"
248 " noir-rollup-no-zk Rollup without ZK\n"
249 " starknet Starknet via Garaga (ZK)\n"
250 " starknet-no-zk Starknet without ZK")
251 ->envname("BB_VERIFIER_TARGET")
252 ->check(CLI::IsMember({ "evm",
253 "evm-no-zk",
254 "noir-recursive",
255 "noir-recursive-no-zk",
256 "noir-rollup",
257 "noir-rollup-no-zk",
258 "starknet",
259 "starknet-no-zk" }));
260 };
261
262 const auto add_write_vk_flag = [&](CLI::App* subcommand) {
263 return subcommand->add_flag("--write_vk", flags.write_vk, "Write the provided circuit's verification key");
264 };
265
266 const auto remove_zk_option = [&](CLI::App* subcommand) {
267 return subcommand
268 ->add_flag("--disable_zk",
269 flags.disable_zk,
270 "Use a non-zk version of --scheme. Prefer using --verifier_target *-no-zk variants instead.")
271 ->group(advanced_group);
272 };
273
274 const auto add_bytecode_path_option = [&](CLI::App* subcommand) {
275 subcommand->add_option("--bytecode_path, -b", bytecode_path, "Path to ACIR bytecode generated by Noir.")
276 /* ->check(CLI::ExistingFile) OR stdin indicator - */;
277 };
278
279 const auto add_witness_path_option = [&](CLI::App* subcommand) {
280 subcommand->add_option("--witness_path, -w", witness_path, "Path to partial witness generated by Noir.")
281 /* ->check(CLI::ExistingFile) OR stdin indicator - */;
282 };
283
284 const auto add_ivc_inputs_path_options = [&](CLI::App* subcommand) {
285 subcommand
286 ->add_option(
287 "--ivc_inputs_path", ivc_inputs_path, "For IVC, path to input stack with bytecode and witnesses.")
288 ->group(advanced_group);
289 };
290
291 const auto add_public_inputs_path_option = [&](CLI::App* subcommand) {
292 return subcommand->add_option(
293 "--public_inputs_path, -i", public_inputs_path, "Path to public inputs.") /* ->check(CLI::ExistingFile) */;
294 };
295
296 const auto add_proof_path_option = [&](CLI::App* subcommand) {
297 return subcommand->add_option(
298 "--proof_path, -p", proof_path, "Path to a proof.") /* ->check(CLI::ExistingFile) */;
299 };
300
301 const auto add_vk_path_option = [&](CLI::App* subcommand) {
302 return subcommand->add_option("--vk_path, -k", vk_path, "Path to a verification key.")
303 /* ->check(CLI::ExistingFile) */;
304 };
305
306 const auto add_verbose_flag = [&](CLI::App* subcommand) {
307 return subcommand->add_flag("--verbose, --verbose_logging, -v", flags.verbose, "Output all logs to stderr.")
308 ->group(advanced_group);
309 };
310
311 const auto add_debug_flag = [&](CLI::App* subcommand) {
312 return subcommand->add_flag("--debug_logging, -d", flags.debug, "Output debug logs to stderr.")
313 ->group(advanced_group);
314 };
315
316 bool disable_asserts = false;
317 const auto add_disable_asserts_flag = [&](CLI::App* subcommand) {
318 return subcommand
319 ->add_flag("--disable_asserts",
320 disable_asserts,
321 "Disable BB assertions (asserts become warnings). Not for production use.")
322 ->group(advanced_group);
323 };
324
325 const auto add_include_gates_per_opcode_flag = [&](CLI::App* subcommand) {
326 return subcommand->add_flag("--include_gates_per_opcode",
327 flags.include_gates_per_opcode,
328 "Include gates_per_opcode in the output of the gates command.");
329 };
330
331 const auto add_slow_low_memory_flag = [&](CLI::App* subcommand) {
332 return subcommand
333 ->add_flag("--slow_low_memory", flags.slow_low_memory, "Enable low memory mode (can be 2x slower or more).")
334 ->group(advanced_group);
335 };
336
337 const auto add_storage_budget_option = [&](CLI::App* subcommand) {
338 return subcommand
339 ->add_option("--storage_budget",
340 flags.storage_budget,
341 "Storage budget for FileBackedMemory (e.g. '500m', '2g'). When exceeded, falls "
342 "back to RAM (requires --slow_low_memory).")
343 ->group(advanced_group);
344 };
345
346 const auto add_vk_policy_option = [&](CLI::App* subcommand) {
347 return subcommand
348 ->add_option("--vk_policy",
349 flags.vk_policy,
350 "Policy for handling verification keys. 'default' uses the provided VK as-is, 'check' "
351 "verifies the provided VK matches the computed VK (throws error on mismatch), 'recompute' "
352 "always ignores the provided VK and treats it as nullptr, 'rewrite' checks the VK and "
353 "rewrites the input file with the correct VK if there's a mismatch (for check command).")
354 ->check(CLI::IsMember({ "default", "check", "recompute", "rewrite" }).name("is_member"))
355 ->group(advanced_group);
356 };
357
358 const auto add_use_zk_flavor_flag = [&](CLI::App* subcommand) {
359 return subcommand
360 ->add_flag("--use_zk_flavor",
361 flags.use_zk_flavor,
362 "Chonk-only: derive the VK against MegaZKFlavor rather than MegaFlavor. "
363 "Set this for the IVC hiding kernel (the only Chonk circuit proven as MegaZK).")
364 ->group(advanced_group);
365 };
366
367 const auto add_optimized_solidity_verifier_flag = [&](CLI::App* subcommand) {
368 return subcommand->add_flag(
369 "--optimized", flags.optimized_solidity_verifier, "Use the optimized Solidity verifier.");
370 };
371
372 const auto add_output_format_option = [&](CLI::App* subcommand) {
373 return subcommand
374 ->add_option("--output_format",
375 flags.output_format,
376 "Output format for proofs and verification keys: 'binary' (default) or 'json'.\n"
377 "JSON format includes metadata like bb_version, scheme, and verifier_target.")
378 ->check(CLI::IsMember({ "binary", "json" }).name("is_member"));
379 };
380
381 bool print_bench = false;
382 const auto add_print_bench_flag = [&](CLI::App* subcommand) {
383 return subcommand
384 ->add_flag(
385 "--print_bench", print_bench, "Pretty print op counts to standard error in a human-readable format.")
386 ->group(advanced_group);
387 };
388
389 std::string bench_out;
390 const auto add_bench_out_option = [&](CLI::App* subcommand) {
391 return subcommand->add_option("--bench_out", bench_out, "Path to write the op counts in a json.")
392 ->group(advanced_group);
393 };
394 std::string bench_out_hierarchical;
395 const auto add_bench_out_hierarchical_option = [&](CLI::App* subcommand) {
396 return subcommand
397 ->add_option("--bench_out_hierarchical",
398 bench_out_hierarchical,
399 "Path to write the hierarchical benchmark data (op counts and timings with "
400 "parent-child relationships) as json.")
401 ->group(advanced_group);
402 };
403 std::string memory_profile_out;
404 const auto add_memory_profile_out_option = [&](CLI::App* subcommand) {
405 return subcommand
406 ->add_option("--memory_profile_out",
407 memory_profile_out,
408 "Path to write memory profile data (polynomial breakdown by category, RSS "
409 "checkpoints, CRS size) as json.")
410 ->group(advanced_group);
411 };
412
413 std::string trace_out_perfetto;
414 const auto add_trace_out_perfetto_option = [&](CLI::App* subcommand) {
415 return subcommand
416 ->add_option("--trace_out_perfetto",
417 trace_out_perfetto,
418 "Path to write a Chrome Trace Event Format JSON of every instrumented "
419 "BB_BENCH scope (per-call timeline). Drop the file into ui.perfetto.dev "
420 "or chrome://tracing.")
421 ->group(advanced_group);
422 };
423 std::string trace_out_perfetto_aggregate;
424 const auto add_trace_out_perfetto_aggregate_option = [&](CLI::App* subcommand) {
425 return subcommand
426 ->add_option("--trace_out_perfetto_aggregate",
427 trace_out_perfetto_aggregate,
428 "Path to write a synthesized Chrome Trace Event Format JSON derived from the "
429 "aggregate stats. Smaller than --trace_out_perfetto but lossy about individual "
430 "call timing.")
431 ->group(advanced_group);
432 };
433
434 /***************************************************************************************************************
435 * Top-level flags
436 ***************************************************************************************************************/
437 add_verbose_flag(&app);
438 add_debug_flag(&app);
439 add_crs_path_option(&app);
440
441 /***************************************************************************************************************
442 * Builtin flag: --version
443 ***************************************************************************************************************/
444 app.set_version_flag("--version", BB_VERSION, "Print the version string.");
445
446 /***************************************************************************************************************
447 * Flag: --help-extended (register with CLI11)
448 ***************************************************************************************************************/
449 app.add_flag("--help-extended", "Show all options including advanced and Aztec-specific commands.");
450
451 /***************************************************************************************************************
452 * Subcommand: acir_roundtrip
453 ***************************************************************************************************************/
454 std::filesystem::path acir_roundtrip_output_path;
455 CLI::App* acir_roundtrip_cmd =
456 app.add_subcommand("acir_roundtrip",
457 "[Internal testing] Deserialize an ACIR program from bytecode (msgpack), "
458 "re-serialize it back to msgpack, and write it to an output JSON file "
459 "in nargo-compatible format. Functional equivalence should then be verified "
460 "externally (e.g. by proving with the roundtripped bytecode).");
461
462 acir_roundtrip_cmd->group(aztec_internal_group);
463 add_bytecode_path_option(acir_roundtrip_cmd);
464 acir_roundtrip_cmd
465 ->add_option("--output_path,-o", acir_roundtrip_output_path, "Output path for the roundtripped bytecode JSON.")
466 ->required();
467
468 /***************************************************************************************************************
469 * Subcommand: check
470 ***************************************************************************************************************/
471 CLI::App* check = app.add_subcommand(
472 "check",
473 "A debugging tool to quickly check whether a witness satisfies a circuit The "
474 "function constructs the execution trace and iterates through it row by row, applying the "
475 "polynomial relations defining the gate types. For Chonk, we check the VKs in the folding stack.");
476
477 add_help_extended_flag(check);
478 add_scheme_option(check);
479 add_bytecode_path_option(check);
480 add_witness_path_option(check);
481 add_ivc_inputs_path_options(check);
482 add_vk_policy_option(check);
483 add_disable_asserts_flag(check);
484
485 /***************************************************************************************************************
486 * Subcommand: gates
487 ***************************************************************************************************************/
488 CLI::App* gates = app.add_subcommand("gates",
489 "Construct a circuit from the given bytecode (in particular, expand black box "
490 "functions) and return the gate count information.");
491
492 add_help_extended_flag(gates);
493 add_scheme_option(gates);
494 add_verbose_flag(gates);
495 add_bytecode_path_option(gates);
496 add_include_gates_per_opcode_flag(gates);
497 add_verifier_target_option(gates);
498 add_oracle_hash_option(gates);
499 add_ipa_accumulation_flag(gates);
500
501 /***************************************************************************************************************
502 * Subcommand: prove
503 ***************************************************************************************************************/
504 CLI::App* prove = app.add_subcommand("prove", "Generate a proof.");
505
506 add_help_extended_flag(prove);
507 add_scheme_option(prove);
508 add_bytecode_path_option(prove);
509 add_witness_path_option(prove);
510 add_output_path_option(prove, output_path);
511 add_ivc_inputs_path_options(prove);
512 add_vk_path_option(prove);
513 add_vk_policy_option(prove);
514 add_verbose_flag(prove);
515 add_debug_flag(prove);
516 add_crs_path_option(prove);
517 add_verifier_target_option(prove);
518 add_oracle_hash_option(prove);
519 add_write_vk_flag(prove);
520 add_ipa_accumulation_flag(prove);
521 remove_zk_option(prove);
522 add_slow_low_memory_flag(prove);
523 add_print_bench_flag(prove);
524 add_bench_out_option(prove);
525 add_bench_out_hierarchical_option(prove);
526 add_memory_profile_out_option(prove);
527 add_trace_out_perfetto_option(prove);
528 add_trace_out_perfetto_aggregate_option(prove);
529 add_storage_budget_option(prove);
530 add_output_format_option(prove);
531
532 prove->add_flag("--verify", "Verify the proof natively, resulting in a boolean output. Useful for testing.");
533
534 /***************************************************************************************************************
535 * Subcommand: write_vk
536 ***************************************************************************************************************/
537 CLI::App* write_vk =
538 app.add_subcommand("write_vk",
539 "Write the verification key of a circuit. The circuit is constructed using "
540 "quickly generated but invalid witnesses (which must be supplied in Barretenberg in order "
541 "to expand ACIR black box opcodes), and no proof is constructed.");
542
543 add_help_extended_flag(write_vk);
544 add_scheme_option(write_vk);
545 add_bytecode_path_option(write_vk);
546 add_output_path_option(write_vk, output_path);
547 add_ivc_inputs_path_options(write_vk);
548
549 add_verbose_flag(write_vk);
550 add_debug_flag(write_vk);
551 add_crs_path_option(write_vk);
552 add_verifier_target_option(write_vk);
553 add_oracle_hash_option(write_vk);
554 add_ipa_accumulation_flag(write_vk);
555 remove_zk_option(write_vk);
556 add_output_format_option(write_vk);
557 add_use_zk_flavor_flag(write_vk);
558
559 /***************************************************************************************************************
560 * Subcommand: verify
561 ***************************************************************************************************************/
562 CLI::App* verify = app.add_subcommand("verify", "Verify a proof.");
563
564 add_help_extended_flag(verify);
565 add_public_inputs_path_option(verify);
566 add_proof_path_option(verify);
567 add_vk_path_option(verify);
568
569 add_verbose_flag(verify);
570 add_debug_flag(verify);
571 add_scheme_option(verify);
572 add_crs_path_option(verify);
573 add_verifier_target_option(verify);
574 add_oracle_hash_option(verify);
575 remove_zk_option(verify);
576 add_ipa_accumulation_flag(verify);
577
578 /***************************************************************************************************************
579 * Subcommand: batch_verify
580 ***************************************************************************************************************/
581 std::filesystem::path batch_verify_proofs_dir{ "./proofs" };
582 CLI::App* batch_verify =
583 app.add_subcommand("batch_verify", "Batch-verify multiple Chonk proofs with batched IPA SRS MSMs.");
584
585 add_help_extended_flag(batch_verify);
586 add_scheme_option(batch_verify);
587 batch_verify->add_option("--proofs_dir", batch_verify_proofs_dir, "Directory containing proof_N/vk_N pairs.");
588 add_verbose_flag(batch_verify);
589 add_debug_flag(batch_verify);
590 add_crs_path_option(batch_verify);
591
592 /***************************************************************************************************************
593 * Subcommand: proof_stats
594 ***************************************************************************************************************/
595 CLI::App* proof_stats =
596 app.add_subcommand("proof_stats", "Output proof statistics (compressed size, number of public inputs).");
597
598 add_help_extended_flag(proof_stats);
599 add_scheme_option(proof_stats);
600 add_proof_path_option(proof_stats);
601 add_output_path_option(proof_stats, output_path);
602 add_verbose_flag(proof_stats);
603
604 /***************************************************************************************************************
605 * Subcommand: write_solidity_verifier
606 ***************************************************************************************************************/
607 CLI::App* write_solidity_verifier =
608 app.add_subcommand("write_solidity_verifier",
609 "Write a Solidity smart contract suitable for verifying proofs of circuit "
610 "satisfiability for the circuit with verification key at vk_path. Not all "
611 "hash types are implemented due to efficiency concerns.");
612
613 add_help_extended_flag(write_solidity_verifier);
614 add_scheme_option(write_solidity_verifier);
615 add_vk_path_option(write_solidity_verifier);
616 add_output_path_option(write_solidity_verifier, output_path);
617
618 add_verbose_flag(write_solidity_verifier);
619 add_verifier_target_option(write_solidity_verifier);
620 remove_zk_option(write_solidity_verifier);
621 add_crs_path_option(write_solidity_verifier);
622 add_optimized_solidity_verifier_flag(write_solidity_verifier);
623
624 std::filesystem::path avm_inputs_path{ "./target/avm_inputs.bin" };
625 const auto add_avm_inputs_option = [&](CLI::App* subcommand) {
626 return subcommand->add_option("--avm-inputs", avm_inputs_path, "");
627 };
628 std::filesystem::path avm_public_inputs_path{ "./target/avm_public_inputs.bin" };
629 const auto add_avm_public_inputs_option = [&](CLI::App* subcommand) {
630 return subcommand->add_option("--avm-public-inputs", avm_public_inputs_path, "");
631 };
632
633 /***************************************************************************************************************
634 * Subcommand: avm_simulate
635 ***************************************************************************************************************/
636 CLI::App* avm_simulate_command = app.add_subcommand("avm_simulate", "Simulate AVM execution.");
637 avm_simulate_command->group(aztec_internal_group);
638 add_verbose_flag(avm_simulate_command);
639 add_debug_flag(avm_simulate_command);
640 add_avm_inputs_option(avm_simulate_command);
641
642 /***************************************************************************************************************
643 * Subcommand: avm_prove
644 ***************************************************************************************************************/
645 CLI::App* avm_prove_command = app.add_subcommand("avm_prove", "Generate an AVM proof.");
646 avm_prove_command->group(aztec_internal_group);
647 add_verbose_flag(avm_prove_command);
648 add_debug_flag(avm_prove_command);
649 add_crs_path_option(avm_prove_command);
650 std::filesystem::path avm_prove_output_path{ "./proofs" };
651 add_output_path_option(avm_prove_command, avm_prove_output_path);
652 add_avm_inputs_option(avm_prove_command);
653
654 /***************************************************************************************************************
655 * Subcommand: avm_write_vk
656 ***************************************************************************************************************/
657 CLI::App* avm_write_vk_command = app.add_subcommand("avm_write_vk", "Write AVM verification key.");
658 avm_write_vk_command->group(aztec_internal_group);
659 add_verbose_flag(avm_write_vk_command);
660 add_debug_flag(avm_write_vk_command);
661 add_crs_path_option(avm_write_vk_command);
662 std::filesystem::path avm_write_vk_output_path{ "./keys" };
663 add_output_path_option(avm_write_vk_command, avm_write_vk_output_path);
664
665 /***************************************************************************************************************
666 * Subcommand: avm_check_circuit
667 ***************************************************************************************************************/
668 CLI::App* avm_check_circuit_command = app.add_subcommand("avm_check_circuit", "Check AVM circuit satisfiability.");
669 avm_check_circuit_command->group(aztec_internal_group);
670 add_verbose_flag(avm_check_circuit_command);
671 add_debug_flag(avm_check_circuit_command);
672 add_crs_path_option(avm_check_circuit_command);
673 add_avm_inputs_option(avm_check_circuit_command);
674
675 /***************************************************************************************************************
676 * Subcommand: avm_verify
677 ***************************************************************************************************************/
678 CLI::App* avm_verify_command = app.add_subcommand("avm_verify", "Verify an AVM proof.");
679 avm_verify_command->group(aztec_internal_group);
680 add_verbose_flag(avm_verify_command);
681 add_debug_flag(avm_verify_command);
682 add_crs_path_option(avm_verify_command);
683 add_avm_public_inputs_option(avm_verify_command);
684 add_proof_path_option(avm_verify_command);
685
686 /***************************************************************************************************************
687 * Subcommand: aztec_process_artifact
688 ***************************************************************************************************************/
689 CLI::App* aztec_process = app.add_subcommand(
690 "aztec_process",
691 "Process Aztec contract artifacts: transpile and generate verification keys for all private functions.\n"
692 "If input is a directory (and no output specified), recursively processes all artifacts found in the "
693 "directory.\n"
694 "Multiple -i flags can be specified when no -o flag is present for parallel processing.");
695 aztec_process->group(aztec_internal_group);
696
697 std::vector<std::string> artifact_input_paths;
698 std::string artifact_output_path;
699 bool force_regenerate = false;
700
701 aztec_process->add_option("-i,--input",
702 artifact_input_paths,
703 "Input artifact JSON path or directory to search (optional, defaults to current "
704 "directory). Can be specified multiple times when no -o flag is present.");
705 aztec_process->add_option(
706 "-o,--output",
707 artifact_output_path,
708 "Output artifact JSON path (optional, same as input if not specified). Cannot be used with multiple -i flags.");
709 aztec_process->add_flag("-f,--force", force_regenerate, "Force regeneration of verification keys");
710 add_verbose_flag(aztec_process);
711 add_debug_flag(aztec_process);
712
713 /***************************************************************************************************************
714 * Subcommand: aztec_process cache_paths
715 ***************************************************************************************************************/
716 CLI::App* cache_paths_command =
717 aztec_process->add_subcommand("cache_paths",
718 "Output cache paths for verification keys in an artifact.\n"
719 "Format: <hash>:<cache_path>:<function_name> (one per line).");
720
721 std::string cache_paths_input;
722 cache_paths_command->add_option("input", cache_paths_input, "Input artifact JSON path (required).")->required();
723 add_verbose_flag(cache_paths_command);
724 add_debug_flag(cache_paths_command);
725
726 /***************************************************************************************************************
727 * Subcommand: msgpack
728 ***************************************************************************************************************/
729 CLI::App* msgpack_command = app.add_subcommand("msgpack", "Msgpack API interface.");
730
731 // Subcommand: msgpack schema
732 CLI::App* msgpack_schema_command =
733 msgpack_command->add_subcommand("schema", "Output a msgpack schema encoded as JSON to stdout.");
734 add_verbose_flag(msgpack_schema_command);
735
736 // Subcommand: msgpack curve_constants
737 CLI::App* msgpack_curve_constants_command =
738 msgpack_command->add_subcommand("curve_constants", "Output curve constants as msgpack to stdout.");
739 add_verbose_flag(msgpack_curve_constants_command);
740
741 // Subcommand: msgpack run
742 CLI::App* msgpack_run_command =
743 msgpack_command->add_subcommand("run", "Execute msgpack API commands from stdin or file.");
744 add_verbose_flag(msgpack_run_command);
745 std::string msgpack_input_file;
746 msgpack_run_command->add_option(
747 "-i,--input", msgpack_input_file, "Input file containing msgpack buffers (defaults to stdin)");
748 size_t request_ring_size = 1024 * 1024; // 1MB default
749 msgpack_run_command
750 ->add_option(
751 "--request-ring-size", request_ring_size, "Request ring buffer size for shared memory IPC (default: 1MB)")
752 ->check(CLI::PositiveNumber);
753 size_t response_ring_size = 1024 * 1024; // 1MB default
754 msgpack_run_command
755 ->add_option("--response-ring-size",
756 response_ring_size,
757 "Response ring buffer size for shared memory IPC (default: 1MB)")
758 ->check(CLI::PositiveNumber);
759 int max_clients = 1;
760 msgpack_run_command
761 ->add_option("--max-clients",
762 max_clients,
763 "Maximum concurrent clients for socket IPC servers (default: 1, only used for .sock files)")
764 ->check(CLI::PositiveNumber);
765
766 /***************************************************************************************************************
767 * Build the CLI11 App
768 ***************************************************************************************************************/
769
770 CLI11_PARSE(app, argc, argv);
771
772 // Handle --help-extended: print help and exit
773 if (show_extended_help) {
774 std::cout << app.help() << '\n';
775 return 0;
776 }
777
778 // Apply verifier_target to derive oracle_hash_type, disable_zk, and ipa_accumulation
779 // This only applies when verifier_target is explicitly set
780 if (!flags.verifier_target.empty()) {
781 // Check for conflicting flags - verifier_target should not be combined with low-level flags
782 // We need to check the active subcommand for these options
783 CLI::App* active_sub = find_deepest_subcommand(&app);
784 if (active_sub != nullptr) {
785 // Helper to safely get option count (returns 0 if option doesn't exist)
786 auto get_option_count = [](CLI::App* sub, const std::string& name) -> size_t {
787 auto* option = sub->get_option_no_THROW(name);
788 if (option == nullptr) {
789 return 0;
790 }
791 return option->count();
792 };
793
794 if (get_option_count(active_sub, "--oracle_hash") > 0) {
795 throw_or_abort("Cannot use --verifier_target with --oracle_hash. "
796 "The --verifier_target flag sets oracle_hash automatically.");
797 }
798 if (get_option_count(active_sub, "--disable_zk") > 0) {
799 throw_or_abort("Cannot use --verifier_target with --disable_zk. "
800 "Use a '-no-zk' variant of --verifier_target instead (e.g., 'evm-no-zk').");
801 }
802 if (get_option_count(active_sub, "--ipa_accumulation") > 0) {
803 throw_or_abort("Cannot use --verifier_target with --ipa_accumulation. "
804 "Use '--verifier_target noir-rollup' for IPA accumulation.");
805 }
806 }
807
808 // Map verifier_target to underlying flags
809 if (flags.verifier_target == "evm") {
810 flags.oracle_hash_type = "keccak";
811 } else if (flags.verifier_target == "evm-no-zk") {
812 flags.oracle_hash_type = "keccak";
813 flags.disable_zk = true;
814 } else if (flags.verifier_target == "noir-recursive") {
815 flags.oracle_hash_type = "poseidon2";
816 } else if (flags.verifier_target == "noir-recursive-no-zk") {
817 flags.oracle_hash_type = "poseidon2";
818 flags.disable_zk = true;
819 } else if (flags.verifier_target == "noir-rollup") {
820 flags.oracle_hash_type = "poseidon2";
821 flags.ipa_accumulation = true;
822 } else if (flags.verifier_target == "noir-rollup-no-zk") {
823 flags.oracle_hash_type = "poseidon2";
824 flags.ipa_accumulation = true;
825 flags.disable_zk = true;
826 } else if (flags.verifier_target == "starknet") {
827 flags.oracle_hash_type = "starknet";
828 } else if (flags.verifier_target == "starknet-no-zk") {
829 flags.oracle_hash_type = "starknet";
830 flags.disable_zk = true;
831 }
832 vinfo("verifier_target '",
833 flags.verifier_target,
834 "' -> oracle_hash_type='",
835 flags.oracle_hash_type,
836 "', disable_zk=",
837 flags.disable_zk,
838 ", ipa_accumulation=",
839 flags.ipa_accumulation);
840 }
841
842 // Immediately after parsing, we can init the global CRS factory. Note this does not yet read or download any
843 // points; that is done on-demand.
844 srs::init_net_crs_factory(flags.crs_path);
845 if ((prove->parsed() || write_vk->parsed()) && output_path != "-") {
846 // If writing to an output folder, make sure it exists.
847 std::filesystem::create_directories(output_path);
848 }
849 if (flags.debug) {
851 } else if (flags.verbose) {
853 }
854 slow_low_memory = flags.slow_low_memory;
855#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
856 if (!flags.storage_budget.empty()) {
857 storage_budget = parse_size_string(flags.storage_budget);
858 }
859 if (!memory_profile_out.empty()) {
861 vinfo("Memory profiling enabled via --memory_profile_out");
862 }
863 if (print_bench || !bench_out.empty() || !bench_out_hierarchical.empty() || !trace_out_perfetto.empty() ||
864 !trace_out_perfetto_aggregate.empty()) {
866 vinfo("BB_BENCH enabled via --print_bench / --bench_out / --trace_out_perfetto");
867 }
868 if (!trace_out_perfetto.empty()) {
870 vinfo("Per-call BB_BENCH event capture enabled via --trace_out_perfetto");
871 }
872#endif
873
875 info("Scheme is: ", flags.scheme, ", num threads: ", get_num_cpus());
876 if (CLI::App* deepest = find_deepest_subcommand(&app)) {
878 }
879
880 // TODO(AD): it is inflexible that Chonk shares an API command (prove) with UH this way. The base API class is a
881 // poor fit. It would be better to have a separate handling for each scheme with subcommands to prove.
882 const auto execute_non_prove_command = [&](API& api) {
883 if (check->parsed()) {
884 api.check(flags, bytecode_path, witness_path);
885 return 0;
886 }
887 if (gates->parsed()) {
888 api.gates(flags, bytecode_path);
889 return 0;
890 }
891 if (write_vk->parsed()) {
892 api.write_vk(flags, bytecode_path, output_path);
893 return 0;
894 }
895 if (verify->parsed()) {
896 const bool verified = api.verify(flags, public_inputs_path, proof_path, vk_path);
897 vinfo("verified: ", verified);
898 return verified ? 0 : 1;
899 }
900 if (write_solidity_verifier->parsed()) {
901 // Validate that verifier_target is compatible with Solidity verifier
902 if (!flags.verifier_target.empty() && flags.verifier_target != "evm" &&
903 flags.verifier_target != "evm-no-zk") {
904 throw_or_abort("write_solidity_verifier requires --verifier_target to be 'evm' or 'evm-no-zk', got '" +
905 flags.verifier_target + "'");
906 }
907 api.write_solidity_verifier(flags, output_path, vk_path);
908 return 0;
909 }
910 auto subcommands = app.get_subcommands();
911 const std::string message = std::string("No handler for subcommand ") + subcommands[0]->get_name();
912 throw_or_abort(message);
913 return 1;
914 };
915
916#ifndef BB_NO_EXCEPTIONS
917 try
918#endif
919 {
920 // ACIR roundtrip (internal testing)
921 if (acir_roundtrip_cmd->parsed()) {
922 acir_roundtrip(bytecode_path, acir_roundtrip_output_path);
923 return 0;
924 }
925
926 // MSGPACK
927 if (msgpack_schema_command->parsed()) {
929 return 0;
930 }
931 if (msgpack_curve_constants_command->parsed()) {
933 return 0;
934 }
935 if (msgpack_run_command->parsed()) {
936 return execute_msgpack_run(msgpack_input_file, max_clients, request_ring_size, response_ring_size);
937 }
938 if (aztec_process->parsed()) {
939#ifdef __wasm__
940 throw_or_abort("Aztec artifact processing is not supported in WASM builds.");
941#else
942 // Handle cache_paths subcommand
943 if (cache_paths_command->parsed()) {
944 return get_cache_paths(cache_paths_input) ? 0 : 1;
945 }
946
947 // Check for invalid combination of multiple inputs with output path
948 if (!artifact_output_path.empty() && artifact_input_paths.size() > 1) {
949 throw_or_abort("Cannot specify --output when multiple --input flags are provided.");
950 }
951
952 // Default to current directory if no inputs specified
953 if (artifact_input_paths.empty()) {
954 artifact_input_paths.push_back(".");
955 }
956
957 // Handle multiple inputs (process in parallel)
958 if (artifact_input_paths.size() > 1) {
959 // Validate all inputs are files, not directories
960 for (const auto& input : artifact_input_paths) {
961 if (std::filesystem::is_directory(input)) {
962 throw_or_abort("When using multiple --input flags, all inputs must be files, not directories.");
963 }
964 }
965
966 // Process all artifacts in parallel
967 std::atomic<bool> all_success = true;
968 std::vector<std::string> failures;
969 std::mutex failures_mutex;
970
971 parallel_for(artifact_input_paths.size(), [&](size_t i) {
972 const auto& input = artifact_input_paths[i];
973 if (!process_aztec_artifact(input, input, force_regenerate)) {
974 all_success = false;
975 std::lock_guard<std::mutex> lock(failures_mutex);
976 failures.push_back(input);
977 }
978 });
979
980 if (!all_success) {
981 info("Failed to process ", failures.size(), " artifact(s)");
982 return 1;
983 }
984 info("Successfully processed ", artifact_input_paths.size(), " artifact(s)");
985 return 0;
986 }
987
988 // Single input case
989 std::string input = artifact_input_paths[0];
990
991 // Check if input is a directory
992 if (std::filesystem::is_directory(input)) {
993 // If output specified for directory input, that's an error
994 if (!artifact_output_path.empty()) {
996 "Cannot specify --output when input is a directory. Artifacts are updated in-place.");
997 }
998 // Recursively process all artifacts in directory
999 return process_all_artifacts(input, force_regenerate) ? 0 : 1;
1000 }
1001
1002 // Input is a file, process single artifact
1003 std::string output = artifact_output_path.empty() ? input : artifact_output_path;
1004 return process_aztec_artifact(input, output, force_regenerate) ? 0 : 1;
1005#endif
1006 }
1007 // AVM - functions will throw at runtime if not supported (via stub module)
1008 else if (avm_prove_command->parsed()) {
1009 // This outputs both files: proof and vk, under the given directory.
1010 avm_prove(avm_inputs_path, avm_prove_output_path);
1011 } else if (avm_check_circuit_command->parsed()) {
1012 avm_check_circuit(avm_inputs_path);
1013 } else if (avm_verify_command->parsed()) {
1014 return avm_verify(proof_path, avm_public_inputs_path) ? 0 : 1;
1015 } else if (avm_simulate_command->parsed()) {
1016 avm_simulate(avm_inputs_path);
1017 } else if (avm_write_vk_command->parsed()) {
1018 avm_write_verification_key(avm_write_vk_output_path);
1019 } else if (flags.scheme == "chonk") {
1020 ChonkAPI api;
1021 if (prove->parsed()) {
1022 if (!std::filesystem::exists(ivc_inputs_path)) {
1023 throw_or_abort("The prove command for Chonk expect a valid file passed with --ivc_inputs_path "
1024 "<ivc-inputs.msgpack> (default ./ivc-inputs.msgpack)");
1025 }
1026 api.prove(flags, ivc_inputs_path, output_path);
1027#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
1028 if (print_bench) {
1029 vinfo("Printing BB_BENCH results...");
1032 }
1033 if (!bench_out.empty()) {
1034 std::ofstream file(bench_out);
1036 }
1037 if (!bench_out_hierarchical.empty()) {
1038 std::ofstream file(bench_out_hierarchical);
1040 }
1041 if (!trace_out_perfetto.empty()) {
1042 std::ofstream file(trace_out_perfetto);
1044 vinfo("Perfetto per-call trace written to ", trace_out_perfetto);
1045 }
1046 if (!trace_out_perfetto_aggregate.empty()) {
1047 std::ofstream file(trace_out_perfetto_aggregate);
1049 vinfo("Perfetto aggregate trace written to ", trace_out_perfetto_aggregate);
1050 }
1051#endif
1052 if (!memory_profile_out.empty()) {
1053 std::ofstream file(memory_profile_out);
1055 vinfo("Memory profile written to ", memory_profile_out);
1056 }
1057 return 0;
1058 }
1059 if (check->parsed()) {
1060 if (!std::filesystem::exists(ivc_inputs_path)) {
1061 throw_or_abort("The check command for Chonk expect a valid file passed with --ivc_inputs_path "
1062 "<ivc-inputs.msgpack> (default ./ivc-inputs.msgpack)");
1063 }
1064 if (disable_asserts) {
1066 return api.check_precomputed_vks(flags, ivc_inputs_path) ? 0 : 1;
1067 }
1068 return api.check_precomputed_vks(flags, ivc_inputs_path) ? 0 : 1;
1069 }
1070 if (batch_verify->parsed()) {
1071 const bool verified = api.batch_verify(flags, batch_verify_proofs_dir);
1072 vinfo("batch verified: ", verified);
1073 return verified ? 0 : 1;
1074 }
1075 if (proof_stats->parsed()) {
1076 api.proof_stats(proof_path, output_path);
1077 return 0;
1078 }
1079 return execute_non_prove_command(api);
1080 } else if (flags.scheme == "ultra_honk") {
1081 UltraHonkAPI api;
1082 if (prove->parsed()) {
1083 api.prove(flags, bytecode_path, witness_path, vk_path, output_path);
1084#if !defined(__wasm__) || defined(ENABLE_WASM_BENCH)
1085 if (print_bench) {
1087 }
1088 if (!bench_out.empty()) {
1089 std::ofstream file(bench_out);
1091 }
1092 if (!bench_out_hierarchical.empty()) {
1093 std::ofstream file(bench_out_hierarchical);
1095 }
1096 if (!trace_out_perfetto.empty()) {
1097 std::ofstream file(trace_out_perfetto);
1099 vinfo("Perfetto per-call trace written to ", trace_out_perfetto);
1100 }
1101 if (!trace_out_perfetto_aggregate.empty()) {
1102 std::ofstream file(trace_out_perfetto_aggregate);
1104 vinfo("Perfetto aggregate trace written to ", trace_out_perfetto_aggregate);
1105 }
1106#endif
1107 return 0;
1108 }
1109 return execute_non_prove_command(api);
1110 } else {
1111 throw_or_abort("No match for API command");
1112 return 1;
1113 }
1114 }
1115#ifndef BB_NO_EXCEPTIONS
1116 catch (std::runtime_error const& err) {
1117 std::cerr << err.what() << std::endl;
1118 return 1;
1119 }
1120#endif
1121 return 0;
1122}
1123} // namespace bb
#define BB_DISABLE_ASSERTS()
Definition assert.hpp:33
size_t parse_size_string(const std::string &size_str)
bool slow_low_memory
size_t storage_budget
Definition api.hpp:7
CLI API for Chonk (Aztec's client-side proving).
Definition api_chonk.hpp:33
void proof_stats(const std::filesystem::path &proof_path, const std::filesystem::path &output_path)
Output proof statistics: compressed proof and its size.
bool batch_verify(const Flags &flags, const std::filesystem::path &proofs_dir)
Batch-verify multiple Chonk proofs from a directory of proof_N/vk_N pairs.
void prove(const Flags &flags, const std::filesystem::path &input_path, const std::filesystem::path &output_dir)
Main production entry point: generate a Chonk proof from private execution steps.
Definition api_chonk.cpp:62
bool check_precomputed_vks(const Flags &flags, const std::filesystem::path &input_path)
Validate that precomputed VKs in ivc-inputs.msgpack match computed VKs.
void prove(const Flags &flags, const std::filesystem::path &bytecode_path, const std::filesystem::path &witness_path, const std::filesystem::path &vk_path, const std::filesystem::path &output_dir)
group class. Represents an elliptic curve group element. Group is parametrised by Fq and Fr
Definition group.hpp:38
#define CLI11_PARSE(app,...)
#define info(...)
Definition log.hpp:93
#define vinfo(...)
Definition log.hpp:94
Programmatic interface for generating msgpack-encoded curve constants.
LogLevel bb_log_level
Definition log.cpp:9
std::string get_bb_schema_as_json()
bool use_memory_profile
MemoryProfile GLOBAL_MEMORY_PROFILE
GlobalBenchStatsContainer GLOBAL_BENCH_STATS
Definition bb_bench.cpp:822
std::atomic< bool > capture_per_call_events
Definition bb_bench.cpp:177
bool use_bb_bench
Definition bb_bench.cpp:175
void init_net_crs_factory(const std::filesystem::path &path)
std::filesystem::path bb_crs_path()
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
void print_subcommand_options(const CLI::App *sub)
Definition cli.cpp:80
void avm_simulate(const std::filesystem::path &inputs_path)
Simulates an public transaction.
Definition api_avm.cpp:78
int execute_msgpack_run(const std::string &msgpack_input_file, int max_clients, size_t request_ring_size, size_t response_ring_size)
Execute msgpack run command.
int parse_and_run_cli_command(int argc, char *argv[])
Parse command line arguments and run the corresponding command.
Definition cli.cpp:111
bool process_all_artifacts(const std::string &search_path, bool force)
Process all discovered contract artifacts in a directory tree.
bool get_cache_paths(const std::string &input_path)
Get cache paths for all verification keys in an artifact.
void write_curve_constants_msgpack_to_stdout()
Write msgpack-encoded curve constants to stdout.
bool process_aztec_artifact(const std::string &input_path, const std::string &output_path, bool force)
Process Aztec contract artifacts: transpile and generate verification keys.
size_t get_num_cpus()
Definition thread.cpp:33
void acir_roundtrip(const std::filesystem::path &bytecode_path, const std::filesystem::path &output_path)
Deserialize an ACIR program from bytecode (msgpack), re-serialize it, and write the result to an outp...
Definition api_acir.cpp:14
bool avm_verify(const std::filesystem::path &proof_path, const std::filesystem::path &public_inputs_path)
Verifies an avm proof and writes the result to stdout.
Definition api_avm.cpp:65
void print_active_subcommands(const CLI::App &app, const std::string &prefix="bb command: ")
Definition cli.cpp:51
void avm_write_verification_key(const std::filesystem::path &output_path)
Writes an avm (incomplete) verification key to a file.
Definition api_avm.cpp:90
void avm_prove(const std::filesystem::path &inputs_path, const std::filesystem::path &output_path)
Writes an avm proof to a file.
Definition api_avm.cpp:31
const char * BB_VERSION
Definition version.hpp:14
void avm_check_circuit(const std::filesystem::path &inputs_path)
Stub - throws runtime error if called.
Definition api_avm.cpp:53
const bool avm_enabled
Definition api_avm.cpp:15
CLI::App * find_deepest_subcommand(CLI::App *app)
Definition cli.cpp:65
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:111
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string scheme
Definition api.hpp:18
void print_aggregate_counts_hierarchical(std::ostream &) const
Definition bb_bench.cpp:548
void serialize_trace_events_json(std::ostream &) const
Definition bb_bench.cpp:406
void print_aggregate_counts(std::ostream &, size_t) const
Definition bb_bench.cpp:303
void serialize_aggregate_data_json(std::ostream &) const
Definition bb_bench.cpp:342
void serialize_aggregate_trace_json(std::ostream &) const
Definition bb_bench.cpp:474
void serialize_json(std::ostream &os) const
void throw_or_abort(std::string const &err)