bug: erroneous hint reference
Describe the bug A clear and concise description of what the bug is.
In this code:
// Prepare arguments
// MARK: args assignment
[ap] = range_check_ptr, ap++;
[ap] = bitwise_ptr, ap++;
[ap] = keccak_ptr, ap++;
[ap] = poseidon_ptr, ap++;
[ap] = range_check96_ptr, ap++;
[ap] = add_mod_ptr, ap++;
[ap] = mul_mod_ptr, ap++;
[ap] = evm.value, ap++;
call abs precompile_fn;
let range_check_ptr = [ap - 9];
let bitwise_ptr = cast([ap - 8], BitwiseBuiltin*);
let keccak_ptr = cast([ap - 7], KeccakBuiltin*);
let poseidon_ptr = cast([ap - 6], PoseidonBuiltin*);
let range_check96_ptr = cast([ap - 5], felt*);
let add_mod_ptr = cast([ap - 4], ModBuiltin*);
let mul_mod_ptr = cast([ap - 3], ModBuiltin*);
let evm = Evm(cast([ap - 2], EvmStruct*));
let err = cast([ap - 1], EthereumException*);
%{
precompile_address_bytes = ids.precompile_address.to_bytes(20, "little")
print(f"[CAIRO] PrecompileEnd: {precompile_address_bytes}")
%}
When executing the hint, we load up all the ids_data into an ids dict, based on the HintReference for each object in scope. However, for the Evm object, we get:
reference: HintReference { offset1: Value(0), offset2: Value(0), inner_dereference: false, outer_dereference: false, ap_tracking_data: None, cairo_type: Some("ethereum.cancun.vm.evm_impl.Evm") }
I'm unable to get any relevant information regarding evm here - I cannot get the address of the variable as a relocatable (as it's a let reference), and i'm unable to get it's ap offset, because offset1 and offset2 are zero)
Expected behavior I should have proper offsets in the HintReference data
What version/commit are you on? For example: 5c56712768586e979166296bb82176892b5a3113
Additional context I can't provide an easy repro. But I can check periodically how things go.
Hi @enitrat , at first glance, it looks like let range_check_ptr = [ap - 9]; it trying to access the ap with an out of bounds offset. Does precompile_fn function increment the op too?
Hi, yes ap gets increased in the function call. I will try to provide a small reproducible example when I have some time
Hi @FrancoGiachetta here's a MRE:
%builtins output pedersen range_check ecdsa bitwise ec_op keccak poseidon range_check96 add_mod mul_mod
from starkware.cairo.common.cairo_builtins import (
BitwiseBuiltin,
KeccakBuiltin,
PoseidonBuiltin,
ModBuiltin,
HashBuiltin,
SignatureBuiltin,
EcOpBuiltin,
)
from starkware.cairo.common.registers import get_label_location
struct MyStruct {
value: MyStructPointer*,
}
struct MyStructPointer {
a: felt,
b: felt,
}
func foo(my_struct: MyStruct) -> MyStruct {
tempvar my_new_struct = MyStruct(new MyStructPointer(my_struct.value.a+1, my_struct.value.b+1));
return my_new_struct;
}
func main{
output_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
ecdsa_ptr: SignatureBuiltin*,
bitwise_ptr: BitwiseBuiltin*,
ec_op_ptr: EcOpBuiltin*,
keccak_ptr: KeccakBuiltin*,
poseidon_ptr: PoseidonBuiltin*,
range_check96_ptr: felt*,
add_mod_ptr: ModBuiltin*,
mul_mod_ptr: ModBuiltin*,
}() {
let (foo_label) = get_label_location(foo);
tempvar my_struct = MyStruct(new MyStructPointer(1,2));
call abs foo_label;
let my_struct = MyStruct(cast([ap-1], MyStructPointer*));
%{breakpoint()%} // This could be any hint, what's important for us is to just see what's in the HintReference object
return();
}
Here's what the HintReference object looks like:
Hint References:
range_check_ptr => HintReference { offset1: Reference(FP, -11, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: None, cairo_type: Some("felt") }
output_ptr => HintReference { offset1: Reference(FP, -13, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: None, cairo_type: Some("felt*") }
__temp4 => HintReference { offset1: Reference(AP, -1, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: Some(ApTracking { group: 6, offset: 15 }), cairo_type: Some("felt") }
ec_op_ptr => HintReference { offset1: Reference(FP, -8, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: None, cairo_type: Some("starkware.cairo.common.cairo_builtins.EcOpBuiltin*") }
bitwise_ptr => HintReference { offset1: Reference(FP, -9, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: None, cairo_type: Some("starkware.cairo.common.cairo_builtins.BitwiseBuiltin*") }
ecdsa_ptr => HintReference { offset1: Reference(FP, -10, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: None, cairo_type: Some("starkware.cairo.common.cairo_builtins.SignatureBuiltin*") }
pedersen_ptr => HintReference { offset1: Reference(FP, -12, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: None, cairo_type: Some("starkware.cairo.common.cairo_builtins.HashBuiltin*") }
poseidon_ptr => HintReference { offset1: Reference(FP, -6, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: None, cairo_type: Some("starkware.cairo.common.cairo_builtins.PoseidonBuiltin*") }
my_struct => HintReference { offset1: Value(0), offset2: Value(0), inner_dereference: false, outer_dereference: false, ap_tracking_data: None, cairo_type: Some("__main__.MyStruct") }
add_mod_ptr => HintReference { offset1: Reference(FP, -4, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: None, cairo_type: Some("starkware.cairo.common.cairo_builtins.ModBuiltin*") }
foo_label => HintReference { offset1: Reference(AP, -1, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: Some(ApTracking { group: 6, offset: 7 }), cairo_type: Some("felt*") }
range_check96_ptr => HintReference { offset1: Reference(FP, -5, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: None, cairo_type: Some("felt*") }
mul_mod_ptr => HintReference { offset1: Reference(FP, -3, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: None, cairo_type: Some("starkware.cairo.common.cairo_builtins.ModBuiltin*") }
keccak_ptr => HintReference { offset1: Reference(FP, -7, false, true), offset2: Value(0), inner_dereference: false, outer_dereference: true, ap_tracking_data: None, cairo_type: Some("starkware.cairo.common.cairo_builtins.KeccakBuiltin*") }
--Return--
We can see for my_struct:
my_struct => HintReference { offset1: Value(0), offset2: Value(0), inner_dereference: false, outer_dereference: false, ap_tracking_data: None, cairo_type: Some("__main__.MyStruct") }
Okay, thanks. I don't get what would be the exepected behavior. In the issue you say it should have proper offsets. Why is it that you believe this is an error and not a misuse?
In the Hint References you sent, the offset1 of foo_label is ap - 1, which is that you are trying to cast as MyStructPointer*. Couldn't that be the error?
In the Hint References you sent, the offset1 of foo_label is ap - 1, which is that you are trying to cast as MyStructPointer*. Couldn't that be the error?
I double-checked and can attest that memory[ap-1] is indeed the value returned by foo, in our case it's my_struct as expected. Not foo_label
Thus, I suspect that the offsets returned by the hint reference are not correct (namely - my_struct should be at ap - 1)
Sorry for being insistent, but doesn't this statement return () in foo mean it returns nothing?
no, because my_struct is an implicit arg, it's always returned. It's true that I could've made it explicit, though, it's equivalent. I will edit the program in my previous message
Mmm, in that case, this code should work right? I mean, ignoring the current error:
%builtins output pedersen range_check ecdsa
from starkware.cairo.common.cairo_builtins import (
HashBuiltin,
SignatureBuiltin,
)
from starkware.cairo.common.registers import get_label_location
struct MyStruct {
value: MyStructPointer*,
}
struct MyStructPointer {
a: felt,
b: felt,
}
func foo(my_struct: MyStruct) -> MyStruct {
tempvar my_new_struct = MyStruct(new MyStructPointer(my_struct.value.a+1, my_struct.value.b+1));
return my_new_struct;
}
func main{
output_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
ecdsa_ptr: SignatureBuiltin*,
}() {
let (foo_label) = get_label_location(foo);
call abs foo_label;
tempvar my_struct = MyStruct(new MyStructPointer(1,2));
let my_struct = MyStruct(cast([ap-1], MyStructPointer*));
assert my_struct = MyStruct(new MyStructPointer(1,2));
// %{%} // This could be any hint, what's important for us is to just see what's in the HintReference object
return();
}
I'm running this code with both python vm and rust vm, and both return the same error:
Rust
Couldn't run program: VmException(VmException { pc: Relocatable { segment_index: 0, offset: 44 }, inst_location: Some(Location { end_line: 49, end_col: 59, input_file: InputFile { filename: "custom_hint.cairo" }, parent_location: None, start_line: 49, start_col: 5 }), inner_exc: DiffAssertValues((RelocatableValue(Relocatable { segment_index: 1, offset: 25 }), RelocatableValue(Relocatable { segment_index: 1, offset: 33 }))), error_attr_value: None, traceback: None })
Python
An ASSERT_EQ instruction failed: 1:25 != 1:33.
assert my_struct = MyStruct(new MyStructPointer(1,2));
^****************************************************^
Nevermind, I was mistaken.
Hey @FrancoGiachetta here's an example of a case where this issue lead to a VM execution that did not match the definition of the program - i think it's related given that changing let to local solved the issue in that case
https://github.com/feltroidprime/garaga-zero/pull/14
Hi @enitrat!
I've run the program you'd passed before but with the python vm, something I hadn't done before, but instead of calling breakpoint, calling print(ids.my_struct) in the hint, and got this error:
Error at pc=0:36:
Got an exception while executing a hint.
%{print(ids.my_struct)%} // This could be any hint, what's important for us is to just see what's in the HintReference object
^**********************^
Traceback (most recent call last):
File "examples/program.cairo", line 46, in <module>
%{print(ids.my_struct)%} // This could be any hint, what's important for us is to just see what's in the HintReference object
File "/Users/franco/Documents/Projects/cairo-vm/cairo-vm-env/lib/python3.9/site-packages/starkware/cairo/lang/vm/vm_consts.py", line 61, in __getattr__
return self.get_or_set_value(name, None)
File "/Users/franco/Documents/Projects/cairo-vm/cairo-vm-env/lib/python3.9/site-packages/starkware/cairo/lang/vm/vm_consts.py", line 155, in get_or_set_value
return getattr(self, handler_name)(name, value, scope, set_value)
File "/Users/franco/Documents/Projects/cairo-vm/cairo-vm-env/lib/python3.9/site-packages/starkware/cairo/lang/vm/vm_consts.py", line 216, in handle_ReferenceDefinition
expr, expr_type = simplify_type_system(expr, identifiers=self._context.identifiers)
File "/Users/franco/Documents/Projects/cairo-vm/cairo-vm-env/lib/python3.9/site-packages/starkware/cairo/lang/compiler/type_system_visitor.py", line 412, in simplify_type_system
return TypeSystemVisitor(
File "/Users/franco/Documents/Projects/cairo-vm/cairo-vm-env/lib/python3.9/site-packages/starkware/cairo/lang/compiler/ast/visitor.py", line 42, in visit
return getattr(self, f"visit_{type(obj).__name__}", self._visit_default)(obj)
File "/Users/franco/Documents/Projects/cairo-vm/cairo-vm-env/lib/python3.9/site-packages/starkware/cairo/lang/compiler/type_system_visitor.py", line 348, in visit_ExprCast
raise CairoTypeError(
starkware.cairo.lang.compiler.type_casts.CairoTypeError: :1:1: Cannot cast 'felt' to '__main__.MyStruct'.
cast(([ap + (-1)]), __main__.MyStruct)
^************************************^
Hi @FrancoGiachetta I guess this is because we're doing a cast inside the let my_struct instruction, but because this one is still a reference when you try to print it, it's not yet accessible as a VmConst.
If you run this
let my_struct_ptr = cast([ap-1], MyStructPointer*);
let my_struct = MyStruct(my_struct_ptr);
%{breakpoint()%}
You'll see
(Pdb) ids.my_struct_ptr
<starkware.cairo.lang.vm.vm_consts.VmConstsReference object at 0x1066cb790>
(Pdb) ids.my_struct
*** starkware.cairo.lang.compiler.type_casts.CairoTypeError: :1:1: Cannot cast 'felt' to '__main__.MyStruct'.
cast(([ap + (-1)]), __main__.MyStruct)
ids.my_struct_ptr is accessible