-
Notifications
You must be signed in to change notification settings - Fork 310
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(acir-simulator): advanced debug formatting for noir + acir simul…
…ator (#775) * advanced debug formatting for noir + acir simulator * formatting * comment out debug log in noir * cleanup * Update set.nr * Remove commented out debug in set.nr * Examples and warnings in debug log
- Loading branch information
Showing
5 changed files
with
109 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { ACVMField } from '../acvm/index.js'; | ||
|
||
/** | ||
* Convert an array of ACVMFields to a string. | ||
* | ||
* @param msg - array of ACVMFields where each represents a single ascii character | ||
* @returns string representation of the message | ||
*/ | ||
function acvmFieldMessageToString(msg: ACVMField[]): string { | ||
let msgStr = ''; | ||
for (const msgChar of msg) { | ||
const asciiCode = Number(msgChar); | ||
const asciiChar = String.fromCharCode(asciiCode); | ||
msgStr = msgStr.concat(asciiChar); | ||
} | ||
// cut off string in case of preemptive null termination | ||
const nullCharIndex = msgStr.indexOf('\\0'); | ||
if (nullCharIndex >= 0) { | ||
msgStr = msgStr.substring(0, nullCharIndex); | ||
} | ||
return msgStr.replaceAll('\\n', '\n').replaceAll('\\t', '\t'); | ||
} | ||
|
||
/** | ||
* Format a debug string for Noir filling in `'{0}'` entries with their | ||
* corresponding values from the args array. | ||
* | ||
* @param formatStr - str of form `'this is a string with some entries like {0} and {1}'` | ||
* @param args - array of fields to fill in the string format entries with | ||
* @returns formatted string | ||
*/ | ||
function applyStringFormatting(formatStr: string, args: ACVMField[]): string { | ||
const matches = formatStr.match(/{\d+}/g); | ||
if (matches == null) { | ||
return formatStr; | ||
} | ||
// Get the numeric values within the curly braces, convert them to numbers, | ||
// and find the maximum value. | ||
const maxIndex = Math.max(...matches.map(match => Number(match.slice(1, -1)))); | ||
const argsPadded = args.concat(Array.from({ length: Math.max(0, maxIndex - args.length) }, () => '0xBAD')); | ||
|
||
return formatStr.replace(/{(\d+)}/g, function (match, index) { | ||
return typeof args[index] != 'undefined' ? argsPadded[index] : match; | ||
}); | ||
} | ||
|
||
/** | ||
* Convert an array of ACVMFields from ACVM to a formatted string. | ||
* | ||
* @param fields - either a single field to be printed, or a string to be formatted. | ||
* When it is a string to be formatted: | ||
* The last entry in `fields` is `numArgs` (the number of formatting | ||
* args). The `formatArgs` occupy the end of the `fields` array, | ||
* excluding that last entry (`numArgs`). The message string `msg` | ||
* takes up the remaining entries at the start of the `fields` array. | ||
* | ||
* @returns formatted string | ||
*/ | ||
export function fieldsToFormattedStr(fields: ACVMField[]): string { | ||
if (fields.length === 1) { | ||
return `${fields[0]}`; | ||
} else { | ||
const numArgs = Number(fields[fields.length - 1]); | ||
const msgLen = fields.length - 1 - numArgs; | ||
|
||
const msgFields = fields.slice(0, msgLen); | ||
const formatArgs = fields.slice(msgLen, fields.length - 1); | ||
|
||
const msg = acvmFieldMessageToString(msgFields); | ||
const formattedMsg = applyStringFormatting(msg, formatArgs); | ||
|
||
return formattedMsg; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 28 additions & 5 deletions
33
yarn-project/noir-contracts/src/contracts/noir-aztec3/src/oracle/debug_log.nr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,32 @@ | ||
|
||
// Utility function to console.log data in the acir simulator | ||
// WARNING: sometimes when using debug logs the ACVM errors with: `thrown: "solver opcode resolution error: cannot solve opcode: expression has too many unknowns x155"` | ||
|
||
#[oracle(debugLog)] | ||
fn debug_log_oracle(_msg: Field) -> Field {} | ||
fn debug_log_oracle<T, N>(_msg: T, _num_args: Field) -> Field {} | ||
#[oracle(debugLog)] | ||
fn debug_log_format_oracle<T, N>(_msg: T, _args: [Field; N], _num_args: Field) -> Field {} | ||
#[oracle(debugLog)] | ||
fn debug_log_field_oracle(_field: Field) -> Field {} | ||
|
||
/// NOTE: call this with a str<N> msg of length > 1 | ||
/// Example: | ||
/// `debug_log("blah blah this is a debug string");` | ||
unconstrained fn debug_log<T>(msg: T) { | ||
constrain debug_log_oracle(msg, 0) == 0; | ||
} | ||
|
||
/// NOTE: call this with a str<N> msg of form | ||
/// "some string with {0} and {1} ... {N}" | ||
/// and an array of N field which will be formatted | ||
/// into the string in the simulator. | ||
/// Example: | ||
/// `debug_log_format("get_2(slot:{0}) =>\n\t0:{1}\n\t1:{2}", [storage_slot, notes.0.value, notes.1.value]);` | ||
unconstrained fn debug_log_format<T, N>(msg: T, args: [Field; N]) { | ||
constrain debug_log_format_oracle(msg, args, args.len()) == 0; | ||
} | ||
|
||
unconstrained fn debug_log(msg: Field) -> Field { | ||
debug_log_oracle(msg) | ||
} | ||
/// Example: | ||
/// `debug_log_field(my_field);` | ||
unconstrained fn debug_log_field(field: Field) { | ||
constrain debug_log_field_oracle(field) == 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters