Skip to content

Commit

Permalink
initMainEntrypoint refact and unit tests (keep-starknet-strange#405)
Browse files Browse the repository at this point in the history
* initMainEntrypoint refact and unit tests

* short unwrap of var

* improve style code
  • Loading branch information
StringNick authored Feb 25, 2024
1 parent 4741dcf commit a591101
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 57 deletions.
26 changes: 7 additions & 19 deletions src/vm/core.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1089,7 +1089,7 @@ pub const CairoVM = struct {
return self.segments.loadData(
self.allocator,
ptr,
data,
data.items,
);
}

Expand Down Expand Up @@ -1644,24 +1644,12 @@ test "Core: test step for preset memory alloc hint extensive" {
}

const expected_trace = [_][3][2]u64{
.{
.{ 0, 3 }, .{ 1, 2 }, .{ 1, 2 }
},
.{
.{ 0, 0 }, .{ 1, 4 }, .{ 1, 4 }
},
.{
.{ 0, 2 }, .{ 1, 5 }, .{ 1, 4 }
},
.{
.{ 0, 5 }, .{ 1, 5 }, .{ 1, 2 }
},
.{
.{ 0, 7 }, .{ 1, 6 }, .{ 1, 2 }
},
.{
.{ 0, 8 }, .{ 1, 6 }, .{ 1, 2 }
},
.{ .{ 0, 3 }, .{ 1, 2 }, .{ 1, 2 } },
.{ .{ 0, 0 }, .{ 1, 4 }, .{ 1, 4 } },
.{ .{ 0, 2 }, .{ 1, 5 }, .{ 1, 4 } },
.{ .{ 0, 5 }, .{ 1, 5 }, .{ 1, 2 } },
.{ .{ 0, 7 }, .{ 1, 6 }, .{ 1, 2 } },
.{ .{ 0, 8 }, .{ 1, 6 }, .{ 1, 2 } },
};

try std.testing.expectEqual(expected_trace.len, vm.trace_context.state.enabled.entries.items.len);
Expand Down
4 changes: 4 additions & 0 deletions src/vm/error.zig
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ pub const CairoRunnerError = error{

/// Represents different error conditions that occur in the built-in runners.
pub const RunnerError = error{
//Initialization failure: No execution base
NoExecBase,
// Initialization failure: No program base
NoProgBase,
/// Errors associated with computing the address of a stop pointer of RangeCheckBuiltinRunner
/// Raised when underflow occurs (i.e., subtracting 1 from 0),
/// or when it fails to get a value for the computed address.
Expand Down
18 changes: 9 additions & 9 deletions src/vm/memory/segments.zig
Original file line number Diff line number Diff line change
Expand Up @@ -295,18 +295,18 @@ pub const MemorySegmentManager = struct {
self: *Self,
allocator: Allocator,
ptr: Relocatable,
data: *std.ArrayList(MaybeRelocatable),
data: []const MaybeRelocatable,
) !Relocatable {
var idx = data.items.len;
var idx = data.len;
while (idx > 0) : (idx -= 1) {
const i = idx - 1;
try self.memory.set(
allocator,
try ptr.addUint(@intCast(i)),
data.items[i],
data[i],
);
}
return ptr.addUint(data.items.len) catch MemoryError.Math;
return ptr.addUint(data.len) catch MemoryError.Math;
}

/// Records details for a specified segment, facilitating relocation:
Expand Down Expand Up @@ -411,7 +411,7 @@ pub const MemorySegmentManager = struct {
try self.loadData(
self.allocator,
ptr,
arg,
arg.items,
),
),
std.ArrayList(Relocatable) => {
Expand All @@ -427,7 +427,7 @@ pub const MemorySegmentManager = struct {
try self.loadData(
self.allocator,
ptr,
&tmp,
tmp.items,
),
);
},
Expand Down Expand Up @@ -1099,7 +1099,7 @@ test "MemorySegmentManager: loadData with empty data" {
try memory_segment_manager.loadData(
allocator,
Relocatable.init(0, 3),
&data,
data.items,
),
);
}
Expand All @@ -1119,7 +1119,7 @@ test "MemorySegmentManager: loadData with one element" {
const actual = try memory_segment_manager.loadData(
allocator,
Relocatable.init(0, 0),
&data,
data.items,
);
defer memory_segment_manager.memory.deinitData(std.testing.allocator);

Expand Down Expand Up @@ -1147,7 +1147,7 @@ test "MemorySegmentManager: loadData with three elements" {
const actual = try memory_segment_manager.loadData(
allocator,
Relocatable.init(0, 0),
&data,
data.items,
);
defer memory_segment_manager.memory.deinitData(std.testing.allocator);

Expand Down
126 changes: 97 additions & 29 deletions src/vm/runners/cairo_runner.zig
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,15 @@ pub const CairoRunner = struct {
program: Program,
allocator: Allocator,
vm: CairoVM,
program_base: Relocatable = undefined,
execution_base: Relocatable = undefined,
program_base: ?Relocatable = null,
execution_base: ?Relocatable = null,
initial_pc: ?Relocatable = null,
initial_ap: ?Relocatable = null,
initial_fp: ?Relocatable = null,
final_pc: *Relocatable = undefined,
instructions: std.ArrayList(MaybeRelocatable),
// function_call_stack: std.ArrayList(MaybeRelocatable),
entrypoint_name: []const u8 = "main",
entrypoint: ?usize,
layout: CairoLayout,
runner_mode: RunnerMode,
run_ended: bool = false,
Expand Down Expand Up @@ -161,6 +161,7 @@ pub const CairoRunner = struct {
.runner_mode = if (proof_mode) .proof_mode_canonical else .execution_mode,
.relocated_memory = ArrayList(?Felt252).init(allocator),
.execution_scopes = try ExecutionScopes.init(allocator),
.entrypoint = program.shared_program_data.main,
};
}

Expand Down Expand Up @@ -217,20 +218,25 @@ pub const CairoRunner = struct {
/// # Arguments
/// - `entrypoint:` The address, relative to the program segment, where execution begins.
pub fn initState(self: *Self, entrypoint: usize, stack: *std.ArrayList(MaybeRelocatable)) !void {
self.initial_pc = self.program_base;
self.initial_pc.?.addUintInPlace(entrypoint);
if (self.program_base) |prog_base| {
self.initial_pc = try prog_base.addUint(entrypoint);

_ = try self.vm.segments.loadData(
self.allocator,
self.program_base,
&self.instructions,
);
_ = try self.vm.segments.loadData(
self.allocator,
prog_base,
self.program.shared_program_data.data.items,
);

_ = try self.vm.segments.loadData(
self.allocator,
self.execution_base,
stack,
);
for (0..self.program.shared_program_data.data.items.len) |i|
self.vm.segments.memory.markAsAccessed(try prog_base.addUint(i));
}
if (self.execution_base) |exec_base| {
_ = try self.vm.segments.loadData(
self.allocator,
exec_base,
stack.items,
);
} else return RunnerError.NoProgBase;
}

pub fn initFunctionEntrypoint(self: *Self, entrypoint: usize, return_fp: Relocatable, stack: *std.ArrayList(MaybeRelocatable)) !Relocatable {
Expand Down Expand Up @@ -262,9 +268,8 @@ pub const CairoRunner = struct {
for (self.vm.builtin_runners.items) |*builtin_runner| {
const builtin_stack = try builtin_runner.initialStack(self.allocator);
defer builtin_stack.deinit();
for (builtin_stack.items) |item| {
try stack.append(item);
}

try stack.appendSlice(builtin_stack.items);
}

if (self.isProofMode()) {
Expand All @@ -274,13 +279,16 @@ pub const CairoRunner = struct {
var stack_prefix = try std.ArrayList(MaybeRelocatable).initCapacity(self.allocator, 2 + stack.items.len);
defer stack_prefix.deinit();

try stack_prefix.append(MaybeRelocatable.fromRelocatable(try self.execution_base.addUint(target_offset)));
try stack_prefix.append(MaybeRelocatable.fromRelocatable(try (self.execution_base orelse return RunnerError.NoExecBase).addUint(target_offset)));
try stack_prefix.append(MaybeRelocatable.fromFelt(Felt252.zero()));
try stack_prefix.appendSlice(stack.items);

var execution_public_memory = try std.ArrayList(usize).initCapacity(self.allocator, stack_prefix.items.len);

for (0..stack_prefix.items.len) |v| {
try execution_public_memory.append(v);
}

self.execution_public_memory = execution_public_memory;

try self.initState(try (self.program.shared_program_data.start orelse
Expand All @@ -297,23 +305,16 @@ pub const CairoRunner = struct {
RunnerError.NoProgramStart), &stack);
}

self.initial_fp = try self.execution_base.addUint(target_offset);
self.initial_fp = try (self.execution_base orelse return RunnerError.NoExecBase).addUint(target_offset);
self.initial_ap = self.initial_fp;

return self.program_base.addUint(try (self.program.shared_program_data.end orelse
return (self.program_base orelse return RunnerError.NoExecBase).addUint(try (self.program.shared_program_data.end orelse
RunnerError.NoProgramEnd));
}

const return_fp = try self.vm.segments.addSegment();
// Buffer for concatenation
var buffer: [100]u8 = undefined;

// Concatenate strings
const full_entrypoint_name = try std.fmt.bufPrint(&buffer, "__main__.{s}", .{self.entrypoint_name});

if (self.program.shared_program_data.identifiers.get(full_entrypoint_name)) |identifier|
if (identifier.pc) |pc|
return self.initFunctionEntrypoint(pc, return_fp, &stack);
if (self.entrypoint) |main| return self.initFunctionEntrypoint(main, return_fp, &stack);

return RunnerError.MissingMain;
}
Expand Down Expand Up @@ -622,6 +623,73 @@ test "CairoRunner: initMainEntrypoint no main" {
} else |_| {}
}

test "CairoRunner: initMainEntrypoint" {
var program = try Program.initDefault(std.testing.allocator, true);

program.shared_program_data.main = 1;

var cairo_runner = try CairoRunner.init(
std.testing.allocator,
program,
"all_cairo",
ArrayList(MaybeRelocatable).init(std.testing.allocator),
try CairoVM.init(
std.testing.allocator,
.{},
),
false,
);

defer cairo_runner.deinit(std.testing.allocator);
// why this deinit is separated?
defer cairo_runner.vm.segments.memory.deinitData(std.testing.allocator);

cairo_runner.program_base = Relocatable.init(0, 0);
cairo_runner.execution_base = Relocatable.init(0, 0);

// Add an OutputBuiltinRunner to the CairoRunner without setting the stop pointer.
// try cairo_runner.vm.builtin_runners.append(.{ .Output = OutputBuiltinRunner.initDefault(std.testing.allocator) });
try expectEqual(
Relocatable.init(1, 0),
cairo_runner.initMainEntrypoint(),
);
}

test "CairoRunner: initMainEntrypoint proof_mode empty program" {
var program = try Program.initDefault(std.testing.allocator, true);

program.shared_program_data.main = 8;
program.shared_program_data.start = 0;
program.shared_program_data.end = 0;

var runner = try CairoRunner.init(
std.testing.allocator,
program,
"all_cairo",
ArrayList(MaybeRelocatable).init(std.testing.allocator),
try CairoVM.init(
std.testing.allocator,
.{},
),
true,
);

runner.runner_mode = .proof_mode_canonical;

defer runner.deinit(std.testing.allocator);
// why this deinit is separated?
defer runner.vm.segments.memory.deinitData(std.testing.allocator);

try runner.initSegments(null);

try expectEqual(Relocatable.init(1, 0), runner.execution_base);
try expectEqual(Relocatable.init(0, 0), runner.program_base);
try expectEqual(Relocatable.init(0, 0), runner.initMainEntrypoint());
try expectEqual(Relocatable.init(1, 2), runner.initial_ap);
try expectEqual(runner.initial_fp, runner.initial_ap);
try expectEqual([2]usize{ 0, 1 }, runner.execution_public_memory.?.items[0..2].*);
}

test "CairoRunner: initVM should initialize the VM properly with no builtins" {
// Initialize a CairoRunner with an empty program, "plain" layout, and empty instructions.
var cairo_runner = try CairoRunner.init(
Expand Down

0 comments on commit a591101

Please sign in to comment.