diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index 91dedac8e35..7f6be27e295 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -169,20 +169,26 @@ impl<'b, B: BlackBoxFunctionSolver, F: AcirField> BrilligSolver<'b, F, B> { brillig_index: *brillig_index, }) .collect(); - let payload = match reason { + + Err(match reason { FailureReason::RuntimeError { message } => { - Some(ResolvedAssertionPayload::String(message)) + OpcodeResolutionError::BrilligFunctionFailed { + call_stack, + payload: Some(ResolvedAssertionPayload::String(message)), + } } + FailureReason::Trap { revert_data_offset, revert_data_size } => { - extract_failure_payload_from_memory( - self.vm.get_memory(), - revert_data_offset, - revert_data_size, - ) + OpcodeResolutionError::BrilligFunctionUnsatisfiedConstrain { + call_stack, + payload: extract_failure_payload_from_memory( + self.vm.get_memory(), + revert_data_offset, + revert_data_size, + ), + } } - }; - - Err(OpcodeResolutionError::BrilligFunctionFailed { payload, call_stack }) + }) } VMStatus::ForeignCallWait { function, inputs } => { Ok(BrilligSolverStatus::ForeignCallWait(ForeignCallWaitInfo { function, inputs })) diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs index 4292d72fad5..886845ce948 100644 --- a/acvm-repo/acvm/src/pwg/mod.rs +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -135,6 +135,11 @@ pub enum OpcodeResolutionError { call_stack: Vec, payload: Option>, }, + #[error("Cannot satisfy constraint")] + BrilligFunctionUnsatisfiedConstrain { + call_stack: Vec, + payload: Option>, + }, #[error("Attempted to call `main` with a `Call` opcode")] AcirMainCallAttempted { opcode_location: ErrorLocation }, #[error("{results_size:?} result values were provided for {outputs_size:?} call output witnesses, most likely due to bad ACIR codegen")] @@ -502,7 +507,7 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> ACVM<'a, F, B> { fn map_brillig_error(&self, mut err: OpcodeResolutionError) -> OpcodeResolutionError { match &mut err { - OpcodeResolutionError::BrilligFunctionFailed { call_stack, payload } => { + OpcodeResolutionError::BrilligFunctionUnsatisfiedConstrain { call_stack, payload } => { // Some brillig errors have static strings as payloads, we can resolve them here let last_location = call_stack.last().expect("Call stacks should have at least one item"); diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index e55dbb73ae1..10391235326 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -670,7 +670,7 @@ fn unsatisfied_opcode_resolved_brillig() { let solver_status = acvm.solve(); assert_eq!( solver_status, - ACVMStatus::Failure(OpcodeResolutionError::BrilligFunctionFailed { + ACVMStatus::Failure(OpcodeResolutionError::BrilligFunctionUnsatisfiedConstrain { payload: None, call_stack: vec![OpcodeLocation::Brillig { acir_index: 0, brillig_index: 3 }] }), diff --git a/acvm-repo/acvm_js/src/execute.rs b/acvm-repo/acvm_js/src/execute.rs index 94ef30604e2..44b1e316393 100644 --- a/acvm-repo/acvm_js/src/execute.rs +++ b/acvm-repo/acvm_js/src/execute.rs @@ -200,9 +200,11 @@ impl<'a, B: BlackBoxFunctionSolver> ProgramExecutor<'a, B> { opcode_location: ErrorLocation::Resolved(opcode_location), .. } => Some(vec![*opcode_location]), - OpcodeResolutionError::BrilligFunctionFailed { call_stack, .. } => { - Some(call_stack.clone()) - } + OpcodeResolutionError::BrilligFunctionFailed { call_stack, .. } + | OpcodeResolutionError::BrilligFunctionUnsatisfiedConstrain { + call_stack, + .. + } => Some(call_stack.clone()), _ => None, }; // If the failed opcode has an assertion message, integrate it into the error message for backwards compatibility. @@ -215,6 +217,10 @@ impl<'a, B: BlackBoxFunctionSolver> ProgramExecutor<'a, B> { | OpcodeResolutionError::BrilligFunctionFailed { payload: Some(payload), .. + } + | OpcodeResolutionError::BrilligFunctionUnsatisfiedConstrain { + payload: Some(payload), + .. } => match payload { ResolvedAssertionPayload::Raw(raw_payload) => { ("Assertion failed".to_string(), Some(raw_payload)) diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index d18ec5f0786..a78d6996455 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -471,9 +471,14 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { self.brillig_solver = Some(solver); self.handle_foreign_call(foreign_call) } - Err(err) => DebugCommandResult::Error(NargoError::ExecutionError( - ExecutionError::SolvingError(err, None), - )), + Err(err) => { + // return solver ownership so context has the right opcode location when reporting error + self.brillig_solver = Some(solver); + + DebugCommandResult::Error(NargoError::ExecutionError(ExecutionError::SolvingError( + err, None, + ))) + } } } diff --git a/tooling/nargo/src/errors.rs b/tooling/nargo/src/errors.rs index b2248605cb5..0348ce30b53 100644 --- a/tooling/nargo/src/errors.rs +++ b/tooling/nargo/src/errors.rs @@ -84,6 +84,7 @@ impl NargoError { | OpcodeResolutionError::UnsatisfiedConstrain { .. } | OpcodeResolutionError::AcirMainCallAttempted { .. } | OpcodeResolutionError::BrilligFunctionFailed { .. } + | OpcodeResolutionError::BrilligFunctionUnsatisfiedConstrain { .. } | OpcodeResolutionError::AcirCallOutputsMismatch { .. } => None, OpcodeResolutionError::BlackBoxFunctionFailed(_, reason) => { Some(reason.to_string()) @@ -111,6 +112,10 @@ fn extract_locations_from_error( ExecutionError::SolvingError( OpcodeResolutionError::BrilligFunctionFailed { .. }, acir_call_stack, + ) + | ExecutionError::SolvingError( + OpcodeResolutionError::BrilligFunctionUnsatisfiedConstrain { .. }, + acir_call_stack, ) => acir_call_stack.clone(), ExecutionError::AssertionFailed(_, call_stack) => Some(call_stack.clone()), ExecutionError::SolvingError( diff --git a/tooling/nargo/src/ops/execute.rs b/tooling/nargo/src/ops/execute.rs index c9cc60d03d9..3f2495053c3 100644 --- a/tooling/nargo/src/ops/execute.rs +++ b/tooling/nargo/src/ops/execute.rs @@ -97,7 +97,11 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver, E: ForeignCallExecutor> self.call_stack.push(resolved_location); Some(self.call_stack.clone()) } - OpcodeResolutionError::BrilligFunctionFailed { call_stack, .. } => { + OpcodeResolutionError::BrilligFunctionFailed { call_stack, .. } + | OpcodeResolutionError::BrilligFunctionUnsatisfiedConstrain { + call_stack, + .. + } => { let brillig_call_stack = call_stack.iter().map(|location| ResolvedOpcodeLocation { acir_function_index: self.current_function_index, @@ -111,6 +115,10 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver, E: ForeignCallExecutor> let assertion_payload: Option> = match &error { OpcodeResolutionError::BrilligFunctionFailed { payload, .. } + | OpcodeResolutionError::BrilligFunctionUnsatisfiedConstrain { + payload, + .. + } | OpcodeResolutionError::UnsatisfiedConstrain { payload, .. } => { payload.clone() }