def test_valid_l1_handler(): program = preprocess_str(""" %lang starknet %builtins ecdsa @l1_handler func f(from_address : felt): return () end """) assert isinstance( program.identifiers.get_by_full_name(WRAPPER_SCOPE + 'f'), FunctionDefinition) expected_result = '%builtins ecdsa\n\n' + strip_comments_and_linebreaks( """\ ret [ap] = [fp + (-3)] + 1; ap++ # Compute effective calldata end. [fp + (-4)] = [ap + (-1)] - [fp + (-3)] # Verify calldata size (1). [ap] = [[fp + (-3)]]; ap++ # Pass from_address. call rel -5 # Call f. %{ memory[ap] = segments.add() %} # Allocate memory for return value ap += 1 [ap] = [[fp + (-5)]]; ap++ # Return syscall_ptr [ap] = [[fp + (-5)] + 1]; ap++ # Return storage_ptr. [ap] = [[fp + (-5)] + 2]; ap++ # Return ecdsa. [ap] = 0; ap++ # Return retdata_size=0 [ap] = [ap + (-5)]; ap++ # Return retdata_ptr ret """) assert program.format() == expected_result
def test_wrapper_without_implicit_args(): program = preprocess_str(""" %lang starknet %builtins ecdsa @external func f(): return () end """) assert isinstance( program.identifiers.get_by_full_name(WRAPPER_SCOPE + 'f'), FunctionDefinition) expected_result = '%builtins ecdsa\n\n' + strip_comments_and_linebreaks( """\ ret [fp + (-4)] = [fp + (-3)] - [fp + (-3)] # Verify calldata size (0). call rel -2 # Call f. %{ memory[ap] = segments.add() %} # Allocate memory for return value ap += 1 [ap] = [[fp + (-5)]]; ap++ # Return syscall_ptr [ap] = [[fp + (-5)] + 1]; ap++ # Return storage_ptr. [ap] = [[fp + (-5)] + 2]; ap++ # Return ecdsa. [ap] = 0; ap++ # Return retdata_size=0 [ap] = [ap + (-5)]; ap++ # Return retdata_ptr ret """) assert program.format() == expected_result
def test_wrapper_with_return_args(): program = preprocess_str(""" %lang starknet %builtins pedersen range_check ecdsa struct HashBuiltin: end @external func f{ecdsa_ptr}(a : felt, b : felt) -> (c : felt, d : felt): return (c=1, d=2) end """) assert isinstance( program.identifiers.get_by_full_name(WRAPPER_SCOPE + 'f'), FunctionDefinition) expected_result = '%builtins pedersen range_check ecdsa\n' + strip_comments_and_linebreaks( """\ # Implementation of f [ap] = [fp + (-5)]; ap++ # Return ecdsa_ptr. [ap] = 1; ap++ # Return c=1 [ap] = 2; ap++ # Return d=2 ret # Implementation of __wrappers__.f [ap] = [fp + (-3)] + 2; ap++ # Compute effective calldata end. [fp + (-4)] = [ap + (-1)] - [fp + (-3)] # Verify calldata size (2). [ap] = [[fp + (-5)] + 4]; ap++ # Pass ecdsa_ptr. [ap] = [[fp + (-3)]]; ap++ # Pass a. [ap] = [[fp + (-3)] + 1]; ap++ # Pass b. call rel -12 # Call f. %{ memory[ap] = segments.add() %} # Allocate memory for return value ap += 1 [[ap + (-1)]] = [ap + (-3)] # [retdata_ptr] = c [[ap + (-1)] + 1] = [ap + (-2)] # [retdata_ptr + 1] = d [ap] = [[fp + (-5)]]; ap++ # Return syscall_ptr [ap] = [[fp + (-5)] + 1]; ap++ # Return storage_ptr [ap] = [[fp + (-5)] + 2]; ap++ # Return pedersen_ptr. [ap] = [[fp + (-5)] + 3]; ap++ # Return range_check. [ap] = [ap + (-8)]; ap++ # Return ecdsa. [ap] = 2; ap++ # Return retdata_size=2 [ap] = [ap + (-7)]; ap++ # Return retdata_ptr ret """) assert program.format() == expected_result
def test_check_felts_only_type(): program = preprocess_str(""" struct A: member x : felt end struct B: end struct C: member x : felt member y : (felt, A, B) member z : A end struct D: member x : felt* end struct E: member x : D end """) for (typ, expected_res) in [ # Positive cases. ('test_scope.A', True), ('test_scope.B', True), ('test_scope.C', True), ('(felt, felt)', True), ('(felt, (felt, test_scope.C))', True), # Negative cases. ('test_scope.D', False), ('test_scope.E', False), ('(felt, test_scope.D)', False), ]: assert check_felts_only_type( cairo_type=mark_type_resolved(parse_type(typ)), identifier_manager=program.identifiers) == expected_res
def test_abi(): program = preprocess_str(""" %lang starknet %builtins range_check @external func f(a : felt, arr_len : felt, arr : felt*) -> (b : felt, c : felt): return (0, 1) end @view func g() -> (a: felt): return (0) end @l1_handler func handler(from_address): return () end """) assert program.abi == [ { 'inputs': [ { 'name': 'a', 'type': 'felt' }, { 'name': 'arr_len', 'type': 'felt' }, { 'name': 'arr', 'type': 'felt*' }, ], 'name': 'f', 'outputs': [ { 'name': 'b', 'type': 'felt' }, { 'name': 'c', 'type': 'felt' }, ], 'type': 'function', }, { 'inputs': [], 'name': 'g', 'outputs': [ { 'name': 'a', 'type': 'felt' }, ], 'type': 'function', 'stateMutability': 'view', }, { 'inputs': [{ 'name': 'from_address', 'type': 'felt' }], 'name': 'handler', 'outputs': [], 'type': 'l1_handler', }, ]
def test_storage_var_success(): program = preprocess_str(""" %lang starknet from starkware.starknet.common.storage import Storage from starkware.cairo.common.cairo_builtins import HashBuiltin struct A: member x : felt end struct B: member a : A member y : felt end func g{storage_ptr : Storage*, range_check_ptr, pedersen_ptr : HashBuiltin*}(): alloc_locals let (x) = my_var.read() my_var.write(value=x + 1) local storage_ptr : Storage* = storage_ptr let (my_var2_addr) = my_var2.addr(1, 2) my_var2.write(1, 2, value=B(A(3), 4)) let a = my_var2.read(1, 2) return () end @storage_var func my_var() -> (res : felt): # Comment. end @storage_var func my_var2(x, y) -> (res : B): end """) addr = starknet_keccak(b'my_var') addr2 = starknet_keccak(b'my_var2') expected_result = f"""\ # Code for the dummy modules. ret ret ret ret # Implementation of g. ap += 1 [ap] = [fp + (-5)]; ap++ # Push storage_ptr. [ap] = [fp + (-4)]; ap++ # Push range_check_ptr. [ap] = [fp + (-3)]; ap++ # Push pedersen_ptr. call rel ??? # Call my_var.read. [ap] = [ap + (-4)]; ap++ # Push (updated) storage_ptr. [ap] = [ap + (-4)]; ap++ # Push (updated) range_check_ptr. [ap] = [ap + (-4)]; ap++ # Push (updated) pedersen_ptr. [ap] = [ap + (-4)] + 1; ap++ # Push value. call rel ??? # Call my_var.write. [fp] = [ap + (-3)] # Copy storage_ptr to a local variable. [ap] = 1; ap++ # Push 1. [ap] = 2; ap++ # Push 2. call rel ??? # Call my_var2.addr. [ap] = [fp]; ap++ # Push storage_ptr. [ap] = [ap + (-4)]; ap++ # Push range_check_ptr. [ap] = [ap + (-4)]; ap++ # Push pedersen_ptr. [ap] = 1; ap++ # Push 1. [ap] = 2; ap++ # Push 2. [ap] = 3; ap++ # Push 3. [ap] = 4; ap++ # Push 4. call rel ??? # Call my_var2.write. [ap] = 1; ap++ # Push 1. [ap] = 2; ap++ # Push 2. call rel ??? # Call my_var2.read. [ap] = [ap + (-5)]; ap++ # Return (updated) storage_ptr. [ap] = [ap + (-5)]; ap++ # Return (updated) range_check_ptr. [ap] = [ap + (-5)]; ap++ # Return (updated) pedersen_ptr. ret # Implementation of my_var.addr. [ap] = [fp + (-4)]; ap++ # Return range_check_ptr. [ap] = [fp + (-3)]; ap++ # Return pedersen_ptr. [ap] = {addr}; ap++ # Return address. ret # Implementation of my_var.read. [ap] = [fp + (-4)]; ap++ # Push range_check_ptr. [ap] = [fp + (-3)]; ap++ # Push pedersen_ptr. call rel ??? # Call my_var.addr(). [ap] = [fp + (-5)]; ap++ # Push storage_ptr. [ap] = [ap + (-2)]; ap++ # Push address. call rel ??? # Call storage_read(). [ap] = [ap + (-2)]; ap++ # Return storage_ptr. [ap] = [ap + (-8)]; ap++ # Return (updated) range_check_ptr. [ap] = [ap + (-8)]; ap++ # Return (updated) pedersen_ptr. [ap] = [ap + (-4)]; ap++ # Return value. ret # Implementation of my_var.write. [ap] = [fp + (-5)]; ap++ # Push range_check_ptr. [ap] = [fp + (-4)]; ap++ # Push pedersen_ptr. call rel ??? # Call my_var.addr(). [ap] = [fp + (-6)]; ap++ # Push storage_ptr. [ap] = [ap + (-2)]; ap++ # Push address. [ap] = [fp + (-3)]; ap++ # Push value. call rel ??? # Call storage_write(). [ap] = [ap + (-8)]; ap++ # Return (updated) range_check_ptr. [ap] = [ap + (-8)]; ap++ # Return (updated) pedersen_ptr. ret # Implementation of my_var2.addr. [ap] = [fp + (-5)]; ap++ # Push pedersen_ptr. [ap] = {addr2}; ap++ # Push address. [ap] = [fp + (-4)]; ap++ # Push x. call rel ??? # Call hash2(res, x). [ap] = [fp + (-3)]; ap++ # Push y. call rel ??? # Call hash2(res, y). [ap] = [fp + (-6)]; ap++ # Push range_check_ptr. [ap] = [ap + (-2)]; ap++ # Push res. call rel ??? # Call normalize_address(res). [ap] = [ap + (-2)]; ap++ # Return (updated) range_check_ptr. [ap] = [ap + (-7)]; ap++ # Return (updated) pedersen_ptr. [ap] = [ap + (-3)]; ap++ # Return res. ret # Implementation of my_var2.read. [ap] = [fp + (-6)]; ap++ # Push range_check_ptr. [ap] = [fp + (-5)]; ap++ # Push pedersen_ptr. [ap] = [fp + (-4)]; ap++ # Push x. [ap] = [fp + (-3)]; ap++ # Push y. call rel ??? # Call my_var.addr(). [ap] = [fp + (-7)]; ap++ # Push storage_ptr. [ap] = [ap + (-2)]; ap++ # Push address. call rel ??? # Call storage_read(). [ap] = [ap + (-2)]; ap++ # Push (updated) storage_ptr. [ap] = [ap + (-6)] + 1; ap++ # Push address + 1. call rel ??? # Call storage_read(). [ap] = [ap + (-2)]; ap++ # Return storage_ptr. [ap] = [ap + (-12)]; ap++ # Return (updated) range_check_ptr. [ap] = [ap + (-12)]; ap++ # Return (updated) pedersen_ptr. [ap] = [ap + (-8)]; ap++ # Return x. [ap] = [ap + (-5)]; ap++ # Return y. ret # Implementation of my_var2.write. [ap] = [fp + (-8)]; ap++ # Push range_check_ptr. [ap] = [fp + (-7)]; ap++ # Push pedersen_ptr. [ap] = [fp + (-6)]; ap++ # Push x. [ap] = [fp + (-5)]; ap++ # Push y. call rel ??? # Call my_var.addr(). [ap] = [fp + (-9)]; ap++ # Push storage_ptr. [ap] = [ap + (-2)]; ap++ # Push address. [ap] = [fp + (-4)]; ap++ # Push value. call rel ??? # Call storage_write(). [ap] = [ap + (-6)] + 1; ap++ # Push address. [ap] = [fp + (-3)]; ap++ # Push value. call rel ??? # Call storage_write(). [ap] = [ap + (-12)]; ap++ # Return (updated) range_check_ptr. [ap] = [ap + (-12)]; ap++ # Return (updated) pedersen_ptr. ret """ assert re.sub('call rel -?[0-9]+', 'call rel ???', program.format()) == \ strip_comments_and_linebreaks(expected_result).lstrip()