Closed vezenovm closed 6 months ago
This approach, altough a bit fragile (since modifications in SSA assertions need to account for dynamic assertions, or bugs like this one can happen) works fine for circuits. But it poses some challenges for public functions in aztec:
Instead of using an entirely new approach for dynamic assertion messages, we can follow the same approach that we have for static assertion messages. The Map<OpcodeLocation, String> that the circuit struct holds could be extended to be a Map<OpcodeLocation, AssertionData> The type AssertionData would be:
struct AssertionData {
typing_metadata: PrintableType, // This is what is currently serialized into the bytecode.
payload: AssertionPayload
};
enum AssertionPayload {
Witness(Vec<Expression>),
MemoryArray(BlockId),
BrilligOutput, // The brillig VM returns the data directly in revert data
}
So the example code:
fn option_expect<T, Err>(opt: Option<T>, err: Err) -> T {
assert(opt.is_some(), err);
opt.unwrap_unchecked()
}
fn main(option: Option<u8>) -> pub u8 {
option_expect(option, "option is none")
}
would generate the following SSA:
Initial SSA:
acir(inline) fn main f0 {
b0(v0: u1, v1: u8):
v12 = call f1(v0, v1, [u8 111, u8 2⁴×7, u8 116, u8 105, u8 111, u8 110, u8 2⁵, u8 105, u8 115, u8 2⁵, u8 110, u8 111, u8 110, u8 101])
return v12
}
acir(inline) fn option_expect f1 {
b0(v0: u1, v1: u8, v2: [u8; 14]):
inc_rc v2
v4 = call f2(v0, v1)
inc_rc v2
constrain v4 == u1 1 v2 // Notice here constrain directly holds an SSA value
v10 = call f4(v0, v1)
dec_rc v2
return v10
}
acir(inline) fn is_some f2 {
b0(v0: u1, v1: u8):
return v0
}
acir(inline) fn unwrap_unchecked f4 {
b0(v0: u1, v1: u8):
return v1
}
ACIR generation and Brillig generation need access to the PrintableType metadata that is generated from the HIR for all non-string assert payloads. It could be maintained in parallel or directly embedded in the constrain instruction in SSA, altough the latter sounds worse. This is necessary since we need to build the AssertionData
defined above.
When an opcode fails, the ACVM immediately has enough data to:
We can avoid storing metadata about assertion payload types in the circuit struct if we put it in the ABI.
The circuit struct will have a map of Map<OpcodeLocation, AssertionPayload>
instead of Map<OpcodeLocation, AssertionData>
. The metadata about the type of the error payload will live in the ABI instead. Nargo and other runners are then responsible to properly format the error data.
No more need to cache oracle calls to figure out the payload for a failing assertion.
I think that's unnecessary now anyway now we have revert data in brillig so this is a constant between all proposals. This was just a hack in the short term.
Closing this after https://github.com/AztecProtocol/aztec-packages/pull/5949, we can reopen an issue for the next iteration.
Problem
This TODO was added in https://github.com/noir-lang/noir/pull/4101. This is due to having two different strategies for resolving constrain instruction error messages which can be seen in this enum (https://github.com/noir-lang/noir/blob/afcb385daa572f990178eda51faf10dc20acd2d0/compiler/noirc_evaluator/src/ssa/ir/instruction.rs#L5730). We have two different strategies as sometimes when doing SSA codegen we want to include a constrain with a message, but we can't easily codegen a call to
resolve_assert_message
in the same way we do for user provided assertion messages. Thus, we have thisassert_messages
map for resolving messages specified by the compiler and separate calls toresolve_assert_message
for handling assert messages specified by the user.Happy Case
We should unify the strategy for specifying errors and error types. Ideally we would remove the
assert_messages
map from theCircuit
type. We most likely could instead store errors and their respective types on the ABI rather than on the circuit. Upon circuit failure we can then use the ABI for fetching the appropriate error.Some example pseudocode written by @TomAFrench from when we were originally planning #4101.
Unifying these constrain errors would essentially require full structured errors as part of the ABI. We could then have followup work to enable custom errors inside Noir similar to https://soliditylang.org/blog/2021/04/21/custom-errors/.
Alternatives Considered
No response
Additional Context
No response
Would you like to submit a PR for this Issue?
No
Support Needs
No response