Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: trap with revert data #5732

Merged
merged 15 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 92 additions & 29 deletions avm-transpiler/src/transpile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec<u8> {
lhs,
rhs,
} => {
assert!(is_integral_bit_size(*bit_size), "BinaryIntOp bit size should be integral: {:?}", brillig_instr);
assert!(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we weren't running cargo fmt on this file :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ouch, I was just working on it but I guess if I run cargo ftm as well I'll be ok :D

is_integral_bit_size(*bit_size),
"BinaryIntOp bit size should be integral: {:?}",
brillig_instr
);
let avm_opcode = match op {
BinaryIntOp::Add => AvmOpcode::ADD,
BinaryIntOp::Sub => AvmOpcode::SUB,
Expand Down Expand Up @@ -102,20 +106,27 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec<u8> {
],
});
}
BrilligOpcode::CalldataCopy { destination_address, size, offset } => {
BrilligOpcode::CalldataCopy {
destination_address,
size,
offset,
} => {
avm_instrs.push(AvmInstruction {
opcode: AvmOpcode::CALLDATACOPY,
indirect: Some(ALL_DIRECT),
operands: vec![
AvmOperand::U32 {
value: *offset as u32, // cdOffset (calldata offset)
}, AvmOperand::U32 {
},
AvmOperand::U32 {
value: *size as u32,
}, AvmOperand::U32 {
},
AvmOperand::U32 {
value: destination_address.to_usize() as u32, // dstOffset
}],
..Default::default()
});
},
],
..Default::default()
});
}
BrilligOpcode::Jump { location } => {
let avm_loc = brillig_pcs_to_avm_pcs[*location];
Expand Down Expand Up @@ -146,14 +157,22 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec<u8> {
..Default::default()
});
}
BrilligOpcode::Const { destination, value, bit_size } => {
BrilligOpcode::Const {
destination,
value,
bit_size,
} => {
handle_const(&mut avm_instrs, destination, value, bit_size);
}
BrilligOpcode::Mov {
destination,
source,
} => {
avm_instrs.push(generate_mov_instruction(Some(ALL_DIRECT), source.to_usize() as u32, destination.to_usize() as u32));
avm_instrs.push(generate_mov_instruction(
Some(ALL_DIRECT),
source.to_usize() as u32,
destination.to_usize() as u32,
));
}
BrilligOpcode::ConditionalMov {
source_a,
Expand All @@ -165,10 +184,18 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec<u8> {
opcode: AvmOpcode::CMOV,
indirect: Some(ALL_DIRECT),
operands: vec![
AvmOperand::U32 { value: source_a.to_usize() as u32 },
AvmOperand::U32 { value: source_b.to_usize() as u32 },
AvmOperand::U32 { value: condition.to_usize() as u32 },
AvmOperand::U32 { value: destination.to_usize() as u32 },
AvmOperand::U32 {
value: source_a.to_usize() as u32,
},
AvmOperand::U32 {
value: source_b.to_usize() as u32,
},
AvmOperand::U32 {
value: condition.to_usize() as u32,
},
AvmOperand::U32 {
value: destination.to_usize() as u32,
},
],
..Default::default()
});
Expand All @@ -177,13 +204,21 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec<u8> {
destination,
source_pointer,
} => {
avm_instrs.push(generate_mov_instruction(Some(ZEROTH_OPERAND_INDIRECT), source_pointer.to_usize() as u32, destination.to_usize() as u32));
avm_instrs.push(generate_mov_instruction(
Some(ZEROTH_OPERAND_INDIRECT),
source_pointer.to_usize() as u32,
destination.to_usize() as u32,
));
}
BrilligOpcode::Store {
destination_pointer,
source,
} => {
avm_instrs.push(generate_mov_instruction(Some(FIRST_OPERAND_INDIRECT), source.to_usize() as u32, destination_pointer.to_usize() as u32));
avm_instrs.push(generate_mov_instruction(
Some(FIRST_OPERAND_INDIRECT),
source.to_usize() as u32,
destination_pointer.to_usize() as u32,
));
}
BrilligOpcode::Call { location } => {
let avm_loc = brillig_pcs_to_avm_pcs[*location];
Expand All @@ -199,38 +234,66 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec<u8> {
opcode: AvmOpcode::INTERNALRETURN,
..Default::default()
}),
BrilligOpcode::Stop { return_data_offset, return_data_size } => {
BrilligOpcode::Stop {
return_data_offset,
return_data_size,
} => {
avm_instrs.push(AvmInstruction {
opcode: AvmOpcode::RETURN,
indirect: Some(ALL_DIRECT),
operands: vec![
AvmOperand::U32 { value: *return_data_offset as u32 },
AvmOperand::U32 { value: *return_data_size as u32 },
AvmOperand::U32 {
value: *return_data_offset as u32,
},
AvmOperand::U32 {
value: *return_data_size as u32,
},
],
..Default::default()
});
}
BrilligOpcode::Trap { /*return_data_offset, return_data_size*/ } => {
BrilligOpcode::Trap {
revert_data_offset,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this be direct or indirect? I.e., do I have to read from [revert_data_offset, revert_data_offset+size]?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Direct!

Copy link
Collaborator Author

@sirasistant sirasistant Apr 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ouch, I was just working on it but I guess if I run cargo ftm as well I'll be ok :D

I think rust-analyzer ships with vscode formatting :D

revert_data_size,
} => {
// TODO(https://github.com/noir-lang/noir/issues/3113): Trap should support return data
avm_instrs.push(AvmInstruction {
opcode: AvmOpcode::REVERT,
indirect: Some(ALL_DIRECT),
operands: vec![
//AvmOperand::U32 { value: *return_data_offset as u32},
//AvmOperand::U32 { value: *return_data_size as u32},
AvmOperand::U32 { value: 0 },
AvmOperand::U32 { value: 0 },
AvmOperand::U32 {
value: *revert_data_offset as u32,
},
AvmOperand::U32 {
value: *revert_data_size as u32,
},
],
..Default::default()
});
},
BrilligOpcode::Cast { destination, source, bit_size } => {
avm_instrs.push(generate_cast_instruction(source.to_usize() as u32, destination.to_usize() as u32, tag_from_bit_size(*bit_size)));
}
BrilligOpcode::ForeignCall { function, destinations, inputs, destination_value_types:_, input_value_types:_ } => {
BrilligOpcode::Cast {
destination,
source,
bit_size,
} => {
avm_instrs.push(generate_cast_instruction(
source.to_usize() as u32,
destination.to_usize() as u32,
tag_from_bit_size(*bit_size),
));
}
BrilligOpcode::ForeignCall {
function,
destinations,
inputs,
destination_value_types: _,
input_value_types: _,
} => {
handle_foreign_call(&mut avm_instrs, function, destinations, inputs);
},
BrilligOpcode::BlackBox(operation) => handle_black_box_function(&mut avm_instrs, operation),
}
BrilligOpcode::BlackBox(operation) => {
handle_black_box_function(&mut avm_instrs, operation)
}
_ => panic!(
"Transpiler doesn't know how to process {:?} brillig instruction",
brillig_instr
Expand Down
16 changes: 15 additions & 1 deletion barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,9 @@ struct BrilligOpcode {
};

struct Trap {
uint64_t revert_data_offset;
uint64_t revert_data_size;

friend bool operator==(const Trap&, const Trap&);
std::vector<uint8_t> bincodeSerialize() const;
static Trap bincodeDeserialize(std::vector<uint8_t>);
Expand Down Expand Up @@ -5990,6 +5993,12 @@ namespace Program {

inline bool operator==(const BrilligOpcode::Trap& lhs, const BrilligOpcode::Trap& rhs)
{
if (!(lhs.revert_data_offset == rhs.revert_data_offset)) {
return false;
}
if (!(lhs.revert_data_size == rhs.revert_data_size)) {
return false;
}
return true;
}

Expand All @@ -6016,14 +6025,19 @@ template <>
template <typename Serializer>
void serde::Serializable<Program::BrilligOpcode::Trap>::serialize(const Program::BrilligOpcode::Trap& obj,
Serializer& serializer)
{}
{
serde::Serializable<decltype(obj.revert_data_offset)>::serialize(obj.revert_data_offset, serializer);
serde::Serializable<decltype(obj.revert_data_size)>::serialize(obj.revert_data_size, serializer);
}

template <>
template <typename Deserializer>
Program::BrilligOpcode::Trap serde::Deserializable<Program::BrilligOpcode::Trap>::deserialize(
Deserializer& deserializer)
{
Program::BrilligOpcode::Trap obj;
obj.revert_data_offset = serde::Deserializable<decltype(obj.revert_data_offset)>::deserialize(deserializer);
obj.revert_data_size = serde::Deserializable<decltype(obj.revert_data_size)>::deserialize(deserializer);
return obj;
}

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/developers/debugging/aztecnr-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ This error occurs when your contract is trying to get a secret via the `get_secr
This error might occur when you register an account only as a recipient and not as an account.
To address the error, register the account by calling `server.registerAccount(...)`.

#### `Failed to solve brillig function, reason: explicit trap hit in brillig 'self._is_some`
#### `Failed to solve brillig function 'self._is_some`

You may encounter this error when trying to send a transaction that is using an invalid contract. The contract may compile without errors and you only encounter this when sending the transaction.

Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ library Constants {
uint256 internal constant DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE =
0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631;
uint256 internal constant DEPLOYER_CONTRACT_ADDRESS =
0x1df42e0457430b8d294d920181cc72ae0e3c5f8afd8d62d461bd26773cfdf3c1;
0x0b217585168f564dbf0e5d81b5ab0b76f5dcdb9e713822f488079ea27caa4cbb;
uint256 internal constant L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 17;
uint256 internal constant MAX_NOTE_FIELDS_LENGTH = 20;
uint256 internal constant GET_NOTE_ORACLE_RETURN_LENGTH = 23;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ global REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af8166354
// CONTRACT INSTANCE CONSTANTS
// sha224sum 'struct ContractInstanceDeployed'
global DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631;
global DEPLOYER_CONTRACT_ADDRESS = 0x1df42e0457430b8d294d920181cc72ae0e3c5f8afd8d62d461bd26773cfdf3c1;
global DEPLOYER_CONTRACT_ADDRESS = 0x0b217585168f564dbf0e5d81b5ab0b76f5dcdb9e713822f488079ea27caa4cbb;

// NOIR CONSTANTS - constants used only in yarn-packages/noir-contracts
// Some are defined here because Noir doesn't yet support globals referencing other globals yet.
Expand Down
9 changes: 9 additions & 0 deletions noir/noir-repo/acvm-repo/acir/codegen/acir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,9 @@ namespace Program {
};

struct Trap {
uint64_t revert_data_offset;
uint64_t revert_data_size;

friend bool operator==(const Trap&, const Trap&);
std::vector<uint8_t> bincodeSerialize() const;
static Trap bincodeDeserialize(std::vector<uint8_t>);
Expand Down Expand Up @@ -4952,6 +4955,8 @@ Program::BrilligOpcode::BlackBox serde::Deserializable<Program::BrilligOpcode::B
namespace Program {

inline bool operator==(const BrilligOpcode::Trap &lhs, const BrilligOpcode::Trap &rhs) {
if (!(lhs.revert_data_offset == rhs.revert_data_offset)) { return false; }
if (!(lhs.revert_data_size == rhs.revert_data_size)) { return false; }
return true;
}

Expand All @@ -4975,12 +4980,16 @@ namespace Program {
template <>
template <typename Serializer>
void serde::Serializable<Program::BrilligOpcode::Trap>::serialize(const Program::BrilligOpcode::Trap &obj, Serializer &serializer) {
serde::Serializable<decltype(obj.revert_data_offset)>::serialize(obj.revert_data_offset, serializer);
serde::Serializable<decltype(obj.revert_data_size)>::serialize(obj.revert_data_size, serializer);
}

template <>
template <typename Deserializer>
Program::BrilligOpcode::Trap serde::Deserializable<Program::BrilligOpcode::Trap>::deserialize(Deserializer &deserializer) {
Program::BrilligOpcode::Trap obj;
obj.revert_data_offset = serde::Deserializable<decltype(obj.revert_data_offset)>::deserialize(deserializer);
obj.revert_data_size = serde::Deserializable<decltype(obj.revert_data_size)>::deserialize(deserializer);
return obj;
}

Expand Down
26 changes: 24 additions & 2 deletions noir/noir-repo/acvm-repo/acvm/src/pwg/brillig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use acir::{
FieldElement,
};
use acvm_blackbox_solver::BlackBoxFunctionSolver;
use brillig_vm::{MemoryValue, VMStatus, VM};
use brillig_vm::{FailureReason, MemoryValue, VMStatus, VM};

use crate::{pwg::OpcodeNotSolvable, OpcodeResolutionError};

Expand Down Expand Up @@ -159,7 +159,29 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> {
match vm_status {
VMStatus::Finished { .. } => Ok(BrilligSolverStatus::Finished),
VMStatus::InProgress => Ok(BrilligSolverStatus::InProgress),
VMStatus::Failure { message, call_stack } => {
VMStatus::Failure { reason, call_stack } => {
let message = match reason {
FailureReason::RuntimeError { message } => Some(message),
FailureReason::Trap { revert_data_offset, revert_data_size } => {
// Since noir can only revert with strings currently, we can parse return data as a string
if revert_data_size == 0 {
None
} else {
let memory = self.vm.get_memory();
let bytes = memory
[revert_data_offset..(revert_data_offset + revert_data_size)]
.iter()
.map(|x| {
x.try_into().expect("Assert message character is not a byte")
})
.collect();
Some(
String::from_utf8(bytes)
.expect("Assert message is not valid UTF-8"),
)
}
}
};
Err(OpcodeResolutionError::BrilligFunctionFailed {
message,
call_stack: call_stack
Expand Down
4 changes: 2 additions & 2 deletions noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ pub enum OpcodeResolutionError {
IndexOutOfBounds { opcode_location: ErrorLocation, index: u32, array_size: u32 },
#[error("Failed to solve blackbox function: {0}, reason: {1}")]
BlackBoxFunctionFailed(BlackBoxFunc, String),
#[error("Failed to solve brillig function, reason: {message}")]
BrilligFunctionFailed { message: String, call_stack: Vec<OpcodeLocation> },
#[error("Failed to solve brillig function{}", .message.as_ref().map(|m| format!(", reason: {}", m)).unwrap_or_default())]
BrilligFunctionFailed { message: Option<String>, call_stack: Vec<OpcodeLocation> },
#[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")]
Expand Down
4 changes: 2 additions & 2 deletions noir/noir-repo/acvm-repo/acvm/tests/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ fn unsatisfied_opcode_resolved_brillig() {
let jmp_if_opcode =
BrilligOpcode::JumpIf { condition: MemoryAddress::from(2), location: location_of_stop };

let trap_opcode = BrilligOpcode::Trap;
let trap_opcode = BrilligOpcode::Trap { revert_data_offset: 0, revert_data_size: 0 };
let stop_opcode = BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 };

let brillig_opcode = Opcode::Brillig(Brillig {
Expand Down Expand Up @@ -597,7 +597,7 @@ fn unsatisfied_opcode_resolved_brillig() {
assert_eq!(
solver_status,
ACVMStatus::Failure(OpcodeResolutionError::BrilligFunctionFailed {
message: "explicit trap hit in brillig".to_string(),
message: None,
call_stack: vec![OpcodeLocation::Brillig { acir_index: 0, brillig_index: 3 }]
}),
"The first opcode is not satisfiable, expected an error indicating this"
Expand Down
Loading
Loading