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

Implement proof_mode functionalities #682

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open

Implement proof_mode functionalities #682

wants to merge 40 commits into from

Conversation

MaksymMalicki
Copy link
Contributor

No description provided.

MaksymMalicki and others added 25 commits November 15, 2024 16:16
* Add parsing logic for input user args

* Add flags for available gas, input user args, writing args to memory

* Fix unit tests for user arguments parsing

* Lint the PR

* Add user args to hint context

* Refactor the code

* Fix unconditional append of ExternalWriteArgsToMemory, bug fixes in integration tests

* Add fixes of the call size calculation and include ExternalWriteArgsToMemory hint when gas present

* Add layouts for integration tests

* Add error handling

* Fixes in entry code generation

* Address changes mentioned in a discussion

* Add comment regarding writing to memory in a hint for the future reference in the integration tests with args

* Changes in calculations of the initial PC offset, CALL opcode offset incremented by mainFuncOffset, writing user args to the AP in the hint

* Turn back VM config to private field

* Add error handling on assign of `userArgs` to the initial scope

* Lint project

* Bump go version from 1.20 -> 1.21 (#678)

* Bump go version from 1.20 -> 1.21

* Update golangci-lint

* Simplify the Makefile

* Correction in the makefile
@MaksymMalicki MaksymMalicki marked this pull request as draft January 17, 2025 11:43
Base automatically changed from inputs to main January 22, 2025 16:04
@MaksymMalicki MaksymMalicki marked this pull request as ready for review January 29, 2025 18:32
Comment on lines +132 to +136
"./cairo_1_programs/",
"./cairo_1_programs/dict_non_squashed",
"./cairo_1_programs/with_input",
"./cairo_1_programs/serialized_output",
"./cairo_1_programs/serialized_output/with_input",
Copy link
Contributor

Choose a reason for hiding this comment

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

As discussed in the daily today, it would be nice to refactor the code below to run the tests recursively in the same folder, instead of having to pass all the subdirectories as roots as well. This could be solved in a separate PR, as this already has a lot of things. Let's just link the issue to this comment

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, I cannot comment on lines that haven't been changed, but looking into the refactor I noticed in line 195 (before this changes) the last argument should be false, as discussed today as well

@@ -191,6 +191,8 @@ func (segment *Segment) String() string {
// Represents the whole VM memory divided into segments
type Memory struct {
Segments []*Segment
// TemporarySegments is a map of temporary segments, key is the segment index, value is the segment
TemporarySegments map[uint64]*Segment
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure why we need to use a map here. As far as I see, the only place where this is updated is in AllocateEmptyTemporarySegment function in line:

memory.TemporarySegments[uint64(len(memory.TemporarySegments))] = EmptySegment()

This looks like you could just use an array and append an EmptySegment instead.
Am I missing something?

@@ -227,6 +229,15 @@ func (memory *Memory) AllocateEmptySegment() MemoryAddress {
}
}

// Allocates an empty temporary segment and returns its index
func (memory *Memory) AllocateEmptyTemporarySegment() MemoryAddress {
memory.TemporarySegments[uint64(len(memory.TemporarySegments))] = EmptySegment()
Copy link
Contributor

Choose a reason for hiding this comment

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

This is what I commented above regarding TemporarySegments structure

func (memory *Memory) AllocateEmptyTemporarySegment() MemoryAddress {
memory.TemporarySegments[uint64(len(memory.TemporarySegments))] = EmptySegment()
return MemoryAddress{
SegmentIndex: uint64(len(memory.TemporarySegments)),
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this the correct SegmentIndex? After the previous line the length of the map increased by 1, so the index you are returning here is different from the one you used as key

@@ -38,19 +38,27 @@ func (d *Dictionary) InitNumber() uint64 {
type DictionaryManager struct {
// a map that links a segment index to a dictionary
dictionaries map[uint64]Dictionary
// useTemporarySegments is a flag that indicates if the dictionaries should located in temporary segments, and later relocated to memory segments
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing word in comment, it should be: "the dictionaries should be located in temporary segments"

Comment on lines +251 to +262
case ExecutionModeZero, ExecutionModeCairo:
returnFp := memory.AllocateEmptySegment()
mvReturnFp := mem.MemoryValueFromMemoryAddress(&returnFp)
if runner.runnerMode == ProofModeCairo {
// In Cairo mainPCOffset is equal to the offset of program segment base
return runner.initializeEntrypoint(uint64(0), nil, &mvReturnFp, memory, stack, 2)
} else if runner.runnerMode == ExecutionModeCairo {
return runner.initializeEntrypoint(uint64(0), nil, &mvReturnFp, memory, stack, 0)
if runner.runnerMode == ExecutionModeCairo {
return runner.initializeEntrypoint(uint64(0), nil, &mvReturnFp, memory, stack)
} else {
mainPCOffset, ok := runner.program.Entrypoints["main"]
if !ok {
return mem.UnknownAddress, errors.New("can't find an entrypoint for main")
}
return runner.initializeEntrypoint(mainPCOffset, nil, &mvReturnFp, memory, stack, 0)
return runner.initializeEntrypoint(mainPCOffset, nil, &mvReturnFp, memory, stack)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps it's better to separate these two, at the end you have the logic in different branches already. I think it will be more readable this way. Should we re-add the comment regarding mainPCOffset in Cairo?

Comment on lines +731 to +739
for _, builtin := range function.Builtins {
adjustedRetOffset += 1
_, ok := builtinsOffsetsMap[builtin]
if ok {
builtinsOffsetsMap[builtin] = adjustedRetOffset
} else {
continue
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
for _, builtin := range function.Builtins {
adjustedRetOffset += 1
_, ok := builtinsOffsetsMap[builtin]
if ok {
builtinsOffsetsMap[builtin] = adjustedRetOffset
} else {
continue
}
}
for _, builtin := range function.Builtins {
adjustedRetOffset += 1
if _, ok := builtinsOffsetsMap[builtin]; ok {
builtinsOffsetsMap[builtin] = adjustedRetOffset
}
}

ctx.AddInlineCASM(fmt.Sprintf("call rel %d; ret;", int(totalSize)))
return ctx.instructions, hints, nil
ctx.instructions[callRelArgLocation] = new(fp.Element).SetUint64(uint64(ctx.currentCodeOffset) + codeOffsetBeforeCallRel)
return ctx.instructions, hints, ctx.currentCodeOffset, programBuiltins, gotGasBuiltin, gotSegmentArena, nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this function returning an error ever?

Comment on lines +891 to +903
// Check if return type is either:
// 1. PanicResult with inner type of Array<felt252> with size 2
// 2. Array<felt252> with size 2
isPanicResultFeltArray := false
if strings.Contains(mainFunc.ReturnArgs[0].DebugName, "core::panics::PanicResult::") {
isPanicResultFeltArray = strings.Contains(mainFunc.ReturnArgs[0].PanicInnerType.DebugName, "Array<felt252>")
}
isFeltArray := mainFunc.ReturnArgs[0].DebugName == "Array<felt252>" &&
mainFunc.ReturnArgs[0].Size == 2

if !isPanicResultFeltArray && !isFeltArray {
return fmt.Errorf("main function return argument should be either PanicResult of size 3 or Felt Array of size 2")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think there is a mismatch between the comment point 1 for PanicResult and the error at the end regarding the size: in the first case it says 2 but in the error it says 3, what's the correct one?

// 2. Array<felt252> with size 2
isPanicResultFeltArray := false
if strings.Contains(mainFunc.ReturnArgs[0].DebugName, "core::panics::PanicResult::") {
isPanicResultFeltArray = strings.Contains(mainFunc.ReturnArgs[0].PanicInnerType.DebugName, "Array<felt252>")
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't you have to check for the size here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants