Skip to content

Commit

Permalink
add opcodeAssertions in runInstruction and small refac (keep-star…
Browse files Browse the repository at this point in the history
…knet-strange#357)

add opcodeAssertions in runInstruction and small refac
  • Loading branch information
tcoratger authored Feb 1, 2024
1 parent d0bffb7 commit c55a416
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 50 deletions.
7 changes: 4 additions & 3 deletions src/vm/cairo_run.zig
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ pub fn writeEncodedTrace(relocated_trace: []const RelocatedTraceEntry, dest: *st
/// - `dest`: The destination file that the memory is to be written.
pub fn writeEncodedMemory(relocated_memory: []?Felt252, dest: *std.fs.File.Writer) !void {
for (relocated_memory, 0..) |memory_cell, i| {
if (memory_cell == null) continue;
try dest.writeInt(u64, i, .little);
try dest.writeInt(u256, memory_cell.?.toInteger(), .little);
if (memory_cell) |cell| {
try dest.writeInt(u64, i, .little);
try dest.writeInt(u256, cell.toInteger(), .little);
}
}
}

Expand Down
56 changes: 56 additions & 0 deletions src/vm/core.zig
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,35 @@ pub const CairoVM = struct {
/// This function may return an error of type `CairoVMError.InstructionEncodingError` if there
/// is an issue with encoding or decoding the instruction.
///
/// # Tracing
///
/// If tracing is not disabled, this function logs the current state, including program counter (`pc`),
/// argument pointer (`ap`), and frame pointer (`fp`) to the trace context before executing the instruction.
///
/// # Operations
///
/// ## Memory Operations
///
/// - Computes operands for the instruction using the `computeOperands` function.
/// - Inserts deduced operands into memory using the `insertDeducedOperands` function.
/// - Performs opcode-specific assertions on operands using the `opcodeAssertions` function.
///
/// ## Register Updates
///
/// - Updates registers based on the instruction and operands using the `updateRegisters` function.
///
/// ## Relocation Limits
///
/// - Calculates and updates relocation limits based on the instruction's offset fields.
///
/// ## Memory Access Marking
///
/// - Marks memory accesses for the instruction's destination and operands.
///
/// ## Step Counter
///
/// - Increments the current step counter after executing the instruction.
///
/// # Safety
///
/// This function assumes proper initialization of the CairoVM instance and must be called in
Expand All @@ -353,6 +382,9 @@ pub const CairoVM = struct {
// Insert deduced operands into memory.
try self.insertDeducedOperands(allocator, operands_result);

// Perform opcode-specific assertions on operands using the `opcodeAssertions` function.
try self.opcodeAssertions(instruction, operands_result);

// Update registers based on the instruction and operands.
try self.updateRegisters(
instruction,
Expand Down Expand Up @@ -1136,11 +1168,35 @@ pub const CairoVM = struct {
}

/// Performs opcode-specific assertions on the operands of an instruction.
///
/// # Arguments
///
/// - `self`: A pointer to the CairoVM instance.
/// - `instruction`: A pointer to the instruction being asserted.
/// - `operands`: The result of the operands computation.
///
/// # Errors
///
/// - Returns an error if an assertion fails.
///
/// # Opcode Assertions
///
/// This function performs opcode-specific assertions based on the opcode of the given instruction.
///
/// - For the `AssertEq` opcode, it asserts that the result and destination operands are equal.
/// Returns `CairoVMError.DiffAssertValues` if the assertion fails or `CairoVMError.UnconstrainedResAssertEq`
/// if the result operand is unconstrained.
///
/// - For the `Call` opcode, it asserts that operand 0 is the return program counter (PC) and that the destination
/// operand is the frame pointer (FP). Returns `CairoVMError.CantWriteReturnPc` if the assertion on operand 0 fails
/// or `CairoVMError.CantWriteReturnFp` if the assertion on the destination operand fails.
///
/// - No assertions are performed for other opcodes.
///
/// # Safety
///
/// This function assumes proper initialization of the CairoVM instance and must be called in
/// a controlled environment to ensure the correct execution of instructions and memory operations.
pub fn opcodeAssertions(self: *Self, instruction: *const Instruction, operands: OperandsResult) !void {
// Switch on the opcode to perform the appropriate assertion.
switch (instruction.opcode) {
Expand Down
17 changes: 8 additions & 9 deletions src/vm/memory/memory.zig
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,8 @@ pub const AddressSet = struct {
/// An error if the addition fails.
pub fn addAddresses(self: *Self, addresses: []const Relocatable) !void {
for (addresses) |address| {
if (address.segment_index < 0) {
continue;
}
try self.set.put(address, true);
if (address.segment_index >= 0)
try self.set.put(address, true);
}
}

Expand Down Expand Up @@ -748,6 +746,7 @@ pub const Memory = struct {
size: usize,
) !std.ArrayList(?MaybeRelocatable) {
var values = std.ArrayList(?MaybeRelocatable).init(allocator);
errdefer values.deinit();
for (0..size) |i| {
try values.append(self.get(try address.addUint(i)));
}
Expand Down Expand Up @@ -804,7 +803,7 @@ pub const Memory = struct {
);
errdefer values.deinit();
for (0..size) |i| {
if (self.get(try address.addUint(@intCast(i)))) |elem| {
if (self.get(try address.addUint(i))) |elem| {
try values.append(elem);
} else {
return MemoryError.GetRangeMemoryGap;
Expand Down Expand Up @@ -1060,25 +1059,25 @@ pub const Memory = struct {
try self.set(
allocator,
Relocatable.init(row[0][0], row[0][1]),
.{ .felt = Felt252.fromInt(u256, row[1][0]) },
MaybeRelocatable.fromInt(u256, row[1][0]),
);
} else {
switch (@typeInfo(@TypeOf(row[1][0]))) {
.Pointer => {
try self.set(
allocator,
Relocatable.init(row[0][0], row[0][1]),
.{ .relocatable = Relocatable.init(
MaybeRelocatable.fromSegment(
try std.fmt.parseUnsigned(i64, row[1][0], 10),
row[1][1],
) },
),
);
},
else => {
try self.set(
allocator,
Relocatable.init(row[0][0], row[0][1]),
.{ .relocatable = Relocatable.init(row[1][0], row[1][1]) },
MaybeRelocatable.fromSegment(row[1][0], row[1][1]),
);
},
}
Expand Down
60 changes: 22 additions & 38 deletions src/vm/memory/relocatable.zig
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,7 @@ pub const Relocatable = struct {
/// - other: The other Relocatable to compare to.
/// # Returns
/// `true` if they are equal, `false` otherwise.
pub fn eq(
self: Self,
other: Self,
) bool {
pub fn eq(self: Self, other: Self) bool {
return self.segment_index == other.segment_index and self.offset == other.offset;
}

Expand All @@ -60,47 +57,40 @@ pub const Relocatable = struct {
/// - other: The other Relocatable to compare to.
/// # Returns
/// `true` if self is less than other, `false` otherwise.
pub fn lt(
self: Self,
other: Self,
) bool {
return self.segment_index < other.segment_index or (self.segment_index == other.segment_index and self.offset < other.offset);
pub fn lt(self: Self, other: Self) bool {
return self.segment_index < other.segment_index or
(self.segment_index == other.segment_index and
self.offset < other.offset);
}

/// Determines if this Relocatable is less than or equal to another.
/// # Arguments
/// - other: The other Relocatable to compare to.
/// # Returns
/// `true` if self is less than or equal to other, `false` otherwise.
pub fn le(
self: Self,
other: Self,
) bool {
return self.segment_index < other.segment_index or (self.segment_index == other.segment_index and self.offset <= other.offset);
pub fn le(self: Self, other: Self) bool {
return self.segment_index < other.segment_index or
(self.segment_index == other.segment_index and self.offset <= other.offset);
}

/// Determines if this Relocatable is greater than another.
/// # Arguments
/// - other: The other Relocatable to compare to.
/// # Returns
/// `true` if self is greater than other, `false` otherwise.
pub fn gt(
self: Self,
other: Self,
) bool {
return self.segment_index > other.segment_index or (self.segment_index == other.segment_index and self.offset > other.offset);
pub fn gt(self: Self, other: Self) bool {
return self.segment_index > other.segment_index or
(self.segment_index == other.segment_index and self.offset > other.offset);
}

/// Determines if this Relocatable is greater than or equal to another.
/// # Arguments
/// - other: The other Relocatable to compare to.
/// # Returns
/// `true` if self is greater than or equal to other, `false` otherwise.
pub fn ge(
self: Self,
other: Self,
) bool {
return self.segment_index > other.segment_index or (self.segment_index == other.segment_index and self.offset >= other.offset);
pub fn ge(self: Self, other: Self) bool {
return self.segment_index > other.segment_index or
(self.segment_index == other.segment_index and self.offset >= other.offset);
}

/// Compares this Relocatable with another.
Expand Down Expand Up @@ -150,10 +140,7 @@ pub const Relocatable = struct {
/// - other: The u64 to substract.
/// # Returns
/// A new Relocatable.
pub fn subUint(
self: Self,
other: u64,
) MathError!Self {
pub fn subUint(self: Self, other: u64) MathError!Self {
if (self.offset < other) return MathError.RelocatableSubUsizeNegOffset;

return .{
Expand All @@ -167,10 +154,7 @@ pub const Relocatable = struct {
/// - other: The u64 to add.
/// # Returns
/// A new Relocatable.
pub fn addUint(
self: Self,
other: u64,
) !Self {
pub fn addUint(self: Self, other: u64) !Self {
const offset = @addWithOverflow(self.offset, other);
if (offset[1] != 0) return MathError.RelocatableAdditionOffsetExceeded;
return .{
Expand All @@ -193,11 +177,11 @@ pub const Relocatable = struct {
/// - other: The i64 to add.
/// # Returns
/// A new Relocatable.
pub fn addInt(
self: Self,
other: i64,
) !Self {
return if (other < 0) self.subUint(@intCast(-other)) else self.addUint(@intCast(other));
pub fn addInt(self: Self, other: i64) !Self {
return if (other < 0)
self.subUint(@intCast(-other))
else
self.addUint(@intCast(other));
}

/// Adds a Felt252 value to this Relocatable.
Expand Down Expand Up @@ -253,7 +237,7 @@ pub const Relocatable = struct {
if (relocation_table.len <= self.segment_index) {
return MemoryError.Relocation;
}
return @intCast(relocation_table[@intCast(self.segment_index)] + self.offset);
return relocation_table[@intCast(self.segment_index)] + self.offset;
}
return MemoryError.TemporarySegmentInRelocation;
}
Expand Down

0 comments on commit c55a416

Please sign in to comment.